leetcode 384. Shuffle an Array

257 篇文章 17 订阅

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();
我就用的最简单的方法,得到一个随机index,若将该index的数存入随机数组,未出现过,则存入数组,若出现过,则找下一个随机index。没想到AC了,不过时间复杂度bu'za'd

package leetcode;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Random;

public class Shuffle_an_Array_384 {

	int[] oriNums;
	int n;
	Random random=new Random();
	
	public Shuffle_an_Array_384(int[] nums) {
		oriNums=nums.clone();
		n=nums.length;
	}

	/** Resets the array to its original configuration and return it. */
	public int[] reset() {
		return oriNums;
	}

	/** Returns a random shuffling of the array. */
	public int[] shuffle() {
		if(n==0){
			return new int[]{};
		}
		int[] result=new int[n];
		HashSet<Integer> hashSet=new HashSet<Integer>();
		int pointer=0;
		while(pointer<n){
			int index=random.nextInt(n);
			while(hashSet.contains(index)){
				index=random.nextInt(n);
			}
			hashSet.add(index);
			result[pointer]=oriNums[index];
			pointer++;
		}
		return result;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] nums=new int[]{1,2,3};
		Shuffle_an_Array_384 s=new Shuffle_an_Array_384(nums);
		System.out.println(Arrays.toString(s.reset()));
		System.out.println(Arrays.toString(s.shuffle()));
	}

}

下面看大神的方法:

import java.util.Random;

public class Solution {
    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 nums;
    }
    
    /** Returns a random shuffling of the array. */
    public int[] shuffle() {
        if(nums == null) return null;
        int[] a = nums.clone();
        for(int j = 1; j < a.length; j++) {
            int i = random.nextInt(j + 1);
            swap(a, i, j);
        }
        return a;
    }
    
    private void swap(int[] a, int i, int j) {
        int t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
}
下面我们来理解一下这个算法的正确性:每个元素有相等的几率出现在数组中的任意一个位置。
对于[1,2,3]这个数组:

循环:j= 1 :0th元素被移到1st位置的概率=( i=0的概率) =1/2
                     1st元素被移到1st位置的概率=( i=1的概率) =1/2

循环:j=2 :0th元素被移到2nd位置的概率= (已经在1st位置的0th元素与2nd位置交换)+ (保留在0th位置的0th元素与2nd位置交换)
                                                                   =    1/2*1/3+1/2*1/3
                                                                   =    1/3 
                    1st元素被移到2nd位置的概率= (已经在0th位置的1st元素与2nd位置交换)+ (保留在1st位置的1st元素与2nd位置交换)
                                                                   =    1/2*1/3+1/2*1/3
                                                                   =    1/3
                    2nd元素被移到2nd位置的概率= 1 - 0th元素被移到2nd位置的概率- 1st元素被移到2nd位置的概率
                                                                   =    1-1/3-1/3
                                                                   =    1/3

我们可以给出正确性的小小证明。对于the 0th element,它一直保留在 index 0位置的可能性是 1/1 * (2-1)/2 * (3-1)/3 * ... (n-1)/n = 1/n,它待在index 1位置的可能性是 1/2 * (3-1)/3 * ... = 1/n,它待在index 2位置的可能性是 1/3 * (4-1)/4 * ...=1/n,这意味着对于 the 0th element,它有 1/n 可能性被安置在任意某个位置。

一旦我们知道了0th 元素将会待在 index x。比如,我们知道0th元素将会待在index 0,那么1st 元素待在 1st position 的可能性是多少呢?是 1/1 * 1/2 * ... (n-2)/(n-1) = 1/(n-1). 这说明了对于 1st 元素,它有1/(n-1) 可能性被安置在任何未被占据的位置上。

证明:假设该结论成立,即对于每个position j (starting from 0), 在 [0,j] 范围内的每个数字出现在 position j 的可能性是 1/(1+j)  
Let's look at int i = random.nextInt(j + 1):
(1)如果 i == j, nums[j] 就不需要改变它的位置,这种情况的可能性是 1/(1+j).
(2)如果 i !=j, nums[j] 需要与 nums[i] 交换,那么在 [0,j-1] 范围内的某个元素x 位于 position j的可能性=( nums[j]改变了它的位置的可能性)   *  ( x在position j的可能性)
                                                                                                                                                              =   (1-1/(1+j)) * (1/j) = 1/(1+j)
则假设成立

对于程序本身,有人疑惑:Why int i = random.nextInt(j + 1);, not int i = random.nextInt(j);?
回答是:nextInt(j + 1) returns a random num between [0, j]. By nextInt(j), you never get a chance to return the original order array.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值