返回
随机数索引:哈希表预处理与蓄水池抽样
后端
2023-09-08 23:46:09
随机数索引:哈希表预处理与蓄水池抽样
哈希表预处理:快速索引查找
假设我们有一个包含整数的数组,我们需要有效地从数组中获取某个特定元素的索引。哈希表预处理 可以轻松解决这个问题。我们可以将数组中的每个元素和它的索引存储在一个哈希表中。这样,当我们想要获取特定元素的索引时,只需查找哈希表即可,时间复杂度为 O(1)。
class Solution {
private HashMap<Integer, Integer> map;
public Solution(int[] nums) {
map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
map.put(nums[i], i);
}
}
public int pick(int target) {
return map.get(target);
}
}
蓄水池抽样:概率子集选择
现在,假设我们有一个包含大量元素的集合,我们想要从中随机抽取一个子集。蓄水池抽样 是一种聪明的算法,可以解决这个问题。它的工作原理如下:
- 从集合中选择第一个元素并将其放入子集中。
- 从第二个元素开始,对于每个元素:
- 计算它被选入子集的概率(该概率等于子集中的元素数量除以集合中的元素总数量)。
- 根据概率生成一个随机数,如果随机数小于或等于概率,则将元素加入子集中。
这种方法确保每个元素都有相同的概率被选入子集中。
import java.util.List;
import java.util.Random;
public class ReservoirSampling {
public static <T> List<T> sample(List<T> elements, int k) {
List<T> reservoir = new ArrayList<>();
int count = 0;
for (T element : elements) {
count++;
if (reservoir.size() < k) {
reservoir.add(element);
} else {
int randomIndex = new Random().nextInt(count);
if (randomIndex < k) {
reservoir.set(randomIndex, element);
}
}
}
return reservoir;
}
}
选择适合你的方法
哈希表预处理和蓄水池抽样都有其优点和缺点:
方法 | 优点 | 缺点 |
---|---|---|
哈希表预处理 | 快速索引查找 | 需要额外的空间存储哈希表 |
蓄水池抽样 | 无需存储整个集合 | 每个元素被选中的概率不完全相等 |
选择最适合你的方法取决于你的特定需求。哈希表预处理对于需要快速索引查找的情况非常有用,而蓄水池抽样对于需要从大集合中选择随机子集的情况非常有用。
常见问题解答
-
哈希表预处理的时间复杂度是多少?
- 预处理:O(n)(n 为数组长度)
- 索引查找:O(1)
-
蓄水池抽样的概率是否总是 100%?
- 不,对于每一个元素,概率等于子集中的元素数量除以集合中的元素总数量。
-
蓄水池抽样是否可以用于从有限流中进行抽样?
- 是,只要我们能够迭代流中的元素。
-
我可以使用哈希表预处理从排序数组中查找索引吗?
- 可以,但由于数组已经排序,二分搜索会更有效。
-
蓄水池抽样和蒙特卡罗抽样有什么区别?
- 蓄水池抽样保证每个元素都有相同的概率被选入子集,而蒙特卡罗抽样不保证这一点。