leetcode題目 398. 隨機數索引

題目

給定一個可能含有重複元素的整數數組,要求隨機輸出給定的數字的索引。 您可以假設給定的數字一定存在於數組中。

注意:
數組大小可能非常大。 使用太多額外空間的解決方案將不會通過測試。

示例:

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留下的概率爲:11{1 \over 1}=1
最後2留下的概率爲:12{1 \over 2}*23{2 \over 3}*34{3 \over 4}*45{4 \over 5}*56{5 \over 6}*67{6 \over 7}*78{7 \over 8}*89{8 \over 9}=19{1 \over 9}
最後3留下的概率爲:13{1 \over 3}*34{3 \over 4}*45{4 \over 5}*56{5 \over 6}*67{6 \over 7}*78{7 \over 8}*89{8 \over 9}=19{1 \over 9}(因爲3會覆蓋前面的值,所以前面是否選取不影響後面結果,其餘同理)
最後4留下的概率爲:14{1 \over 4}*45{4 \over 5}*56{5 \over 6}*67{6 \over 7}*78{7 \over 8}*89{8 \over 9}=19{1 \over 9}
最後5留下的概率爲:15{1 \over 5}*56{5 \over 6}*67{6 \over 7}*78{7 \over 8}*89{8 \over 9}=19{1 \over 9}
最後6留下的概率爲:16{1 \over 6}*67{6 \over 7}*78{7 \over 8}*89{8 \over 9}=19{1 \over 9}
最後7留下的概率爲:17{1 \over 7}*78{7 \over 8}*89{8 \over 9}=19{1 \over 9}
最後8留下的概率爲:18{1 \over 8}*89{8 \over 9}=19{1 \over 9}
最後9留下的概率爲:19{1 \over 9}=19{1 \over 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));
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章