Question:
Shuffle a set of numbers without duplicates.
Example:
// Init an array with set 1, 2, and 3.
int[] nums = {1,2,3};
Solution solution = new Solution(nums);
// Shuffle the array [1,2,3] and return its result. Any permutation of [1,2,3] must equally likely to be returned.
solution.shuffle();
// Resets the array back to its original configuration [1,2,3].
solution.reset();
// Returns the random shuffling of array [1,2,3].
solution.shuffle();
Answer:
var Solution = function(nums) {
// hold nums in Solution
this.nums = nums;
};
Solution.prototype.reset = function() {
return this.nums;
};
Solution.prototype.shuffle = function() {
// create a copy of this.nums, shuffle it, and return it0
const shuffled = this.nums.slice();
const n = shuffled.length;
const swap = (arr, i, j) => {
let tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
// swap elements with random elements
for (let i = 0; i < n; i++)
swap(shuffled, i, Math.floor(Math.random() * n));
return shuffled;
};
My question:
The Math.floor(Math.random() * n ) you are getting a random index out of the length of the array. I do not understand, can't this code make duplicates? Say if the length is 3. Cant the formula get the index of 2 and another index of 2, thus making duplicate indexes. Can anyone clarify something I am misunderstanding. Thanks. Does Math.random automatically withdraw indexes that have been used?
Yes, the Math.floor(Math.random() * n) expression can evaluate to the same number multiple times, but that's OK, because the random number is being used in swap, which switches the number at index i with the number at the chosen random index.
If the random index was taken from the original array and added to the array to be returned, eg
const randIndex = Math.floor(Math.random() * n);
arrToBeReturned.push(arr[randIndex]);
you'd be right, but that's not what the algorithm is doing. Imagine randomly sorting an array of [1, 2, 3]:
First iteration of loop: i is 0, random index chosen is 2. Swap indicies 0 and 2:
[3, 2, 1]
Second iteration: i is 1, random index chosen is 2. Swap indicies 1 and 2:
[3, 1, 2]
Third iteration: i is 2, random index chosen is 2. Swap indicies 2 and 2:
[3, 1, 2]
With this code, every index is randomly swapped with another index at least one time, ensuring that by the end, the array is randomized without bias (assuming Math.random is trustworthy).
Math.floor(Math.random() * n) Yes it can eve-valuate to same index but here you're using the number to swap element so this is ok.
Does Math.random automatically withdraw indexes that have been used?
No it doesn't you need to keep track of previously generated values
What you can do it is have a variable a object or Map to keep track of previously add index if the random generated index is not already included in that variable than add it to final output else again generate a new index,
But in this case it is not needed.
Related
I am trying to get the index of the max element after left rotation. Idea is to rotate array a based on the rotate array. So rotate array is looped over and every iteration array a is rotated that many times as the value of the elementin rotate.. lets say if its 2 then rotate array 'a' 2 times. At the same time find the index of max element of rotated array and keep storing it. However the code is taking way too long to execute and the test time out after some time
lets say this is my array
const a = [ 1, 2, 4, 3 ];
const rotate = [ 2, 1 ];
expected output of getLargestItemIndices would be array like this
[ 0, 1 ]
As for first iteration (2 rotations) max value (4) is at index 0 and 2nd iteration max value is at 1
let indices =[];
const getMaxValueIndex = (arr)=>{
const maxValue = Math.max.apply(Math, arr);
return arr.indexOf(maxValue);
}
const rotateArray = (a,d)=>{
while (d) {
a.push(a.shift());
d--;
}
indices.push(getMaxValueIndex(a));
}
function getLargestItemIndices(a, rotate) {
for (var index = 0; index < rotate.length; index++) {
rotateArray(a.slice(), rotate[index]);
}
return indices;
}
How can i make my loop faster its taking way too long
TL;DR By removing the rotateArray() function
Longer explanation:
I suggest breaking this into smaller parts. First, I would write a function to get the index of the largest item in the input array. You can do this easily with a single for loop.
Now once you know the starting index of the largest item. Think about how you can quickly calculate the index of that item after a rotation of n positions. Repeat this for each number in the rotate array.
Im just wondering who can explain the algorithm of this solution step by step. I dont know how hashmap works. Can you also give a basic examples using a hashmap for me to understand this algorithm. Thank you!
var twoSum = function(nums, target) {
let hash = {};
for(let i = 0; i < nums.length; i++) {
const n = nums[i];
if(hash[target - n] !== undefined) {
return [hash[target - n], i];
}
hash[n] = i;
}
return [];
}
Your code takes an array of numbers and a target number/sum. It then returns the indexes in the array for two numbers which add up to the target number/sum.
Consider an array of numbers such as [1, 2, 3] and a target of 5. Your task is to find the two numbers in this array which add to 5. One way you can approach this problem is by looping over each number in your array and asking yourself "Is there a number (which I have already seen in my array) which I can add to the current number to get my target sum?".
Well, if we loop over the example array of [1, 2, 3] we first start at index 0 with the number 1. Currently, there are no numbers which we have already seen that we can add with 1 to get our target of 5 as we haven't looped over any numbers yet.
So, so far, we have met the number 1, which was at index 0. This is stored in the hashmap (ie object) as {'1': 0}. Where the key is the number and the value (0) is the index it was seen at. The purpose of the object is to store the numbers we have seen and the indexes they appear at.
Next, the loop continues to index 1, with the current number being 2. We can now ask ourselves the question: Is there a number which I have already seen in my array that I can add to my current number of 2 to get the target sum of 5. The amount needed to add to the current number to get to the target can be obtained by doing target-currentNumber. In this case, we are currently on 2, so we need to add 3 to get to our target sum of 5. Using the hashmap/object, we can check if we have already seen the number 3. To do this, we can try and access the object 3 key by doing obj[target-currentNumber]. Currently, our object only has the key of '1', so when we try and access the 3 key you'll get undefined. This means we haven't seen the number 3 yet, so, as of now, there isn't anything we can add to 2 to get our target sum.
So now our object/hashmap looks like {'1': 0, '2': 1}, as we have seen the number 1 which was at index 0, and we have seen the number 2 which was at index 1.
Finally, we reach the last number in your array which is at index 2. Index 2 of the array holds the number 3. Now again, we ask ourselves the question: Is there a number we have already seen which we can add to 3 (our current number) to get the target sum?. The number we need to add to 3 to get our target number of 5 is 2 (obtained by doing target-currentNumber). We can now check our object to see if we have already seen a number 2 in the array. To do so we can use obj[target-currentNumber] to get the value stored at the key 2, which stores the index of 1. This means that the number 2 does exist in the array, and so we can add it to 3 to reach our target. Since the value was in the object, we can now return our findings. That being the index of where the seen number occurred, and the index of the current number.
In general, the object is used to keep track of all the previously seen numbers in your array and keep a value of the index at which the number was seen at.
Here is an example of running your code. It returns [1, 2], as the numbers at indexes 1 and 2 can be added together to give the target sum of 5:
const twoSum = function(nums, target) {
const hash = {}; // Stores seen numbers: {seenNumber: indexItOccurred}
for (let i = 0; i < nums.length; i++) { // loop through all numbers
const n = nums[i]; // grab the current number `n`.
if (hash[target - n] !== undefined) { // check if the number we need to add to `n` to reach our target has been seen:
return [hash[target - n], i]; // grab the index of the seen number, and the index of the current number
}
hash[n] = i; // update our hash to include the. number we just saw along with its index.
}
return []; // If no numbers add up to equal the `target`, we can return an empty array
}
console.log(twoSum([1, 2, 3], 5)); // [1, 2]
A solution like this might seem over-engineered. You might be wondering why you can't just look at one number in the array, and then look at all the other numbers and see if you come across a number that adds up to equal the target. A solution like that would work perfectly fine, however, it's not very efficient. If you had N numbers in your array, in the worst case (where no two numbers add up to equal your target) you would need to loop through all of these N numbers - that means you would do N iterations. However, for each iteration where you look at a singular number, you would then need to look at each other number using a inner loop. This would mean that for each iteration of your outer loop you would do N iterations of your inner loop. This would result in you doing N*N or N2 work (O(N2) work). Unlike this approach, the solution described in the first half of this answer only needs to do N iterations over the entire array. Using the object, we can find whether or not a number is in the object in constant (O(1)) time, which means that the total work for the above algorithm is only O(N).
For further information about how objects work, you can read about bracket notation and other property accessor methods here.
You may want to check out this method, it worked so well for me and I have written a lot of comments on it to help even a beginner understand better.
let nums = [2, 7, 11, 15];
let target = 9;
function twoSums(arr, t){
let num1;
//create the variable for the first number
let num2;
//create the variable for the second number
let index1;
//create the variable for the index of the first number
let index2;
//create the variable for the index of the second number
for(let i = 0; i < arr.length; i++){
//make a for loop to loop through the array elements
num1 = arr[i];
//assign the array iteration, i, value to the num1 variable
//eg: num1 = arr[0] which is 2
num2 = t - num1;
//get the difference between the target and the number in num1.
//eg: t(9) - num1(2) = 7;
if(arr.includes(num2)){
//check to see if the num2 number, 7, is contained in the array;
index1 = arr.indexOf(num2);
//if yes get the index of the num2 value, 7, from the array,
// eg: the index of 7 in the array is 1;
index2 = arr.indexOf(num1)
//get the index of the num1 value, which is 2, theindex of 2 in the array is 0;
}
}
return(`[${index1}, ${index2}]`);
//return the indexes in block parenthesis. You may choose to create an array and push the values into it, but consider space complexities.
}
console.log(twoSums(nums, target));
//call the function. Remeber we already declared the values at the top already.
//In my opinion, this method is best, it considers both time complexity and space complexityat its lowest value.
//Time complexity: 0(n)
function twoSum(numbers, target) {
for (let i = 0; i < numbers.length; i++) {
for (let j = i + 1; j < numbers.length; j++) {
if (numbers[i] + numbers[j] === target) {
return [numbers.indexOf(numbers[i]), numbers.lastIndexOf(numbers[j])];
}
}
}
}
Could anyone provide a clear explanation on what did they do in the example below? It is really confusing.
function reverseArrayInPlace(array) {
for (var i = 0; i < Math.floor(array.length / 2); i++) {
var old = array[i];
array[i] = array[array.length - 1 - i];
array[array.length - 1 - i] = old;
}
return array;
}
var arrayValue = [1, 2, 3, 4, 5];
reverseArrayInPlace(arrayValue);
console.log(arrayValue);
The loop iterates through the first half of the array, up to but not including the middle value for an array with an odd number of elements (since the middle value stays in the same place when the array is reversed).
The first time through the loop, the values of the first and last positions in the array are reversed.
The second time through the loop, the values of the second and second last positions in the array are reversed.
etc...
It's not very complicated really, just get a bit of paper, write down 5 boxes for the array and then step through the program in your head working out what happens at each step. For example:
1,2,3,4,5
i=0
old=1
5,2,3,4,5
5,2,3,4,1
i=1
Continue like that, I got you started.
What is the best way to randomize part of the array in Javascript
For example, if I have 100 items in the array, what is the fast and efficient way of randomizing set of every 10 times. Items between 0 and 9 is randomize within data items[0] to items[9]. Items between 10 to 19 are randomize within data items[10] to items[19] and so on..
You can adjust the array shuffle method that is described here: http://jsfromhell.com/array/shuffle
It is based on Fisher-Yates (Knuth) algorithm (http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
I would just use the built in slice, concat and sort methods. Something like this.
function shuffle(arr, start, end) {
return arr.slice(start, end).sort(function() { return .5 - Math.random(); }).concat(arr.slice(end));
};
That's the basic idea, you probably want to make an algorithm to slice every 10 elements, sort and rejoin the sets.
EDIT: Read comments below for why this solution may not be suitable for your needs.
I would split the 1 array into 10 subsets, then perform a shuffle algorithm of your choice on those subsets, and then recombine in the correct order.
The following shuffles the specified chunk of an array in place, as randomly as the environment's random number generator will allow:
function shuffleSubarray(arr, start, length) {
var i = length, temp, index;
while (i--) {
index = start + Math.floor(i * Math.random());
temp = arr[index];
arr[index] = arr[start + i];
arr[start + i] = temp;
}
return arr;
}
var a = [1, 2, 3, 4, 5, 6, 7, 8, 9];
alert( shuffleSubarray(a, 2, 5) );
Alright, I'm taking an array, and making another array from it with the only difference being the indexes are displaced by an arbitrary number determined using two reference points (one in each array). Doing this creates negative indexes, which if it didn't stop the script from working, would be useful. Is there any way to have the second array have the negative indexes and work, or am I going to have to use an all-together different method? I rewrote the code to be a simple case.
var firstArray = {
field: [ 1, 2, 3, 4, 5],
referenceIndex : 2
};
var secondArray = {
referenceIndex: 1,
offset: 0,
field : {}
};
// Create secondArray.field by finding the offset.
secondArray.offset = firstArray.referenceIndex - secondArray.referenceIndex;
for (i=0; i < firstArray.field.length; i++){
alert([i - secondArray.offset, firstArray.field[i]].join(" "));
secondArray.field[i - secondArray.offset] = firstArray.field[i]; //creates a negative index.
}
An array can have (in a strict sense) only positive integer as indices. However it is also an object, so it can take any string as a property. So in a sense, it will 'work', but do not trust Array#length to have the right value.
var arr = [1,2,3];
arr.length //3
arr[10] = 10;
arr.length //11
arr["blah"] = 100;
arr.length //still 11
arr[-1] = 200;
arr.length //still 11
I'd also like to point you to this excellent article - http://javascriptweblog.wordpress.com/2010/07/12/understanding-javascript-arrays/
No you can't have negative indices and have it work properly, however, you possibly could save a number and add it to your index to create a positive value. For example you have indeces -2 through 4. In the array this would be 0 - 6 so you would need to add or subtract 2 to get to the value of the index you want.