题目要求
设计一个结构,实现三个功能:
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--;
}
}