I am doing this problem
https://leetcode.com/problems/merge-sorted-array/description/
and this is:
You are given two integer arrays nums1 and nums2, sorted in
non-decreasing order, and two integers m and n, representing the
number of elements in nums1 and nums2 respectively.
Merge nums1 and nums2 into a single array sorted in non-decreasing
order.
The final sorted array should not be returned by the function, but
instead be stored inside the array nums1. To accommodate this, nums1
has a length of m + n, where the first m elements denote the elements
that should be merged, and the last n elements are set to 0 and should
be ignored. nums2 has a length of n.
Input: nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3 Output:
[1,2,2,3,5,6] Explanation: The arrays we are merging are [1,2,3] and
[2,5,6]. The result of the merge is [1,2,2,3,5,6] with the underlined
elements coming from nums1.
For input of
nums1 =[0]
m=0
nums2 = 1
n = 1
i don't know why it is returning [0]
when i am doing nums2 = [...nums1]
can you please help me
/**
* #param {number[]} nums1
* #param {number} m
* #param {number[]} nums2
* #param {number} n
* #return {void} Do not return anything, modify nums1 in-place instead.
*/
var merge = function(nums1, m, nums2, n) {
if(m==0){
nums1 = [...nums2]
return;
}
let placement = nums1.length-1
let compare1 = m-1
let compare2 = n-1
while(compare1>0 && compare2>0){
if(nums1[compare1]<nums2[compare2]){
nums1[placement] = nums2[compare2]
placement -=1
compare2 -= 1
}
if(nums1[compare1]>nums2[compare2]){
nums1[placement] = nums1[compare1]
placement -=1
compare1 -= 1
}
if(nums1[compare1] == nums2[compare2]){
nums1[placement] = nums1[compare1]
placement -=1
nums1[placement] = nums2[compare2]
placement -=1
compare1 -=1
compare2 -=1
}
}
return nums1
};
The code challenge requires you to mutate the given array nums1, but your code assigns to nums1 (instead of mutating the array it referenced), so now you have lost the possibility to still access and mutate the original array. Although you have a return nums1, the caller does not look at the return value, but will use the reference it has to the original array and see that nothing has changed inside of it. Note the following phrase in the code challenge (I highlight):
The final sorted array should not be returned by the function, but instead be stored inside the array nums1.
Your code has some other issues as well:
When the while condition becomes false, it might be that compare2 == 0, which means the value nums2[compare2] has not been consulted yet. So that >0 should really be >=0.
When the while condition becomes false, it might be that compare1 < 0, but compare2 is still some positive number, meaning that some values in nums2 have not been moved to nums1. As you want to move all values from nums2 to nums1, the while condition should be compare2 >= 0 only. Then the body of the while loop should check if compare1 >= 0, but this should not be a reason to quit the loop.
When you have fixed this, there is also no more need to have the special case at the start of the function, and you can remove that if block.
The different if blocks should better be mutually exclusive, as otherwise you risk that compare2 becomes negative in the first if block, and although it would work out fine, it is better to just avoid making comparisons with undefined.
The last block that checks for equality is overkill. If you make the second block an else to the first block, then there is no more need to check for equality: it would be dealt with in the else block, and the next iterations will take care of the rest.
Once you have the if..else, then note that placement-- is always executed exactly once in each iteration of the loop, so it can be moved out of the if..else blocks.
Please take the habit to terminate statements with semicolon. Although there is the automatic semicolon insertion procedure, you don't want to make your code's interpretation dependent on the quite complex rules it follows.
Here is your code corrected with the points mentioned above:
var merge = function(nums1, m, nums2, n) {
let placement = nums1.length - 1;
let compare1 = m - 1;
let compare2 = n - 1;
while (compare2 >= 0) { // Make sure all of nums2 is moved!
// If nothing more in nums1, then also copy from nums2
if (compare1 < 0 || nums1[compare1] < nums2[compare2]) {
nums1[placement] = nums2[compare2];
compare2 -= 1;
} else { // Use else, and no specific case for equality
nums1[placement] = nums1[compare1];
compare1 -= 1;
}
placement -= 1; // This is common to all cases
}
};
Related
UPDATE AT THE BOTTOM OF THE POST!
This is the first part of a program that will eventually make SVG star polygons.
Only star polygons that can be made in one go, I.e. like a Pentagram, NOT like a Hexagram that can only be made with at least 2 shapes I.e. 2 inverted and overlapping triangles.
I'm almost finished with this. Everything seems to be working well and I'm getting the out put I want except there's an empty array item in every other array produced for some reason.
In this part
I'm printing to the console (for testing) an object with items named with numbers that represent the number of points / sides of a regular polygon. Within each item is an array with the lower half of all the non factoring numbers of that item (number) I.e. an array of numbers that when the number (item name) is divided by them, it will return a fraction.
E.g. Object
starPolygons{'5': 2, '7': 3, 2, '8': 3, '9': 4, 2, …}
(Representation of: Pentagon: Heptagon: Octagon: Nonagon: …)
What "qty_test" functions does
The points variable (= 8 for example) is sent to a function (qty_test) which is used to find the number of divisors I need to test and inside it is divided by 2. If the result is a fraction, it will return the result rounded back, and if its even, it will return the result - 1.
//8 has more divisors to cycle through -so its a better example!
//In the real program, it will be 5.
let points = 8;
let starPolygons = {};
E.g. qty_test
point (=8) ()=> n /= 2 (=4)
if n - n(rounded-back) = 0?
true returns (n -1) and false returns n(rounded-back)
function qty_test(n) {
n /= 2;
let divisorQTY = n - Math.floor(n) !== 0;
return divisorQTY ? Math.floor(n) : (n - 1);
};
What divisor_test functions does
This function uses the number returned from the previous function (n) to set a for loop that tests every cycle if n is not a factor of the value of the points variable. I.e. points divided by n returns a fraction and if it returns true, meaning a fraction was produced n`s value is indexed in an array and decreaces by 1 (--n).
E.g. divisor_test
n(=8) / 2 = 4 << 2 will be ignored.
n(=8) / 3 = 2.666... << 3 will be collected
function divisor_test(n) {
let nonFactors = [];
n = qty_test(n);
for (let index = 0; index <= n; index++) {
let quotient = (points / n) - Math.floor(points / n) !== 0;
quotient ? nonFactors[index] = n-- : --n;
};
return nonFactors;
};
The program cycles through 5 - 360 and indexes an object with numbers (5-360) and array list of their lower half non factor numbers.
while (points <= 360) {
nonFactors = divisor_test(points);
let testArray = nonFactors.length;
if (testArray) starPolygons[String(points)] = nonFactors;
points++;
};
console.log(starPolygons);
AS YOU CAN SEE IN THIS IMAGE. THE PATTERN OF EMPTY ARRAY INDEXES / ITEMS
UPDATE: I NOTICED THE PATTERN OF ARRAYS WITH THE EMPTY SLOTS HAS AN INTERESTING QUALITY TO IT. This is so cool and so confusing as to what causes this...
During the Iteration you are forcing the array to add an empty item.
So, the empty object appears when the array has only two items in it and you are trying to nonFactors[3] = n--;
and thats what causes the issue.
So a more simplified version of the for loop with the solution will be
for (let index = 0; index <= n; index++) {
let quotient = (points / n) - Math.floor(points / n) !== 0;
if(quotient){
if(index > nonFactors.length){
nonFactors[index - 1] = n--
}else{
nonFactors[index] = n--
}
}else{
n = n -1;
}
};
I solved my problem
There's an answer here that already explains what causes the problem and also gives a working solution by Nadav Hury (upvote his answer. I bet his answer generally works better in more situations)! So I will just post my own version of a solution.
for (let index = 0; n >= 2; index++) {
let quotient = (points / n) - Math.floor(points / n) !== 0;
if (quotient) nonFactors[index] = n--;
else --n, --index;
};
The culprit is that in the line with checking the quotient
quotient ? nonFactors[index] = n-- : --n;
you added setting the value only for the case when it is present that is equal to true but you didn't add to the case when it is false correct solution is:
quotient ? nonFactors[index] = n-- : nonFactors[index] = --n;.
This question already has answers here:
How do I shuffle a Javascript Array ensuring each Index is in a new position in the new Array?
(5 answers)
Closed 1 year ago.
I'm pretty new to algorithms and am trying to solve a problem that involves generating a list of 5,000 numbers in random order each time it is run. Each number in the list must be unique and be between 1 and 5,000 (inclusive).
function createRandomList() {
let arr = [];
while(arr.length < 5000){
const num = Math.floor(Math.random() * 5000) + 1;
if(arr.indexOf(num) === -1) arr.push(num);
}
console.log(arr);
}
createRandomList()
Here's the solution that I came up with. I wanted to know the Time/Space complexity of this solution. Would it just be O(1) for both space and time because the values are bounded?
Any feedback would be greatly appreciated as well better ways to optimize the solution.
Keep a sequential list around and shuffle it. Fisher-Yates shuffle in-place is O(n).
Mike Bostock suggests an implementation here.
function shuffle(array) {
var m = array.length, t, i;
// While there remain elements to shuffle…
while (m) {
// Pick a remaining element…
i = Math.floor(Math.random() * m--);
// And swap it with the current element.
t = array[m];
array[m] = array[i];
array[i] = t;
}
return array;
}
const sequence = [1,2,3,4,5,6,7,8,9] // or gen this for any length you choose
let randomNonRepeatingSequence = shuffle(sequence)
console.log(randomNonRepeatingSequence)
function createRandomList() {
let i=0, numbers=[]
while(i++<5000) numbers.push(i);
numbers.sort(() => (Math.random() > .5) ? 1 : -1);
return numbers
}
console.log(createRandomList())
Your approach has one big problem: towards the end, it will generate many random numbers which are already contained in your sequence. Consider, you already generated 4999 random numbers. Now for the last one, you only have one possibility left, but you still generate numbers in a range from 1 to 5000. So in average you'll 2500 tries to hit the correct number. Better would be, creating a sequence of your allowed elements and then shuffle this sequence. An easy possibly could be the following.
let arr = [1,2,3,4 ..., 5000]
for (let i = arr.length-1; i > 0; i--){
let r = Math.floor(Math.random() * (i + 1));
let x = a[i]; a[i] = a[r]; a[r] = x;
}
How does is work: first you initialize the array with all your allowed values. Then you pick a random index from your array and switch that with the last element of the array. In the next iteration, the range for your random index is decreased by one, and it's switched with the but-last element. And so on and so forth. Once the loop is down to 1, you have a random sequence of your allowed values.
I'm trying to understand how sorting an array in random order works. So, I found the following code:
var as = ["max","jack","sam"];
var s = as.sort(func);
function func(a, b) {
return 0.5 - Math.random();
}
console.log(s);
my main question is why they use 0.5 not another number?
and how it really works
You used
var as = ["max","jack","sam"];
var s = as.sort(func);
function func(a, b) {
return 0.5 - Math.random();
}
console.log(s);
And here the most important thing is as.sort(func).
func(a,b) will return value in range of [-0.5,0.5].
Because this function return 0.5 - Math.random() and Math.random() will return the float value which is in range of [0,1].
So that your func will return value in range of [-0.5,0.5].
And this mean that sort order will be set increase or decrease.
this is random.
So your result will be random
var as = ["max","jack","sam"];
var s = as.sort(func);
function func(a, b) {
return Math.random();
}
console.log(s);
var as = ["max","jack","sam"];
var s = as.sort(func);
function func(a, b) {
return 0 - Math.random();
}
console.log(s);
var as = ["max","jack","sam"];
var s = as.sort(func);
function func(a, b) {
return 0.5 - Math.random();
}
console.log(s);
Math.random() returns a number between 0 and 1 (exclusive). We're using 0.5 because it is the mean value.
Array.sort() sorts the parameters based on the return value. So, 0.5 - Math.random() will yield either positive or negative value with equal probability. Hence, it will sort the parameters randomly.
How it really works
If the return value of Array.sort() is positive, then the index of the
first parameter will be higher than that of the second.
If it is negative, then the index of the second parameter will be
higher than that of the first.
And, if it is 0, then do nothing.
Math.random() return random value between 0 to 1 (0 is included but 1 is excluded).
So 0.5 act as mid point. If use use value like greater than 1 or less 0 than it will always be either true or false.
So for this reason 0.5 is used.
You can read more here about Math.random()
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
Let's understand it bit more with examples
var as = ["max","jack","sam"];
var s = as.sort(func);
function func(a, b) {
return 0.5 - Math.random();
}
console.log(s);
This is what you get when you use value greater than 1
var as = ["max","jack","sam"];
var s = as.sort(func);
function func(a, b) {
return 1 - Math.random();
}
console.log(s);
This is what happens when you use value less than 0
var as = ["max","jack","sam"];
var s = as.sort(func);
function func(a, b) {
return -1 - Math.random();
}
console.log(s);
P.S :-
Try printing output from all the above condition you will see that last two condition will always return either true or false from function. so you will not get a random sorting.
Now talk about any value from 0 to 0.99 you can use any value but 0.5 will serve your purpose best.Because it's a middle point you're most likely to get best answer.
If you just want to nudge the elements near their starting positions in a random way, sure, use sort with random, but in most cases, that's not what you want. You want to thoroughly shuffle an array, completely randomize the position of every element. And for that random in the built-in sort function is a terrible practice, because it is biased towards the initial state, meaning that the elements in the "shuffled" array will tend to stay near their positions (those that were near the beginning have the high probability of staying near the beginning, etc...). The bigger the size the array grows, the less it gets shuffled.
Here is the proof: Is it correct to use JavaScript Array.sort() method for shuffling?
And here is the function for shuffling arrays I use most of the time. It thoroughly randomizes the position of every element.
function shuffle(arr) { // randomly rearanges the items in an array
const result = [];
for (let i = arr.length-1; i >= 0; i--) {
// picks an integer between 0 and i:
const r = Math.floor(Math.random()*(i+1)); // NOTE: use a better RNG if cryptographic security is needed
// inserts the arr[i] element in the r-th free space in the shuffled array:
for(let j = 0, k = 0; j <= arr.length-1; j++) {
if(result[j] === undefined) {
if(k === r) {
result[j] = arr[i]; // NOTE: if array contains objects, this doesn't clone them! Use a better clone function instead, if that is needed.
break;
}
k++;
}
}
}
return result;
}
Math.random returns a number between 0 and 1.
Sorting function use the return value x as the following :
x == 0 : Same value, can order "how it wants"
x < 0 : the first object is less than the second one, therefore its index in the sorted array will be less than the other's
x > 0 same as x < 0 but the other way around
Since Math.random returns a number between 0 and 1 and we want to also get negative numbers, we must subtract some value.
Here 0.5 - Math.random() would give a number between 0.5 and -0.5
If you call the sort method with a function parameter is called several times. This function should accept two parameters (let's call the first A and the second B) Each time it should return a value:
Less than zero, if A < B
Equal to zero, if A = B
Greater the zero, if A > B
So in this example we need random return values that evenly distribute negative and positive values. Since Math.random() returns a value between 0 and 1, 0.5 - Math.random() will return values between -0.5 and 0.5, which meets the requirements.
Shortest Form (Using Lambda Expression):
To answer the question "How sorting of an array in random order works", as others have mentioned, the Array.sort() function can take a function as parameter.
Syntax:
Array.sort([sort_by_function()])
The inner sort_by_function() accepts two parameters (e.g.: x & y) and with use of Math.random() returns a value between -0.5 to 0.5, it returns:
Negative number (-0.5 to -0.1), if x < y
Zero (0), if x = y Positive
Positive number (0.1 to 0.5), if x > y
Remember, if you don't pass in anything to the outer Array.sort() function, it simply rearranges/sorts the elements in Ascending order, if however, you pass in a function (as argument), then it behaves based on what the inner sort_by_function() returns, as it swaps EACH Element of the given array (by swapping pair of two elements at-a-time) essentially, this swapping is decided based on what the inner sort_by_function() returned.
To achieve random-sort order the Array.sort() function will rearrange/sort each pair of elements as below, for a:
Negative value: swap in ascending order,
Zero: no change,
Positive value: swap in descending order.
Example:
arr.sort(function(x,y){return Math.random() - 0.5});
As no one mentioned about the use of the short Lambda expression, here is an example on how you can shorten the inner parameter-function by use of the Lambda expression as below:
arr.sort(() => Math.random() - 0.5);
I entered a coding test where one of the questions was this: given an array A of integers of any length, and then two numbers N and Z, say whether there are Z (distinct) numbers in A such as their sum is N.
So for example (in the format A N Z):
for [1,2,3] 5 2 the answer is YES because 2+3=5
for [1,2,3] 6 2 the answer is NO because there are no two numbers in A that can be added to make 6
My solution (below) first enumerates every (unordered) combination of Z numbers in A, then sums it, and then searches for N in the list of sums.
Although this solution works fine (passed all test cases, with no timeout), I was told the score was too low for me to continue in the test.
So the question is, what can be improved?
An obvious optimization would be to calculate the sum of each combination immediately, and then stop when a match with N is found; but since I didn't run into time issues I don't think this is the problem. What is the better, more elegant/efficient solution?
function main(a, n, z) {
var spacea = [], // array of unordered combinations of z integers from a
space = [], // array of unique sums of combinations from spacea
res=0; // result (1 or 0)
// produce combination
spacea = combo(a,z);
// put unique sums in space
spacea.forEach(function(arr) {
var s = arr.reduce(function(a,b) {
return a+b;
});
if (space.indexOf(s)<0) space.push(s);
});
// is n in space?
res = space.indexOf(n) === -1 ? "NO" :"YES";
return res;
}
// produces combinations (outputs array of arrays)
function combo(a, z) {
var i,
r = [],
head,
right;
if (z > a.length || z <= 0) {
// do nothing, r is already set to []
}
else if (a.length === z) {
r = [a];
}
else if (1 === z) {
// r = array of array of values from a
a.forEach(function(e) {
r.push([e]);
});
}
else { // by virtue of above tests, z>1 and z<a.length
for (i=0; i<a.length-z+1; i++) {
head = a.slice(i, i+1);
right = combo(a.slice(i+1), z-1);
right.forEach(function(e) {
r.push(head.concat(e));
});
}
}
return r;
}
This is a variation of the subset sum problem, which can be solved with Dynamic Programming for more efficient solution.
The main difference here, is you have an extra restriction - the number of elements that must be used. This extra restriction can be handled by adding another variable (dimension) - the number of already used elements.
The recursive formulas (which you will build the DP solution from) should be:
D(0,0,0) = true
D(i,k,x) = false if i < 0 or k < 0
D(i,k,x) = D(i-1, k, x) OR D(i-1, k-1, x - arr[i])
In the above, D(i,k,x) is true if and only if there is a solution that uses k exactly k numbers, from the first i elements, and sums to x.
Complexity of this solution is O(n*N*Z) where n - number of elements in the array, N - number of distinct elements you can use, Z - target sum.
Let's say I have the following code:
arr = [0.1,0.5,0.2,0.2]; //The percentages (or decimals) we want to distribute them over.
value = 100; //The amount of things we have to distribute
arr2 = [0,0,0,0] //Where we want how many of each value to go
To find out how to equally distribute a hundred over the array is simple, it's a case of:
0.1 * 100 = 10
0.5 * 100 = 50
...
Or doing it using a for loop:
for (var i = 0; j < arr.length; i++) {
arr2[i] = arr[i] * value;
}
However, let's say each counter is an object and thus has to be whole. How can I equally (as much as I can) distribute them on a different value. Let's say the value becomes 12.
0.1 * 12 = 1.2
0.5 * 12 = 6
...
How do I deal with the decimal when I need it to be whole? Rounding means that I could potentially not have the 12 pieces needed.
A correct algorithm would -
Take an input/iterate through an array of values (for this example we'll be using the array defined above.
Turn it into a set of whole values, which added together equal the value (which will equal 100 for this)
Output an array of values which, for this example it will look something like [10,50,20,20] (these add up to 100, which is what we need to add them up to and also are all whole).
If any value is not whole, it should make it whole so the whole array still adds up to the value needed (100).
TL;DR dealing with decimals when distributing values over an array and attempting to turn them into an integer
Note - Should this be posted on a different stackoverflow website, my need is programming, but the actual question will likely be solved using a mathematics. Also, I had no idea how to word this question, which makes googling incredibly difficult. If I've missed something incredibly obvious, please tell me.
You should round all values as you assign them using a rounding that is known to uniformly distribute the rounding. Finally, the last value will be assigned differently to round the sum up to 1.
Let's start slowly or things get very confused. First, let's see how to assign the last value to have a total of the desired value.
// we will need this later on
sum = 0;
// assign all values but the last
for (i = 0; i < output.length - 1; i++)
{
output[i] = input[i] * total;
sum += output[i];
}
// last value must honor the total constraint
output[i] = total - sum;
That last line needs some explanation. The i will be one more than the last allowed int the for(..) loop, so it will be:
output.length - 1 // last index
The value we assign will be so that the sum of all elements is equal to total. We already computed the sum in a single-pass during the assignment of the values, and thus don't need to iterated over the elements a second time to determine it.
Next, we will approach the rounding problem. Let's simplify the above code so that it uses a function on which we will elaborate shortly after:
sum = 0;
for (i = 0; i < output.length - 1; i++)
{
output[i] = u(input[i], total);
sum += output[i];
}
output[i] = total - sum;
As you can see, nothing has changed but the introduction of the u() function. Let's concentrate on this now.
There are several approaches on how to implement u().
DEFINITION
u(c, total) ::= c * total
By this definition you get the same as above. It is precise and good, but as you have asked before, you want the values to be natural numbers (e.G. integers). So while for real numbers this is already perfect, for natural numbers we have to round it. Let's suppose we use the simple rounding rule for integers:
[ 0.0, 0.5 [ => round down
[ 0.5, 1.0 [ => round up
This is achieved with:
function u(c, total)
{
return Math.round(c * total);
}
When you are unlucky, you may round up (or round down) so much values that the last value correction will not be enough to honor the total constraint and generally, all value will seem to be off by too much. This is a well known problem of which exists a multi-dimensional solution to draw lines in 2D and 3D space which is called the Bresenham algorithm.
To make things easy I'll show you here how to implement it in 1 dimension (which is your case).
Let's first discuss a term: the remainder. This is what is left after you have rounded your numbers. It is computed as the difference between what you wish and what you really have:
DEFINITION
WISH ::= c * total
HAVE ::= Math.round(WISH)
REMAINDER ::= WISH - HAVE
Now think about it. The remained is like the piece of paper that you discard when you cut out a shape from a sheet. That remaining paper is still there but you throw it away. Instead of this, just add it to the next cut-out so it is not wasted:
WISH ::= c * total + REMAINDER_FROM_PREVIOUS_STEP
HAVE ::= Math.round(WISH)
REMAINDER ::= WISH - HAVE
This way you keep the error and carry it over to the next partition in your computation. This is called amortizing the error.
Here is an amortized implementation of u():
// amortized is defined outside u because we need to have a side-effect across calls of u
function u(c, total)
{
var real, natural;
real = c * total + amortized;
natural = Math.round(real);
amortized = real - natural;
return natural;
}
On your own accord you may wish to have another rounding rule as Math.floor() or Math.ceil().
What I would advise you to do is to use Math.floor(), because it is proven to be correct with the total constraint. When you use Math.round() you will have smoother amortization, but you risk to not have the last value positive. You might end up with something like this:
[ 1, 0, 0, 1, 1, 0, -1 ]
Only when ALL VALUES are far away from 0 you can be confident that the last value will also be positive. So, for the general case the Bresenham algoritm would use flooring, resulting in this last implementation:
function u(c, total)
{
var real, natural;
real = c * total + amortized;
natural = Math.floor(real); // just to be on the safe side
amortized = real - natural;
return natural;
}
sum = 0;
amortized = 0;
for (i = 0; i < output.length - 1; i++)
{
output[i] = u(input[i], total);
sum += output[i];
}
output[i] = total - sum;
Obviously, input and output array must have the same size and the values in input must be a paritition (sum up to 1).
This kind of algorithm is very common for probabilistical and statistical computations.
Alternate implementation - it remembers a pointer to the biggest rounded value and when the sum differs of 100, increment or decrement value at this position.
const items = [1, 2, 3, 5];
const total = items.reduce((total, x) => total + x, 0);
let result = [], sum = 0, biggestRound = 0, roundPointer;
items.forEach((votes, index) => {
let value = 100 * votes / total;
let rounded = Math.round(value);
let diff = value - rounded;
if (diff > biggestRound) {
biggestRound = diff;
roundPointer = index;
}
sum += rounded;
result.push(rounded);
});
if (sum === 99) {
result[roundPointer] += 1;
} else if (sum === 101) {
result[roundPointer] -= 1;
}