384. Shuffle an Array

384. Shuffle an Array

https://leetcode.com/problems/shuffle-an-array/

Shuffle a set of numbers without duplicates.

Approach 1 : Mark Element

class Solution {
    vector<int> nums;
public:
    Solution(vector<int>& nums) {
        this->nums = nums;
    }
    
    /** Resets the array to its original configuration and return it. */
    vector<int> reset() {
        return nums;
    }
    
    /** Returns a random shuffling of the array. */
    vector<int> shuffle() {
        vector<int> ans(nums.size());
        vector<bool> mark(nums.size(), 0);
        int findIndex;
        for(int i=ans.size()-1; i>=0; i--) {
            int random = rand()%(i + 1) + 1;
            int n = 0;
            for(int j = 0; j<mark.size(); j++) {
                if(mark[j] == 0) {
                    n++;
                    if(n == random) {
                        mark[j] = 1;
                        ans[i] = nums[j];
                        break;
                    }
                }
            }            
        }
        return ans;
    }
};

/**
 * Your Solution object will be instantiated and called as such:
 * Solution* obj = new Solution(nums);
 * vector<int> param_1 = obj->reset();
 * vector<int> param_2 = obj->shuffle();
 */

Runtime: 208 ms, faster than 58.55% of C++ online submissions for Shuffle an Array.

Memory Usage: 31.3 MB, less than 21.43% of C++ online submissions for Shuffle an Array.

Complexity Analysis

  • Time complexity : O(n2)O(n^2)

    Since we go through the array nums of length n. And for each character, we go through the array mark of length n. So the quadratic time complexity arises.

  • Space complexity : O(n)O(n)

    Because we need to use linear additional space to store the original array for reset operation.

    Also we need to mark the elements that are used. so we another linear additional space to store the mark flag for each element.

    So the total space is n+n=2n=O(n)n + n = 2n = O(n)

Approach 2 : Fish_Yates

Walk through all positions.

For each current position, select an random position and swap the value of the two position.

Proof:

  • For the first position, the probability is 1n\frac{1}{n} obviously for each value [0,n)[0, n).*

    So the probability of left values[1,n)[1, n) is n1n\frac{n-1}{n} .

  • For the second position, select an random value from [1,n)[1, n). the probability is 1n1\frac{1}{n - 1} obviously for each value [1,n)[1, n) .

    Because of n1n1n1=1n\frac{n-1}{n}*\frac{1}{n-1} = \frac{1}{n}

    For the second position, the probability is 1n\frac{1}{n} for each value of [0,n)[0, n)

    So the probability of left values[2,n)[2, n) is n2n\frac{n-2}{n} .

  • For the third position, select an random value from [2,n)[2, n). the probability is 1n2\frac{1}{n - 2} obviously for each value [2,n)[2, n) .

    because of n2n1n2=1n\frac{n-2}{n}*\frac{1}{n-2} = \frac{1}{n}

    For the third position, the probability is 1n\frac{1}{n} for each value [0,n)[0, n).

  • Similarly, we can prove that:

    For ANY position, the probability is 1n\frac{1}{n} for each value [0,n)[0, n).

class Solution {
    private int[] array;
    private int[] original;

    Random rand = new Random();

    private int randRange(int min, int max) {
        return rand.nextInt(max - min) + min;
    }

    private void swapAt(int i, int j) {
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }

    public Solution(int[] nums) {
        array = nums;
        original = nums.clone();
    }
    
    public int[] reset() {
        array = original;
        original = original.clone();
        return original;
    }
    
    public int[] shuffle() {
        for (int i = 0; i < array.length; i++) {
            swapAt(i, randRange(i, array.length));
        }
        return array;
    }
}

Runtime: 77 ms, faster than 70.11% of Java online submissions for Shuffle an Array.

Memory Usage: 50.8 MB, less than 100.00% of Java online submissions for Shuffle an Array.

class Solution {
    vector<int> nums;
public:
    Solution(vector<int> nums) {
        this->nums = nums;
    }
    
    /** Resets the array to its original configuration and return it. */
    vector<int> reset() {
        return nums;
    }
    
    /** Returns a random shuffling of the array. */
    vector<int> shuffle() {
        vector<int> result(nums);
        for (int i = 0;i < result.size();i++) {
            int pos = rand()%(result.size()-i);
            swap(result[i+pos], result[i]);
        }
        return result;
    }
};

Runtime: 204 ms, faster than 75.73% of C++ online submissions for Shuffle an Array.

Memory Usage: 30.2 MB, less than 71.43% of C++ online submissions for Shuffle an Array.

Complexity Analysis

  • Time complexity : O(n)O(n)

    Go through all element of arrays and generate a random index before the current element and swapping the current element and the random element

  • Space complexity : O(n)O(n)

    Because we need to use linear additional space to store the original array for reset operation

Summary

1. Random Value

  • java

    private int randRange(int min, int max) { 
            // [min, max) left-opened right-closed
            return rand.nextInt(max - min) + min;
        }
    
  • cpp

            for (int i = 0;i < result.size();i++) {
                int pos = rand()%(result.size()-i);
                swap(result[i+pos], result[i]);
            }
    

2. Re-emphasize: [left-opened right-closed)

3. Shuffle Method

發佈了208 篇原創文章 · 獲贊 14 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章