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私有变量,键值对为>,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 1 {1 \over 1} 11=1
最后2留下的概率为: 1 2 {1 \over 2} 21* 2 3 {2 \over 3} 32* 3 4 {3 \over 4} 43* 4 5 {4 \over 5} 54* 5 6 {5 \over 6} 65* 6 7 {6 \over 7} 76* 7 8 {7 \over 8} 87* 8 9 {8 \over 9} 98= 1 9 {1 \over 9} 91
最后3留下的概率为: 1 3 {1 \over 3} 31* 3 4 {3 \over 4} 43* 4 5 {4 \over 5} 54* 5 6 {5 \over 6} 65* 6 7 {6 \over 7} 76* 7 8 {7 \over 8} 87* 8 9 {8 \over 9} 98= 1 9 {1 \over 9} 91(因为3会覆盖前面的值,所以前面是否选取不影响后面结果,其余同理)
最后4留下的概率为: 1 4 {1 \over 4} 41* 4 5 {4 \over 5} 54* 5 6 {5 \over 6} 65* 6 7 {6 \over 7} 76* 7 8 {7 \over 8} 87* 8 9 {8 \over 9} 98= 1 9 {1 \over 9} 91
最后5留下的概率为: 1 5 {1 \over 5} 51* 5 6 {5 \over 6} 65* 6 7 {6 \over 7} 76* 7 8 {7 \over 8} 87* 8 9 {8 \over 9} 98= 1 9 {1 \over 9} 91
最后6留下的概率为: 1 6 {1 \over 6} 61* 6 7 {6 \over 7} 76* 7 8 {7 \over 8} 87* 8 9 {8 \over 9} 98= 1 9 {1 \over 9} 91
最后7留下的概率为: 1 7 {1 \over 7} 71* 7 8 {7 \over 8} 87* 8 9 {8 \over 9} 98= 1 9 {1 \over 9} 91
最后8留下的概率为: 1 8 {1 \over 8} 81* 8 9 {8 \over 9} 98= 1 9 {1 \over 9} 91
最后9留下的概率为: 1 9 {1 \over 9} 91= 1 9 {1 \over 9} 91

思路二代码

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));
	}
}

你可能感兴趣的:(leetcode刷题,数理相关)