384. 打乱数组 🟨
题目
leetcode 中等
题目
给你一个整数数组 nums ,设计算法来打乱一个没有重复元素的数组。打乱后,数组的所有排列应该是 等可能 的。
实现 Solution class:
- Solution(int[] nums) 使用整数数组 nums 初始化对象
- int[] reset() 重设数组到它的初始状态并返回
- int[] shuffle() 返回数组随机打乱后的结果
示例:
输入
[“Solution”, “shuffle”, “reset”, “shuffle”]
[[[1, 2, 3]], [], [], []]
输出
[null, [3, 1, 2], [1, 2, 3], [1, 3, 2]]
解释
Solution solution = new Solution([1, 2, 3]);
solution.shuffle(); // 打乱数组 [1,2,3] 并返回结果。任何 [1,2,3]的排列返回的概率应该相同。例如,返回 [3, 1, 2]
solution.reset(); // 重设数组到它的初始状态 [1, 2, 3] 。返回 [1, 2, 3]
solution.shuffle(); // 随机返回数组 [1, 2, 3] 打乱后的结果。例如,返回 [1, 3, 2]
题解
- 时间复杂度:
- 初始化:O(n),其中 n 为数组中的元素数量。我们需要 O(n) 来初始化 original。
- reset:O(n)。我们需要 O(n) 将 original 复制到 nums。
- shuffle:O(n)。我们只需要遍历 n 个元素即可打乱数组。
- 空间复杂度:O(n)
记录初始状态需要存储 n 个元素。
js
var Solution = function (nums) {
this.nums = nums
this.original = this.nums.slice()
}
Solution.prototype.reset = function () {
this.nums = this.original.slice()
return this.nums
}
Solution.prototype.shuffle = function () {
for (let i = 0; i < this.nums.length; ++i) {
const j = Math.floor(Math.random() * (this.nums.length - i)) + i
;[this.nums[j], this.nums[i]] = [this.nums[i], this.nums[j]]
}
return this.nums
}
const solution = new Solution([1, 2, 3])
console.log(solution.shuffle())
console.log(solution.reset())
console.log(solution.shuffle())
执行结果
[ 1, 2, 3 ]
[ 1, 2, 3 ]
[ 2, 1, 3 ]
ts
class Solution {
nums: Array<number>;
constructor(nums: number[]) {
this.nums = nums;
}
reset(): number[] {
return this.nums;
}
shuffle(): number[] {
let arr = [...this.nums];
let n = arr.length;
for (let i = 0; i < n; i++) {
// 从 i 到 n-1 随机选一个
const rand = randOne(i, n - 1);
// 交换nums数组i和rand下标的两个元素
[arr[i], arr[rand]] = [arr[rand], arr[i]];
}
return arr;
}
}
// 获取闭区间 [n, m] 内的一个随机整数
function randOne(n, m) {
return Math.floor(Math.random() * (m - n + 1)) + n;
}