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();
實現shuffle和reset方法,分別可以完成數組的隨機打亂和還原。隨機打亂即該數組中元素的全部排列組合結果都可以以等比例的機率輸出。java
直觀的思路來講,咱們會將數組複製一份,並根據數組的長度來生成隨機數,並得到該隨機數下標上的值放在新的位置上。本文將詳細講解一下網上的另外一種解法,即Fisher–Yates
算法,該算法可以用O(n)的時間隨機打亂一個數組。算法
該算法的步驟以下:數組
重複以上步驟,直到數組第一個元素。dom
下面解釋一下證實,即爲什麼每一個該結果是等機率的排列組合結果。this
第一步操做,對於數組中全部的元素,均有1/n的機率交換到最後一個位置上code
第二步操做能夠分爲兩種場景。it
((n-1)/n) * (1/n-1) = 1/n
((n-1)/n * (1/n-1)) = 1/n
第三步操做能夠分爲三種場景:io
(1 - 1/n - (n-1)/n * 1 / (n-1)) = (n-2) / n
, 所以最終機率爲(n-2)/n * 1/(n-2) = 1/n
(1 - 1/n - (n-1)/n * 1 / (n-1)) = (n-2) / n
, 所以最終機率爲(n-2)/n * 1/(n-2) = 1/n
1/n
綜上,這種方法可以保證每個元素能夠等機率出如今任何位置上。代碼以下:class
private int[] nums; private Random random; public Solution(int[] nums) { this.nums = nums; random = new Random(); } /** Resets the array to its original configuration and return it. */ public int[] reset() { return this.nums; } /** Returns a random shuffling of the array. */ public int[] shuffle() { if(nums == null) return null; int[] result = nums.clone(); for(int j = 1; j < result.length; j++) { int i = random.nextInt(j + 1); swap(result, i, j); } return result; } private void swap(int[] a, int i, int j) { int t = a[i]; a[i] = a[j]; a[j] = t; }