leetcode384. Shuffle an Array

題目要求

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)的時間隨機打亂一個數組。算法

該算法的步驟以下:數組

  1. 從數組中隨機選擇一個數字,與數組最後一個數字交換
  2. 從前n-1個元素中隨機選擇一個數字,與第n-1個數字交換
  3. 從前n-2個元素中隨機選擇一個數字,與第n-2個數字交換...

重複以上步驟,直到數組第一個元素。dom

下面解釋一下證實,即爲什麼每一個該結果是等機率的排列組合結果。this

第一步操做,對於數組中全部的元素,均有1/n的機率交換到最後一個位置上code

第二步操做能夠分爲兩種場景。it

  • 場景一:選中進行交換的元素爲以前的最後一個元素,則該元素被選中的機率等於上一回閤中該元素被交換到別的位置的機率乘以在當前n-1個元素中被選中的機率,即((n-1)/n) * (1/n-1) = 1/n
  • 場景二:選中進行交換的元素爲其他的n-1個元素,則該元素被選中的機率等於上一回閤中該元素沒被選中交換到最後一個位置的機率乘以在當前n-1個元素中被選中的機率,即((n-1)/n * (1/n-1)) = 1/n

第三步操做能夠分爲三種場景:io

  • 場景一:選中進行交換的元素爲最後一個元素,則該元素被選中的機率等於該元素被交換到前面n-2個元素的機率乘以該元素在當前n-1個元素中被選中的機率。該元素沒有被交換到前面n-2個元素只有兩種可能,即位於原來的位置,或是被交換到倒數第二個位置,所以交換到前面n-2個元素的機率爲(1 - 1/n - (n-1)/n * 1 / (n-1)) = (n-2) / n , 所以最終機率爲(n-2)/n * 1/(n-2) = 1/n
  • 場景二:選中進行交換的元素爲倒數第二個元素,則該元素被選中的機率等於該元素被交換到前面n-2個元素的機率乘以該元素在當前n-2個元素中被選中的機率。該元素沒有被交換到前面n-2個元素只有兩種可能,即該元素被交換至最後一個元素,或是依然位於原來的位置,所以交換到前面n-2個元素的機率爲(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;
    }
相關文章
相關標籤/搜索