题目:给定一个数组,要求实现两个指令函数。第一个函数“shuffle”可以随机打乱这个数组,第
二个函数“reset”可以恢复原来的顺序。
思路: Fisher-Yates 洗牌算法
可以用一个简单的技巧来降低之前算法的时间复杂度和空间复杂度,那就是让数组中的元素互相交换,这样就可以避免掉每次迭代中用于修改列表的时间了。
Fisher-Yates 洗牌算法
Fisher-Yates 洗牌算法跟暴力算法很像。在每次迭代中,生成一个范围在当前下标到数组末尾元素下标之间的随机整数。接下来,将当前元素和随机选出的下标所指的元素互相交换 - 这一步模拟了每次从 “帽子” 里面摸一个元素的过程,其中选取下标范围的依据在于每个被摸出的元素都不可能再被摸出来了。此外还有一个需要注意的细节,当前元素是可以和它本身互相交换的 - 否则生成最后的排列组合的概率就不对了
结合代码学习总结:
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();//克隆?
}
/** Resets the array to its original configuration and return it. */
public int[] reset() {//返回最初的数组
array=original;
original=original.clone();
return original;
}
/** Returns a random shuffling of the array. */
public int[] shuffle() {//打乱随机数组
for(int i=0;i<array.length;i++){
swapAt(i,randRange(i,array.length));
}
return array;
}
}
/**
* Your Solution object will be instantiated and called as such:
* Solution obj = new Solution(nums);
* int[] param_1 = obj.reset();
* int[] param_2 = obj.shuffle();
*/