題目
給定一個可能含有重複元素的整數數組,要求隨機輸出給定的數字的索引。 您可以假設給定的數字一定存在於數組中。
注意:
數組大小可能非常大。 使用太多額外空間的解決方案將不會通過測試。
示例:
int[] nums = new int[] {1,2,3,3,3};
Solution solution = new Solution(nums);
// pick(3) 應該返回索引 2,3 或者 4。每個索引的返回概率應該相等。
solution.pick(3);
// pick(1) 應該返回 0。因爲只有nums[0]等於1。
solution.pick(1);
思路一(hashmap)
初始化Solution對象時,傳入nums數組,我們在Solution類中維護一個HashMap私有變量,鍵值對爲<Integer,List<Integer>>,key代表元素的值,value是List類型,用來存放索引,然後調用pick的時候隨機返回對應key的某個索引即可。
思路一代碼
//請注意,這裏是爲了本地方便,所以類的命名不是Solution
public class problem398 {
private Map<Integer,List<Integer>> hashmap=new HashMap<Integer,List<Integer>>();
private Random ran=new Random();
public problem398(int[] nums) {
hashmap.clear();
for(int i=0;i<nums.length;i++){
//檢查當前數值是否放入map
if(!hashmap.containsKey(nums[i]))
hashmap.put(nums[i], new ArrayList());
hashmap.get(nums[i]).add(i);
}
}
public int pick(int target) {
if(hashmap.containsKey(target)){
int size=hashmap.get(target).size();
return hashmap.get(target).get(ran.nextInt(size));
}else{
return -1;
}
}
public static void main(String[] args) {
}
}
思路二(流水線抽樣)
比如我們要在1,2,3,4,5,6,7,8,9中隨意選出一個數,要求每個數的選取概率相同(這裏你可能會說,我直接隨便選一個不久ok了,但要注意題目給的是一個大數組,我們在遍歷上個元素時,並不知道下個數是否需要被選取,這裏我們把所有可以選取的數拿出來方便講解)。
遍歷第1個數:以1/1的概率留下這個數。
遍歷第2個數:以1/2的概率留下這個數(覆蓋上個數)。
遍歷第3個數:以1/3的概率留下這個數(覆蓋上個數)。
遍歷第4個數:以1/4的概率留下這個數(覆蓋上個數)。
遍歷第5個數:以1/5的概率留下這個數(覆蓋上個數)。
遍歷第6個數:以1/6的概率留下這個數(覆蓋上個數)。
遍歷第7個數:以1/7的概率留下這個數(覆蓋上個數)。
遍歷第8個數:以1/8的概率留下這個數(覆蓋上個數)。
遍歷第9個數:以1/9的概率留下這個數(覆蓋上個數)。
那麼我們來計算對應的概率:
最後1留下的概率爲:=1
最後2留下的概率爲:*******=
最後3留下的概率爲:******=(因爲3會覆蓋前面的值,所以前面是否選取不影響後面結果,其餘同理)
最後4留下的概率爲:*****=
最後5留下的概率爲:****=
最後6留下的概率爲:***=
最後7留下的概率爲:**=
最後8留下的概率爲:*=
最後9留下的概率爲:=
思路二代碼
public class problem398_2 {
private int[] nums;
private Random ran=new Random();
public problem398_2(int[] nums) {
this.nums=nums;
}
public int pick(int target) {
int index=0;
int n=0;
for(int i=0;i<nums.length;i++){
if(nums[i]==target){
n++;
//以1/n的機率保留index
if(ran.nextInt(n)==0)
index = i;
}
}
return index;
}
public static void main(String[] args) {
int[] nums={1,2,3,3,3};
problem398_2 pro=new problem398_2(nums);
System.out.println(pro.pick(3));
}
}