双散列表实现随机概率返回

题目要求

设计一个结构,实现三个功能:
1.add();
将某个String添加到该结构中,做到不重复添加。
2.getRandom();
严格等概率随机返回结构中的任何一个key。
3.delete();
要求以上三个方法的时间复杂度全部为O(1)。

思路分析

1.add()
添加String,并且要求不重复。不重复?O(1)?想到什么?散列表。
2.getRandom()
严格等概率随机返回,相当于要求随机返回散列表中的一个key。首先要知道,散列函数的散列区间并不是严格等概率分布的,要想做到严格等概率分布,怎么实现?
严格等概率分布,相当于要求统计出到底有多少个key,然后用Math.random函数就能实现严格随机。如果统计有多少个key?如果遍历key。时间复杂度就不是1了。怎么实现1?可以用map实现,value依次加1,value对应的就是统计多少个key。但是,等我们通过Math.random函数求出随机的value时,如何找到对应的key?此时,可以考虑用双散列表实现。两个散列表的key和value依次对调
map1保存key-value(String,int)
map2保存value-key(int,String)
用map1保证key不会重复,然后用map2实现等概率随机。
3.delete()
删除方法,给定一个String,删除掉。
不过,有一个问题,等我们删除掉一个时,map中间就会出现一个空洞,此时再调用第二部的随机方法,就会出现问题。
因此,删除方法要能填补中间的空洞。可以先把最后一个复制到空洞处,然后删除最后一个。
map1中,把最后一个的value改成要删除的那个,此时最后一个和要删除的value相同,然后删除。
map2中,把要删除的num的value替换掉,然后删除最后一个。
最后。size–。

代码

import java.util.HashMap;

public class RandomPool {

    private HashMap<String,Integer> map1;
    private HashMap<Integer,String> map2;
    private int size;

    public RandomPool(){
        map1=new HashMap<>();
        map2=new HashMap<>();
        size=0;
    }

    public void add(String str){
        map1.put(str,size);
        map2.put(size,str);
        size++;
    }

    public String getRandom(){
        if(size==0){
            return null;
        }
        return map2.get((int)(Math.random()*size));
    }

    public void delete(String string){
        //获取要删除的num
        int num=map1.get(string);
        //获取最后一个
        String last = map2.get(size);
        //把最后一个复制到num的位置,此时有两个num
        map1.put(last,num);
        //删除string
        map1.remove(string);
        //替换到num位置的string,此时有两个last
        map2.put(num,last);
        //删除掉最后一个
        map2.remove(size);
        size--;
    }
}
上一篇:面试掉了,记录学习总结


下一篇:List<Map<String,Object>> list = new ArrayList<Map<String,Object>>();