Self adjusting random list - javascript

I have a grid of 9 columns by 3 rows (so each column has 3 slots). A minimum of one slot in every column must be marked and no more than 3 can be marked. A mark is represented by a 1,2 or 3 digit.
There must always be 15 marked slots in total. To achieve this I tried the following:
var valueLeft = 15;
while (valueLeft > 0)
{
var ranValue = utils.getRandomInt(1,3);
console.log('slots remaining: ' + (valueLeft - ranValue));
if (ranValue >= valueLeft)
{
ranValue = valueLeft;
}
valueList.push(ranValue);
valueLeft -= ranValue;
}
console.log(valueList);
But this often gives me an array of numbers with less than 9 elements inside. I can see that my logic is flawed but I am pulling my hair out trying to figure out how I can get it to always give a set of 9 elements which all add up to 15.
For example what I might end up with is:
[2, 1, 1, 1, 1, 2, 3, 1, 2, 1]
When what I need for example is:
[2, 2, 1, 1, 1, 1, 3, 2, 2]
or
[2, 2, 1, 2, 1, 1, 3, 2, 1]
and so on.
Any advice appreciated. Feel free to flame me for my poor sense of logic :)

This answer shows a similar approach to many of those already posted, but I feel as though they're making it too complicated. It can be very straightforward:
function pad(list, size) {
var total = list.length;
while (total != size) {
var i = utils.getRandomInt(0, 8);
if (list[i] < 3) {
list[i]++;
total++;
}
}
return list;
}
var valueList = pad(new Array(1,1,1,1,1,1,1,1,1), 15);
You don't need a lot of cases. Just -- as many others have already said -- init the array with 1's. Then, simply add one to random elements (whose value isn't already 3) until the total is 15.

why don't you do this:
start off with an array that looks like this: 1,1,1,1,1,1,1,1,1
then make a function that picks a random number between 0 and 8 6 times.
if the same number has been picked more than twice, skip it and pick a new one
then correlate those 6 numbers to the index of the array and add 1 for each time it picks that number.
var i; var valueList = new Array(1,1,1,1,1,1,1,1,1);
for(i=0;i<6;i++)
{
var ranNum = utils.getRandomInt(0,8);
if(valueList[ranNum]<3) valueList[ranNum]+=1;
else i--;
}
just tested it, changed <=6 to <6 and it's working for me. Good luck!

Following logic should work. You should select a random value (within 1-3) such that choosing that would not lead us to not able to select a random value for further slots.
var gridLeft = 9
var valueLeft = 15
while(gridLeft>0) {
var ranValue
while(true) {
ranValue = utils.getRandomInt(1,3);
if (valueLeft-ranValue > 3*(gridLeft-1))
continue;
else if (valueLeft-ranValue < 1*(gridLeft-1))
continue;
else
break;
}
valueList.push(ranValue);
valueLeft -= ranValue;
gridLeft -= 1
}

Related

How to return all the divisors from a big integer?

I understand the concept of how to return all the divisors from an given integer. However, when it gets to the big integers, nothing gets return:
function divisors(n,res=[]) {
for (let i = 1; i <= n; i++) !(n%i) && res.push(i);
return res;
}
console.log(divisors(4)); // [ 1, 2, 4 ]
console.log(divisors(9)); // [ 1, 3, 9 ]
console.log(divisors(12)); // [ 1, 2, 3, 4, 6, 12 ]
console.log(divisors(975179493674)); // ?????
console.log(divisors(27550356289)); // ?????
The next logical step is to minimize the iteration amount by taking the square root of the given integer n in the for loop. This works and partially return some divisors but it didn't return all the divisors from each integers.
function divisors(n,res=[]) {
for (let i = 1; i <= Math.floor(Math.sqrt(n)); i++) {
!(n%i) && res.push(i)
}
return res
}
console.log(divisors(4)); // [ 1, 2 ]
console.log(divisors(9)); // [ 1, 3 ]
console.log(divisors(12)); // [ 1, 2, 3 ]
console.log(divisors(975179493674)); // [ 1, 2, 97, 194 ]
console.log(divisors(27550356289)); // [ 1, 165983 ]
I just can't quite wrap my head around it. Any help or pointers will be greatly appreciated.
UPDATE:
The solution is still possible with only 1 loop. It was missing a few lines of control flow as follow:
function divisors(n,res=[]) {
for (let i = 1; i <= Math.sqrt(n); i++) {
if (!(n%i)) {
i*i < n && res.push(i);
res.push(n/i);
}
}
return res;
}
console.log(divisors(4)); // [ 1, 2 ]
console.log(divisors(9)); // [ 1, 3 ]
console.log(divisors(12)); // [ 1, 2, 3 ]
console.log(divisors(975179493674)); // [ 1, 2, 97, 194, 5026698421, 10053396842, 487589746837, 975179493674 ]
console.log(divisors(27550356289)); // [ 1, 165983, 27550356289 ]
Having found all the divisors less than or equal to the square root of the input, you can then divide the input by those numbers to get the rest of the divisors:
function divisors(n,res=[]) {
for (let i = 1; i <= Math.floor(Math.sqrt(n)); i++) {
if (n%i == 0) { res.push(i) }
}
let len = res.length;
// if n is a square, don't include the square root twice
if (res[len-1] * res[len-1] == n) len--;
for (i = len - 1; i >= 0; i--) { res.push(n / res[i]) }
return res
}
console.log(divisors(4)); // [ 1, 2, 4 ]
console.log(divisors(9)); // [ 1, 3, 9 ]
console.log(divisors(12)); // [ 1, 2, 3, 4, 6, 12 ]
console.log(divisors(975179493674)); // [ 1, 2, 97, 194, 5026698421, 10053396842, 487589746837, 975179493674 ]
console.log(divisors(27550356289)); // [ 1, 165983, 27550356289 ]
It makes sense to distinguish several similar but different problems here:
(1) To check whether a number N is a prime number or not, you can stop searching for possible divisors when you've reached its square root. That's because if N == x * y, and x > sqrt(N), then y < sqrt(N), so you would have found y before finding x.
As an example with concrete numbers: to check whether 11 is prime, you can stop searching after checking that 11 % 2 != 0 and 11 % 3 != 0 (because sqrt(11) < 4). If any of 4, 5, 6, ... were divisors of 11, then there'd be a corresponding divisor 11/4 or 11/5 or 11/6 etc, all of which are smaller than sqrt(11), so you would have found them before.
(2) To find all prime factors of a number N, you can't simply stop searching at sqrt(N). In contrast with case (1): if you only want to test whether 10 is prime, you can stop searching for divisors after checking 3 == floor(sqrt(10)) (and you would have found 2 at that point, proving that 10 is not prime), whereas if your task is to find all prime factors, you need to somehow find 5 as well, and 5 > sqrt(10).
One way to accomplish that is to keep dividing N by each factor that you find, so you'd have something like:
function primeFactors(n,res=[]) {
for (let i = 2; i <= Math.floor(Math.sqrt(n)); ) {
let candidate = Math.floor(n / i);
if (candidate * i === n) {
res.push(i);
n = candidate;
} else {
i++;
}
}
res.push(n);
return res;
}
Note that this uses candidate * i === n instead of n % i === 0 because multiplications are much faster than divisions. Since we already have the n / i division (and can't avoid that in this approach), we can at least replace the second n % i division with that multiplication.
Similarly, you could improve performance further if you replaced the loop's condition i <= Math.floor(Math.sqrt(n)) with i*i <= n. Or even better, reusing the work we've already done: if (candidate < i) break;.
(3) To find all divisors (both prime factors and composite divisors), you can approach the problem from several directions:
The simplest is probably to do what #Nick's answer suggests: try all candidates i from 1 to sqrt(N), and whenever you find one, add both i and n / i to the list.
As a minor improvement to that, you could start at i = 2, and always add 1 and n to the list without checking (because every integer is divisible by 1 and by itself).
An alternative that's probably faster, but also more complicated to implement, is to find the prime factors first (see (2)), and then build the set of all divisors as the powerset of the prime factors. For example, if you find that the prime factors are [2, 3, 5], then the set of divisors is [1, 2, 3, 5, 2*3, 2*5, 3*5, 2*3*5]. (Note that this will need some deduplication when some prime factors occur more than once.)
If performance is really important, there's more you could do. For example, you could cache prime numbers you've found, and on subsequent invocations only check those as possible divisors.
A very simple step in this direction would be to special-case i=2, and then check only odd candidates (3, 5, 7, ...) afterwards. That simple trick would save about half the work!
One can even go as far as getting rid of expensive divisions entirely at the cost of spending some more memory to keep track of the next multiple of each prime that needs to be checked... but that's getting a bit far from your original question! Before getting too carried away with optimizations, I'd like to point out that for a single invocation, even for an input like 975179493674, any such tuning isn't worth the effort: you'd save a couple of milliseconds of execution time, but it would cost at least several minutes to implement. However, if this happens to be a performance-critical core part of an application, then it provides quite some room for investing implementation effort in order to save execution time.

Returning Null - why is this going wrong?

I am returning null with this code, however I cannot see why/where this is going wrong. (It may be due to the sort function since I got this from a well upvoted snippet on how to sort an array). I care more about the understanding than the correct answer.
Task I am trying to achieve :
Ratiorg got statues of different sizes as a present from CodeMaster for his birthday, each statue having an non-negative integer size. Since he likes to make things perfect, he wants to arrange them from smallest to largest so that each statue will be bigger than the previous one exactly by 1. He may need some additional statues to be able to accomplish that. Help him figure out the minimum number of additional statues needed.
Example
For statues = [6, 2, 3, 8], the output should be
solution(statues) = 3.
Ratiorg needs statues of sizes 4, 5 and 7.
My code & thinking:
function solution(statues) {
let total = 0;
statues.sort(function(a, b) { //From what I understand this should sort the array numerically
return a - b;
});
for (let i = 1; i < statues.length; i++) { //iterate through the array comparing the index to the one before it
if (statues[i + 1] != (statues[i] + 1)) { //if there is a diff between index of more than 1 it will add the diff
total += statues[i + 1] - statues[i]; //to the total variable
}
}
return total;
}
const result = solution([6, 2, 3, 8]);
console.log(result);
Thanks to people who commented who helped me see that there were some errors in my logic - I have now changed the if statement to compare an index starting at 1 to the behind it i.e index 1 compared to index 0. On top of that, there was an issue with the following line total += statues[i] - statues[i-1];
I replaced that with a for loop so that it counts up to the number rather than a simple subtraction of it.
function solution(statues) {
//[6, 2, 3, 8] --- 2,3,6,8 --- 3,6 7-2,
let total = 0;
statues.sort(function(a, b) {
return a - b;
});
for(let i =1; i<statues.length; i++){
if(statues[i] != (statues[i-1]+1) ){
//total += statues[i] - statues[i-1];
for(let j = statues[i-1]; j<statues[i]-1; j++){
total += 1;
}
}
}
return total;
}

LeetCode 120: Triangle - Minimum path sum

I'm doing this problem on leetcode:
Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.
My logic is to find the minimum number in each array and add that to the sum.
This is my code in javascript:
var minimumTotal = function(triangle) {
let sum = 0;
for (let i = 0; i < triangle.length; i++) {
sum += Math.min.apply(null, triangle[i])
}
return sum;
};
But it doesn't work for this test case: [[-1],[2,3],[1,-1,-3]].
The expected output is -1. I'm confused how it should equal -1, because -1 + 2 = 1 and none of the numbers in third array equal -1 when summed with 1.
I looked at the discussion answers and they all used some sort of dynamic programming solution.
What am I doing wrong?
There is a path where the output should be -1.
[
[ -1 ],
[ 2, 3 ],
[ 1, -1, -3 ],
]
-1 + 3 - 3 = -1
The problem is that you only have 2 possible branches at each fork, whereas it appears you're taking the lowest number from the entire row.
Under the rules of the challenge, you shouldn't be able to go from 2 in the second row to -3 in the third row, which would be the most efficient path under your approach.
What you are doing does not seem to follow the desired data structure of the problem. You are generating an int, while the desired output should be an array.
The correct answers are already posted in the discussion board:
This solution is an accepted one (just tested it):
JavaScript
var minimumTotal = function(triangle) {
for (let row = triangle.length - 2; row > -1; row--)
for (let col = 0; col < triangle[row].length; col++)
triangle[row][col] += Math.min(triangle[-~row][col], triangle[-~row][-~col])
return triangle[0][0]
}
-~row is the same as row + 1 (bitwise version).
Reference
Explains it here
If you might be interested in Python and Java, these are "accepted" solutions:
Python
class Solution:
def minimumTotal(self, triangle):
if not triangle:
return
dp = triangle[-1]
for row in range(len(triangle) - 2, -1, -1):
for col in range(len(triangle[row])):
dp[col] = min(dp[col], dp[-~col]) + triangle[row][col]
return dp[0]
Java
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int[] dp = new int[-~triangle.size()];
for (int row = triangle.size() - 1; row > -1; row--)
for (int col = 0; col < triangle.get(row).size(); col++)
dp[col] = Math.min(dp[col], dp[-~col]) + triangle.get(row).get(col);
return dp[0];
}
}
For each step, you may move to an adjacent number of the row below. More formally, if you are on index i on the current row, you may move to either index i or index i + 1 on the next row.
The above statement is part of the question and it helps to create a graph like this.
Dynamic programming is used where we have problems, which can be divided into similar sub-problems, so that their results can be re-used. We start from the bottom and determine which minimum value we take and then we are going to be using that minimum value above. That is why we use dynamic programming here. Now each row gets 1 size bigger, so you can imagine under the last row, we have 4 0's.
that is why in dynamic programming we always create an array whose size is always 1 greater than the original array. We fill the array with default values. I will be explaining in python but later on I will challenge myself to write in javascript. first, initialize the dp array
dp=[0]*(len(triangle)+1) #[[0],[0],[0],[0]]
Now, we are starting from the level=[1,-1,3]. For this level, since the bottom is full of 0's, our dp array will be
dp=[1,-1,-3,0]
now we are moving above level, level=[2,3], but we are using the data from the bottom. (That is why we are using dynamic programming). From 2, its index is 0, so I ask myself what is the minimum between 0'th and 1'st value of the dp array. Whichever is minimum we add it to 2? Obviously, -1 is minimum, 2+(-1)=1 and dp gets updated.
dp=[1, -1, -3, 0]
We do the same for 3. its index is 1, and we ask what is the min(-1,3), because 3 is pointing to -1 and 3 and then we add -1 to 3 which is 2. new dp
dp=[1,0,-3,0]
Now we are at the root level. -1 and its index is 0. We ask what is min value of index 0'th and index 1'st of the dp array. min(1,0)=0 and we add it to -1. dp gets updated
dp=[-1,0,3,0]
and finally, we return dp[0]=0
Here is the code in python:
from typing import List
class Solution:
def min_total(self,triangle:List[List[int]])->int:
# dp[] is the bottom row
dp=[0]*(len(triangle)+1)
// triangle[::-1] says start from the last element of triangle
for row in triangle[::-1]:
for i,n in enumerate(row):
dp[i]=n+min(dp[i],dp[i+1])
return dp[0]
Here is javascript code:
function minPath(triangle) {
let dp = new Array(triangle.length + 1).fill(0);
for (let row = triangle.length - 1; row >= 0; row--) {
for (let i = 0; i <= triangle[row].length - 1; i++) {
dp[i] = triangle[row][i] + Math.min(dp[i], dp[i + 1]);
}
}
console.log(dp);
return dp[0];
}
const triangle = [[-1], [2, 3], [1, -1, -3]];
console.log(minPath(triangle));
As this was brought back up, it's worth pointing out that the dynamic programming technique discussed in answers and comments can be done very simply with a reduceRight:
const minSum = (triangle) =>
triangle .reduceRight ((ms, ns) => ns .map (
(n, i) => n + (i > ms.length ? ms[i] : Math .min (ms [i], ms [i + 1]))
)) [0]
console .log (minSum ([[-1], [2, 3], [1, -1, -3]])) //=> -1
console .log (minSum ([[2], [3, 4], [6, 5, 7], [4, 1, 8, 3]])) //=> 11
console .log (minSum ([[-10]])) //=> -10
At each step we calculate the minimum paths through all the elements in a row. ms is the minimum paths through the row below (and on the initial pass will just be the bottom row) and for each n in our row ns, if we're at the rightmost element, we just copy the value from the corresponding row below, otherwise we take the minimum of the element right below and the one to its right.
Since this is called a triangle, I think we can assume that the first row has only one element. But if that's not the case, we could simply take the minimum of the results rather than taking the first element in the final value. That is, we could replace triangle .reduceRight ( ... ) [0] with Math .min (... triangle .reduceRight ( ... )).
/*
[120] Triangle
https://leetcode.com/problems/triangle/description/
*/
import java.util.List;
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
if (triangle.size() == 0)
return 0;
int rows = triangle.size();
int cols = triangle.get(rows - 1).size();
int[] tmp = new int[cols];
int index = 0;
for (int var : triangle.get(rows - 1)) {
tmp[index++] = var;
}
for (int i = rows - 2; i >= 0; i--) {
for (int j = 0; j <= triangle.get(i).size() - 1; j++) {
tmp[j] = triangle.get(i).get(j) + Math.min(tmp[j], tmp[j + 1]);
}
}
return tmp[0];
}
}

Javascript: Check array of numbers for number of missing numbers needed to make the array consecutive

Working on some Javascript challenges on Code Signal and I'm having an issue solving this:
Ratiorg got statues of different sizes as a present from CodeMaster for his birthday, each statue having an non-negative integer size. Since he likes to make things perfect, he wants to arrange them from smallest to largest so that each statue will be bigger than the previous one exactly by 1. He may need some additional statues to be able to accomplish that. Help him figure out the minimum number of additional statues needed.
Example
For statues = [6, 2, 3, 8], the output should be
makeArrayConsecutive2(statues) = 3.
Ratiorg needs statues of sizes 4, 5 and 7.
My approach:
Sort the array smallest to largest
Create counter variable to store number of missing numbers
Iterate through array
Subtract [i + 1] element from [i] element
If it equals 1, numbers are consecutive, if not the numbers are not consecutive (increment counter variable)
Return counter variable
Here is my code:
function makeArrayConsecutive2(statues) {
// Sorts array numerically smallest to largest
statues.sort((a, b) => a - b);
let counter = 0;
// If array only contains one number return 0
if(statues.length === 1) {
return 0;
}
/* Iterate through array, subtract the current element from the next element, if it
equals 1 the numbers are consecutive, if it doesn't equal one increment the counter
variable */
for(let i = 0; i <= statues.length -1; i++) {
if(statues[i] !== statues.length -1 && statues[i + 1] - statues[i] != 1) {
counter++;
}
console.log(statues[i]);
console.log('counter : ' + counter);
}
return counter;
}
When statues contains [5, 4, 6] the output is this:
4
counter : 0
5
counter : 0
6
counter : 1
I think the problem is when array is on the last element, in this case 6, it's attempting to look at statues[i + 1] when that element doesn't exist. I added statues[i] !== statues.length -1 to my if statement to address that but it doesn't appear to be working. What's wrong with my code and why is the final element incrementing the counter variable?
I'd approach it by building the target array which goes from the min+1 to the max-1 of the input by ones, excluding members of the input.....
function missingConseq(input) {
let min = Math.min.apply(null, input)
let max = Math.max.apply(null, input)
let result = []
for (i = min+1; i < max; i++) {
if (!input.includes(i)) result.push(i)
}
return result
}
let array = [6, 2, 3, 8]
console.log(missingConseq(array))

Selecting from an array based on size

I'm currently working on a small game and got stuck on something I can't figure out.
I have an array with 5 items in, these items represent different positions, like this:
[1, 2, 3, 4, 5]
These are basically different lines that are used to place objects as the players goes further into the game.
Every 5 second new objects should appear, these come from another array, that looks something like this:
[1, 2]
// 1 = single item
// 2 = double item
1 and 2 are different types of objects, both require a different amount of lines.
The problem is that these items sometimes overlap and I can't figure out how to stop this.
You can see the problem from the output:
Items: [1, 2]
[Item of type 1] line: 3
[available lines] [1, 2, 3, 4, 5]
[Item of type 2] line: 2
[available lines] [1, 2, 4, 5]
[1, 5]
So item 1 (1 line) is placed on line 3, but for item 2 (2 lines), line 2 is select, because it's 2 lines wide, this will overlap with my first item.
So basically for item 2 only line 1 and 4 could be selected, but I can't seem to find any logic that would only select these.
It's probably going to be expanded into something around 20 lines with more objects, so I would need to find a way to select a line where the next one is available too.
Any ideas on how I can get started on this?
What I currently use is this:
var random = Math.floor(Math.random() * (start_lines.length - 1));
var line = start_lines[random];
// If it's a barrier, delete 2 rows instead (35)
if(type == 2) {
if(line == 5) {
xPos = this._lines[random - 1] - 35;
start_lines.splice(random - 1, 2);
} else {
xPos = this._lines[random] - 35;
start_lines.splice(random, 2);
}
} else {
start_lines.splice(random, 1);
}
What I did for now was first loop trough the array with lines and check if the next line is available, I then push those 2 lines into another array which I can select from.
if(type == 2) {
var options = [];
for(var i = 0 ; i < start_lines.length; i++) {
var f = start_lines[i];
var n = start_lines[i + 1];
if((f + 1) == n) {
options.push([f, n]);
}
}
var random = Math.floor(Math.random() * (options.length - 1));
var option = options[random];
var f = option[0];
var n = option[1];
xPos = this._lines[f] - 30;
start_lines.splice(f - 1, 2);
start_lines.splice(n - 1, 2);
} else {
var random = Math.floor(Math.random() * (start_lines.length - 1));
var line = start_lines[random];
start_lines.splice(random, 1);
}
I don't know whether this approach fits for your requirement, but it would be better if you can set the lines initially and randomly pick one when needed. This avoids a lot of confusion.
function getLines(){
var start_lines = [1, 2, 3, 4, 5], lines = [];
while(start_lines.length){
var type = Math.ceil(Math.random() * 2);
lines.push(start_lines.splice(0, type));
}
return lines;
}
var lines = getLines();
var random = Math.floor(Math.random() * lines.length);
console.log(lines.splice(random, 1));
Here I am selecting type randomly - either 1 or 2. You will have to make some changes in this.
jsbin : http://jsbin.com/upabom/3/edit

Categories

Resources