[398]. 随机数索引
Posted Debroon
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[398]. 随机数索引相关的知识,希望对你有一定的参考价值。
[398]. 随机数索引
题目
传送门:398. 随机数索引
给你一个可能含有 重复元素 的整数数组 nums ,请你随机输出给定的目标数字 target 的索引。
// 实现 Solution 类:
- Solution(int[] nums)
- int pick(int target)
// 从 nums 中选出一个满足 nums[i] == target 的随机索引 i 。
// 你可以假设给定的数字一定存在于数组中。
// 如果存在多个有效的索引,则随机选取一个,且保证每个索引的返回概率应当相等。
算例:
// 输入
["Solution", "pick", "pick", "pick"]
[[[1, 2, 3, 3, 3]], [3], [1], [3]]
// 输出
[null, 4, 0, 2]
// 解释
Solution solution = new Solution([1, 2, 3, 3, 3]);
solution.pick(3); // 随机返回索引 2, 3 或者 4 之一。每个索引的返回概率应该相等。
solution.pick(1); // 返回 0 。因为只有 nums[0] 等于 1 。
solution.pick(3); // 随机返回索引 2, 3 或者 4 之一。每个索引的返回概率应该相等。
算法设计:哈希思路
哈希算法一般是用一个 hash 数组来记录一个 key 对应的有无或者统计对应的个数,用 key 作为 hash 数组的下标,而下标对应的值用来表示该 key 的存在与否以及统计对应的个数。
比如,传入参数是 [1, 2, 3, 3, 3]。
- 值为 1 的索引有哪些,放入一个数组中
- 值为 2 的索引有哪些,放入一个数组中
- 值为 3 的索引有哪些,放入一个数组中
再从某个匹配数组中,随机选取一个,这样就实现了等概率。
class Solution
unordered_map<int, vector<int>> pos;
public:
Solution(vector<int> &nums)
int n = nums.size(); // 缓存,减少不必要的重复计算
for (int i = 0; i < n; ++i)
pos[nums[i]].push_back(i);
// 值为 nums[i] 的索引有哪些,放入一个数组
int pick(int target)
return pos[target][rand() % pos[target].size()];
// 再从某个匹配数组中,随机选取一个
;
时间复杂度: θ ( n ) \\theta(n) θ(n)
空间复杂度:
θ
(
n
)
\\theta(n)
θ(n)
模偏差:rand( ) 的不公平问题
rand() % 3 // C语言产生随机数函数
random() % 3 // CPP 产生随机数函数
rand() 会生成一个 0 - 32767(INT_MAX - 1) 的数。
- rand() % 3 = 0,等于 0 的情况,有 10923 个
- rand() % 3 = 1,等于 1 的情况,有 10923 个
- rand() % 3 = 2,等于 2 的情况,有 10922 个
因为整型最大值的限制,其实会产生一个模偏差,并没有实现真正的概率平等(公平)。
但是 OJ 平台因为数据量较少,所以可以过。
但,尽管如此,也是没有真正公平的。
我们使用 random() 代替 rand(),虽然运算速度下降了一点点,不过是公平的。
class Solution
unordered_map<int, vector<int>> pos;
public:
Solution(vector<int> &nums)
int n = nums.size(); // 缓存,减少不必要的重复计算
for (int i = 0; i < n; ++i)
pos[nums[i]].push_back(i);
// 值为 nums[i] 的索引有哪些,放入一个数组
int pick(int target)
return pos[target][random() % pos[target].size()];
// 再从某个匹配数组中,等概率随机选取一个
;
- random() 是如何消除模偏差的呢:用C++的random库生成更好的随机数
算法设计:蓄水池抽样
以上是关于[398]. 随机数索引的主要内容,如果未能解决你的问题,请参考以下文章