Facebook Interview Question
Country: India
Unfortunately this is not uniform randomness as the last values would most predictably be at the begining.
Correct algorithm. Though small nitpick- you actually only need to loop from 0 to < n-1, since the last element will be in the final position already.
We need uniform shuffle. So probability of any element picked for swapping must be equal for all elements.
Divide 0-1 range into N intervals . [0, 1/N), [1/N, 2/N), ... [(N-1)/N, N)
The random number you draw must fall into one of the intervals, its index is the element to swap current element with
e.g. N = 25 then
intervals are [0,4), [4,8), ... [96,100)
(range normalized to 0-100 otherwise, each interval is [0,0.4), [0.4, 0.8) so on )
Then for example, when you draw random number 4,5,6 or 7 then you will swap with index 1 element with the current
Not sure why replies are saying this is not a uniform shuffle.
Conceptually, it's the same as taking out elements from the old array one by one at random, and pushing them in a new array. Except that this is done in place, with the new array being the slice from 0..i-1 and the old array from i to N-1.
public class RandomizeArrayProblem {
public static int binRandom(){
return Math.random() < 0.5 ? 0 : 1;
}
public static int nRandom(int n){
int result = 0;
while(--n >= 0)
result += binRandom();
return result;
}
public static void exch(int [] a, int i, int j){
int t = a[i];
a[i] = a[j];
a[j] = t;
}
public static void shuffle(int [] a){
for(int i = 0; i < a.length; i++)
exch(a, i, nRandom(i));
}
public static void main(String[] args) {
int [] testArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
shuffle(testArray);
System.out.println(Arrays.toString(testArray));
}
}
PHP has a really easy way to solve the problem with
usort($array, 'random');
However, I'll show a custom solution to do the same thing. Note that this code only works for indexed arrays, though upon request I can extend it to work for associative arrays.
function arrShuffle($array)
{
// Prevent errors.
if (count($array) === 1) {
return $array;
}
$newArr = array();
foreach ($array as $key => $value) {
if ($key === 0) {
$newArr[] = $value;
continue;
}
if (random() === 1) {
// Add the current value to the stack.
$newArr[$key] = $value;
} else {
// Switch the value with the last value.
$newArr[$key] = $newArr[$key-1];
$newArr[$key-1] = $value;
}
}
return $newArr;
}
static int[] shuffle(int[] A) {
Random rand = new Random();
int[] shuffledArray = new int[A.Length];
Array.Copy(A, shuffledArray, A.Length);
for (int i = 0; i < shuffledArray.Length; i++) {
swap(ref shuffledArray[i],
ref shuffledArray[Convert.ToInt32(rand.NextDouble() * (shuffledArray.Length - 1))]);
}
return shuffledArray;
}
Suppose that we have a function that return a random number belong to internal [0,1), then we can draw a fuction as fllow:
void shuffle(int A[], int n)
{
for (int i = 0; i < n - 1; ++i)
{
int offset = random() * (n - i);
swap(A[i], A[i] + offset);
}
}
import java.util.Arrays;
import java.util.Random;
public class RandomizeArray {
private Random rand = new Random();
public void randomizeArray(int[] a) {
for(int i = 0; i < a.length; i++) {
int index = rand.nextInt(a.length);
swapValues(a,i, rand.nextInt(a.length));
}
}
private void swapValues(int[] a, int i, int i1) {
int temp = a[i];
a[i] = a[i1];
a[i1] = temp;
}
public static void main(String[] args) {
RandomizeArray randomizeArray = new RandomizeArray();
int a[] = {1,2,3,4,5};
for (int i = 0; i < a.length; i++) {
randomizeArray.randomizeArray(a);
System.out.println(Arrays.toString(a));
}
}
}
import java.util.Arrays;
import java.util.Random;
public class RandomizeArray {
private Random rand = new Random();
public void randomizeArray(int[] a) {
for(int i = 0; i < a.length; i++) {
int index = rand.nextInt(a.length);
swapValues(a,i, rand.nextInt(a.length));
}
}
private void swapValues(int[] a, int i, int i1) {
int temp = a[i];
a[i] = a[i1];
a[i1] = temp;
}
public static void main(String[] args) {
RandomizeArray randomizeArray = new RandomizeArray();
int a[] = {1,2,3,4,5};
for (int i = 0; i < a.length; i++) {
randomizeArray.randomizeArray(a);
System.out.println(Arrays.toString(a));
}
}
}
I was asked that in a Starbuck interview. I came up with the normal solution of recreating the array and swaping away the values.
But the interviewer interesting enough he brough a surprising fact. He mentioned that: using the random function in a very close time frame will have clustered values as it depends this function depends on time to calculate the random value.
So for this solution I'll introduce an small delay of a 10th of a millisecond to enable the random function to be more fairly distribute.
Also I'm reusing the array as it did mention that it returns an array but not a new array.
using System.Threading;
static public T[] GetRandomizedArray(T[] A)
{
Random r = new Random();
for(int i = 0; i > A.Length; i++)
{
// The value is between 0..1 not inclusive so it will never
// A.Length when multiply
double rValue = r.NextDouble();
int newIndex = rValue*(A.Length);
T swap = A[newIndex];
A[newIndex] = A[i];
A[i] = swap;
// Max of 10th of a Millisecond wait to get fairly distributed random values
long waitTicks = (long) rValue*TimeSpan.TicksPerMillisecond / 10;
Thread.CurrentThred.Sleep(TimeSpan.FromTicks(waitTicks));
}
}
Given an integer array 'a' of the length 'N' the problem can be solved as follows:
For each 'i' in 0 to N-1:
(i) generate a random number 'k' that is betweem 'i' and N-1
(ii) swap elements a[i] and a[k]
This algorithm yields in a uniform shuffling, hence all possible permutations are equally possible.
- autoboli May 07, 2015