O(1) 时间插入、删除和获取随机元素
难度:中等
维护一个集合插入删除的问题,容易想到用hashSet,但是需要随机返回一个数的话比较麻烦,使用Random随机一个下标,然后循环到这个下标就返回,本以为会TLE,没想到踩线通过。
代码如下:
public class RandomizedSet{
Set<Integer> set;
Random random;
public RandomizedSet() {
this.set = new HashSet();
this.random = new Random();
}
public boolean insert(int val) {
if (set.add(val)){
return true;
}else{
return false;
}
}
public boolean remove(int val) {
if (set.remove(val)){
return true;
}else{
return false;
}
}
public int getRandom() {
int i = random.nextInt(set.size());
int time = 0;
for (Integer integer : set) {
if (time==i){
return integer;
}
time++;
}
//为了方法不报错,实际不会走这里
return -1;
}
}
执行结果:成功
优化:可以将哈希表map设计为:以入参 val 为键,数组下标 loc 为值。
维护一个数组 nums,方便后续随机取值。
维护一个下标idx,记录当前数组位置(也可以认为是数组长度)。
代码如下:
public class InsertDeleteGetrandomO1 {
Map<Integer,Integer> map = new HashMap();
Random random = new Random();
int[] nums = new int[100000];
int idx = 0;
public boolean insert(int val) {
if (map.containsKey(val)) return false;
map.put(val,idx);
nums[idx++] = val;
return true;
}
public boolean remove(int val) {
if (!map.containsKey(val)) return false;
//拿到对应下标
Integer id = map.remove(val);
//将下标的元素更新为数组最末尾的元素(如果本身是最末尾的元素,则会在下次insert被替换)
nums[id] = nums[--idx];
//如果当前元素不是最末尾元素,则需要更新下标。
if (id!=--idx)
map.put(nums[idx],id);
return true;
}
public int getRandom() {
return nums[random.nextInt(map.size())];
}
}