LeetCodee

384. Shuffle an Array

Jump to Solution: Python Java C++ JavaScript C#

Problem Description

Given an integer array nums, design an algorithm to randomly shuffle the array. All permutations of the array should be equally likely as a result of the shuffling.

Implement the Solution class:

  • Solution(int[] nums) Initializes the object with the integer array nums.
  • int[] reset() Resets the array to its original configuration and returns it.
  • int[] shuffle() Returns a random shuffling of the array.

Example 1:

Input
["Solution", "shuffle", "reset", "shuffle"]
[[[1, 2, 3]], [], [], []]
Output
[null, [3, 1, 2], [1, 2, 3], [1, 3, 2]]

Explanation
Solution solution = new Solution([1, 2, 3]);
solution.shuffle();    // Shuffle the array [1,2,3] and return its result.
                      // Any permutation of [1,2,3] must be equally likely to be returned.
                      // Example: return [3, 1, 2]
solution.reset();      // Resets the array back to its original configuration [1,2,3]. Return [1, 2, 3]
solution.shuffle();    // Returns the random shuffling of array [1,2,3]. Example: return [1, 3, 2]

Constraints:

  • 1 <= nums.length <= 200
  • -10⁶ <= nums[i] <= 10⁶
  • All the elements of nums are unique.
  • At most 5 * 10⁴ calls will be made to reset and shuffle.

Solution

Python Solution

class Solution:
    def __init__(self, nums: List[int]):
        self.original = nums.copy()
        self.array = nums

    def reset(self) -> List[int]:
        self.array = self.original.copy()
        return self.array

    def shuffle(self) -> List[int]:
        # Fisher-Yates shuffle algorithm
        for i in range(len(self.array)):
            # Generate random index between i and end
            j = random.randint(i, len(self.array) - 1)
            # Swap elements at i and j
            self.array[i], self.array[j] = self.array[j], self.array[i]
        return self.array

Time Complexity:

  • Constructor: O(n) for copying array
  • reset(): O(n) for copying array
  • shuffle(): O(n) for Fisher-Yates shuffle

Space Complexity: O(n)

For storing the original and current array.

Java Solution

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

    public Solution(int[] nums) {
        original = nums.clone();
        array = nums.clone();
        rand = new Random();
    }
    
    public int[] reset() {
        array = original.clone();
        return array;
    }
    
    public int[] shuffle() {
        // Fisher-Yates shuffle algorithm
        for (int i = 0; i < array.length; i++) {
            // Generate random index between i and end
            int j = rand.nextInt(array.length - i) + i;
            // Swap elements at i and j
            int temp = array[i];
            array[i] = array[j];
            array[j] = temp;
        }
        return array;
    }
}

Time Complexity:

  • Constructor: O(n) for copying array
  • reset(): O(n) for copying array
  • shuffle(): O(n) for Fisher-Yates shuffle

Space Complexity: O(n)

For storing the original and current array.

C++ Solution

class Solution {
private:
    vector original;
    vector array;
    
public:
    Solution(vector& nums) {
        original = nums;
        array = nums;
    }
    
    vector reset() {
        array = original;
        return array;
    }
    
    vector shuffle() {
        // Fisher-Yates shuffle algorithm
        for (int i = 0; i < array.size(); i++) {
            // Generate random index between i and end
            int j = rand() % (array.size() - i) + i;
            // Swap elements at i and j
            swap(array[i], array[j]);
        }
        return array;
    }
};

Time Complexity:

  • Constructor: O(n) for copying array
  • reset(): O(n) for copying array
  • shuffle(): O(n) for Fisher-Yates shuffle

Space Complexity: O(n)

For storing the original and current array.

JavaScript Solution

/**
 * @param {number[]} nums
 */
class Solution {
    constructor(nums) {
        this.original = [...nums];
        this.array = [...nums];
    }
    
    /** 
     * @return {number[]}
     */
    reset() {
        this.array = [...this.original];
        return this.array;
    }
    
    /** 
     * @return {number[]}
     */
    shuffle() {
        // Fisher-Yates shuffle algorithm
        for (let i = 0; i < this.array.length; i++) {
            // Generate random index between i and end
            const j = Math.floor(Math.random() * (this.array.length - i)) + i;
            // Swap elements at i and j
            [this.array[i], this.array[j]] = [this.array[j], this.array[i]];
        }
        return this.array;
    }
}

Time Complexity:

  • Constructor: O(n) for copying array
  • reset(): O(n) for copying array
  • shuffle(): O(n) for Fisher-Yates shuffle

Space Complexity: O(n)

For storing the original and current array.

C# Solution

public class Solution {
    private int[] original;
    private int[] array;
    private Random rand;

    public Solution(int[] nums) {
        original = (int[])nums.Clone();
        array = (int[])nums.Clone();
        rand = new Random();
    }
    
    public int[] Reset() {
        array = (int[])original.Clone();
        return array;
    }
    
    public int[] Shuffle() {
        // Fisher-Yates shuffle algorithm
        for (int i = 0; i < array.Length; i++) {
            // Generate random index between i and end
            int j = rand.Next(i, array.Length);
            // Swap elements at i and j
            int temp = array[i];
            array[i] = array[j];
            array[j] = temp;
        }
        return array;
    }
}

Time Complexity:

  • Constructor: O(n) for copying array
  • reset(): O(n) for copying array
  • shuffle(): O(n) for Fisher-Yates shuffle

Space Complexity: O(n)

For storing the original and current array.

Approach Explanation

The solution uses the Fisher-Yates (or Knuth) shuffle algorithm:

  1. Key Insights:
    • Uniform distribution
    • In-place shuffling
    • Original array preservation
    • Efficient implementation
  2. Algorithm Steps:
    • Start from first element
    • Pick random remaining element
    • Swap current with random
    • Move to next position

Implementation Details:

  • Array copying methods
  • Random number generation
  • Swap operations
  • Index calculations

Optimization Insights:

  • Efficient array copying
  • In-place operations
  • Random number range
  • Memory management

Edge Cases:

  • Single element array
  • Large arrays
  • Multiple shuffles
  • Reset after shuffle