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,记录当前数组位置(也可以认为是数组长度)。
- 当insert操作时,判断map中是否存在,若存在,则返回false,若不存在,则将val与idx以键值对的形式存入map中,再在数组下标idx下记录val。
- 当remove操作时,判断map中是否存在,若不存在,则返回false,若存在,则将map中对应的val删除,并获取map对应的value(即为对应的数组下标,记为id),将当前数组最末尾的元素移动到下标为id的位置,并更新map中对应元素的下标。
代码如下:
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())];
}
}