380. Insert Delete GetRandom O(1)

设计一个数据结构,插入,删除,随机获取其中一个数值操作都是O(1)的时间复杂度。

思考:首先从基本的数据结构开始思考,数组、链表、hash表,map,set等等,发现单一的数据结构是无法支持那些操作都是O(1)的时间复杂度。进而再考虑叠加数据结构的方法。vector + unordered_map 是 不错的叠加方法,用数组存放具体数据,用hash表存放数据的索引。之后再查找时,可以通过索引,再在数组中找到元素。插入时,在vector中插入数据,同时把索引存放到hash里面。插入操作需要注意的是,如果数组本身有对象(v[i] = value)可以直接存放就直接存放,如果没有,在创建对象插入(push_back).删除时,从hash中找到索引,再在vector中删除,删除时考虑到效率问题,可以直接将最后一个元素搬移到需要删除的位置,并更新vector最后可再插入元素位置。

解法:

class RandomizedSet {
public:
    /** Initialize your data structure here. */
    RandomizedSet() {
        len = 0;
    }
    
    /** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
    bool insert(int val) {
        // 这里一定要判断不能等于-1,因为数组只有一个元素时,对它做删除后,该元素位置会更新为-1
        if (idx.count(val) > 0 && data[idx[val]] != -1) { return false; }
        
        // 注意这里要比较当前使用的大小和vector的实际大小
        if (len == data.size()) {
            data.push_back(val);
        } else {
            data[len] = val;
        }
        
        idx[val] = len++;
        return true;
    }
    
    /** Removes a value from the set. Returns true if the set contained the specified element. */
    bool remove(int val) {
        if (idx.count(val) == 0) { return false; }
        
        int pos = idx[val];
        // 把最后一个元素挪到要删除位置,而不是后面的元素整体向前移动,是为了性能考虑
        data[pos] = data[--len]; 
        // 之后把最后位置的数据改为-1,表示这里没有数据
        data[len] = -1;
        // 这个不能忘记删除元素
        idx.erase(val);
        idx[data[pos]] = pos;
        return true;
    }
    
    /** Get a random element from the set. */
    int getRandom() {
        // 不要忘记len是0的情况
        if (len == 0) { return -1; }
        int pos = rand() % len;
        return data[pos];
    }
    
public:
    // 值和索引的映射关系
    unordered_map<int, int> idx;
    // 具体存放数据
    vector<int> data;
    int len;
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值