Java&C++题解与拓展——leetcode380.O(1)时间插入、删除和获取随机元素【unordered_map学习与使用】

每日一题做题记录,参考官方和三叶的题解

题目要求

image.png

思路:哈希表+数组

O ( 1 ) O(1) O(1)复杂度的插入和删除很明显是用哈希表,但是取随机数的话用数组返回随机下标比较方便,所以就同时维护一个哈希表和一个数组,哈希表存着数组内元素及其对应下标。

直接根据数据范围( 2 ∗ 1 0 5 2*10^5 2105)申请一个固定大小的数组,为了方便取随机数,要维护数组的「 i d x idx idx个元素都不空」,所以在删除元素时要把当前最后一个元素 n u m s [ i d x ] nums[idx] nums[idx]放到被删除的元素处 n u m s [ d e l ] nums[del] nums[del]补空。
此时随机操作直接在 [ 0 , i d x ] [0,idx] [0,idx]内取随机值作为下标,返回数组内对应值即可。

而对于插入操作,则判断是否存在于哈希表中,然后同时维护哈希表和数组即可。

Java

class RandomizedSet {
    static int[] nums = new int[200001];
    Random random = new Random();
    Map<Integer, Integer> map = new HashMap<>(); //数组下标与值
    int idx = -1;
    public RandomizedSet() {}
    
    public boolean insert(int val) {
        if(map.containsKey(val))
            return false;
        nums[++idx] = val;
        map.put(val, idx);
        return true;
    }
    
    public boolean remove(int val) {
        if(!map.containsKey(val))
            return false;
        int del = map.remove(val);
        if(del != idx) //是否删除最后一个元素
            map.put(nums[idx], del);
        nums[del] = nums[idx--]; //补空,保证前面都是满的
        return true;
    }
    
    public int getRandom() {
        return nums[random.nextInt(idx + 1)];
    }
}
  • 时间复杂度:所有操作均 O ( 1 ) O(1) O(1)
  • 空间复杂度: O ( n ) O(n) O(n),数组和哈希表均为 O ( n ) O(n) O(n)

C++

class RandomizedSet {
private:
    int nums[200001];
    unordered_map<int, int> map;
    int idx = -1;
public:
    RandomizedSet() {}
    
    bool insert(int val) {
        if(map.count(val))
            return false;
        nums[++idx] = val;
        map[val] = idx;
        return true;
    }
    
    bool remove(int val) {
        if(!map.count(val))
            return false;
        int del = map[val];
        map.erase(val);
        if(del != idx) //是否删除最后一个元素
            map[nums[idx]] = del;
        nums[del] = nums[idx--]; //补空,保证前面都是满的
        return true;
    }
    
    int getRandom() {
        return nums[rand() % (idx+1)];
    }
};
  • 时间复杂度:所有操作均 O ( 1 ) O(1) O(1)
  • 空间复杂度: O ( n ) O(n) O(n),数组和哈希表均为 O ( n ) O(n) O(n)

STL unordered_map

  • 学习参考链接
  • 即为一个无序的map容器,以键值对形式存在,键不能相等。
方法功能备注
e m p l a c e ( ) emplace() emplace()插入元素,效率高于insert()
c o u n t ( k e y ) count(key) count(key)查找键值为 k e y key key的键值对个数上文使用判断是否存在键值为 k e y key key的元素
f i n d ( k e y ) find(key) find(key)查找键值为 k e y key key的键值对,返回相应正向迭代器,若未找到则返回最后一个键值对之后位置的迭代器【即 e n d ( ) end() end()方法的返回值】上文判断处也可换为此方法,即map.find(key) == map.end()则不存在,反之则存在
e r a s e ( k e y ) erase(key) erase(key)删除以 k e y key key为键的键值对

总结

想到了用哈希表,但是没有想到额外维护一个前面值均不空的数组来进行随机数的寻找。

C++的这几个容器的方法都差不多,但是定义不同存在细节差异,还是要注意区分。还有,在这里写习惯了,编译器里很容易忘掉要include相应内容……


欢迎指正与讨论!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值