398—Random Pick Index
Given an array of integers with possible duplicates, randomly output the index of a given target number. You can assume that the given target number must exist in the array.
Note:
The array size can be very large. Solution that uses too much extra space will not pass the judge.
Example 1:
int[] nums = new int[] {1,2,3,3,3};
Solution solution = new Solution(nums);
// pick(3) should return either index 2, 3, or 4 randomly. Each index should have equal probability of returning.
solution.pick(3);
// pick(1) should return 0. Since in the array only nums[0] is equal to 1.
solution.pick(1);
C代码:
#include <stdlib.h>
typedef struct {
int *nums;
int numsSize;
} Solution;
Solution* solutionCreate(int* nums, int numsSize) {
Solution *obj = (Solution*) malloc(sizeof(Solution));
obj->nums = nums;
obj->numsSize = numsSize;
return obj;
}
int solutionPick(Solution* obj, int target) {
// 方法一:直接把nums中所有等于target的index记录在数组中,再随机.
// int result[1000]={0}; //存放nums中等于target的index
// int count = 0; //nums中等于下标的个数
// for(int i = 0; i< obj->numsSize; i++) {
// if(obj->nums[i] == target) {
// result[count++] = i;
// }
// }
// if (count == 1) {
// return result[0];
// }
// return result[rand()%count];
// 方法二: 水塘抽样(Reservoir Sampling)
int count = 0;
int result = -1;
int randomNum = -1;
for(int i = 0; i<obj->numsSize;i++) {
if(obj->nums[i] != target) continue;
if(count == 0){
result = i;
count++;
}else {
count++;
randomNum = rand()%count;
if(randomNum < 1) {
result = i;
}
}
}
return result;
}
void solutionFree(Solution* obj) {
free(obj);
}
Complexity Analysis:
Time complexity : O(n).
Space complexity : O(1).
思路:
- 第一种思路比较简单直接用数组记录,再随机.
- 第二种思路是水塘取样(Reservoir Sampling) 问题:
参考: https://www.cnblogs.com/snowInPluto/p/5996269.html
int* reservoirSampling(int *nums, int numsSize) {
int reservoirSize = 5;
static int reservoir[5];
int i = 0;
//先把水塘装满
for (i = 0; i < reservoirSize;i++)
reservoir[i] = nums[i];
int randomNum;
for(i = reservoirSize;i < numsSize;i++) {
randomNum = rand()%(i+1);
if(randomNum < reservoirSize) {
reservoir[randomNum] = nums[i];
}
}
return reservoir;
}
本题目相当于Sample 为nums中等于target的值的集合, 样本容量(reservoirSize)为1. 事实上保证第k个样本来时,它留下概率为reservoirSize/k即可.