【蓄水池抽样】算法知识点学习自宫水三叶大佬,记录一下。
方法一:哈希表
如果不考虑数组的大小,我们可以在构造函数中,用一个哈希表 map 记录 nums 中相同元素的下标。
对于pick 操作,我们可以从 map 中取出target 对应的下标列表,然后随机选择其中一个下标并返回。
class Solution {
Map<Integer, List<Integer>> map;
Random random;
public Solution(int[] nums) {
map= new HashMap<Integer, List<Integer>>();
random = new Random();
for (int i = 0; i < nums.length; ++i) {
map.putIfAbsent(nums[i], new ArrayList<Integer>());
map.get(nums[i]).add(i);
}
}
public int pick(int target) {
List<Integer> list= map.get(target);
return list.get(random.nextInt(list.size()));
}
}
解法二:蓄水池抽样(不定长数据流)
若 nums 并不是在初始化时完全给出,而是持续以「流」的形式给出,且数据流的很长,不便进行预处理的话,我们只能使用「蓄水池抽样」的方式求解。
class Solution {
int nums[];
Random random=new Random();
public Solution(int[] _nums) {
nums=_nums;
}
public int pick(int target) {
int ans=0;
int k=0;
for(int i=0;i<nums.length;i++){
if(nums[i]==target){
k++;
if(random.nextInt(k)==0){
ans=i;
}
}
}
return ans;
}
}
解法1:模拟
由于链表长度只有 10^4,因此可以在初始化时遍历整条链表,将所有的链表值预处理到一个数组内。
在查询时随机一个下标,并将数组中对应下标内容返回出去。
class Solution {
List<Integer> list = new ArrayList<>();
Random random = new Random(20220116);
public Solution(ListNode head) {
while (head != null) {
list.add(head.val);
head = head.next;
}
}
public int getRandom() {
int idx = random.nextInt(list.size());
return list.get(idx);
}
}
解法2:蓄水池抽样
class Solution {
ListNode head;
Random random=new Random();
public Solution(ListNode _head) {
head=_head;
}
public int getRandom() {
int ans=0;
int k=0;
ListNode cur=head;
while(cur!=null){
k++;
if(random.nextInt(k)==0){
ans=cur.val;
}
cur=cur.next;
}
return ans;
}
}