380. Insert Delete GetRandom O(1)

题目:

Implement the RandomizedSet class:

  • RandomizedSet() Initializes the RandomizedSet object.
  • bool insert(int val) Inserts an item val into the set if not present. Returns true if the item was not present, false otherwise.
  • bool remove(int val) Removes an item val from the set if present. Returns true if the item was present, false otherwise.
  • int getRandom() Returns a random element from the current set of elements (it's guaranteed that at least one element exists when this method is called). Each element must have the same probability of being returned.

You must implement the functions of the class such that each function works in average O(1) time complexity.

Example 1:

Input
["RandomizedSet", "insert", "remove", "insert", "getRandom", "remove", "insert", "getRandom"]
[[], [1], [2], [2], [], [1], [2], []]
Output
[null, true, false, true, 2, true, false, 2]

Explanation
RandomizedSet randomizedSet = new RandomizedSet();
randomizedSet.insert(1); // Inserts 1 to the set. Returns true as 1 was inserted successfully.
randomizedSet.remove(2); // Returns false as 2 does not exist in the set.
randomizedSet.insert(2); // Inserts 2 to the set, returns true. Set now contains [1,2].
randomizedSet.getRandom(); // getRandom() should return either 1 or 2 randomly.
randomizedSet.remove(1); // Removes 1 from the set, returns true. Set now contains [2].
randomizedSet.insert(2); // 2 was already in the set, so return false.
randomizedSet.getRandom(); // Since 2 is the only number in the set, getRandom() will always return 2.

Constraints:

  • -231 <= val <= 231 - 1
  • At most 2 * 105 calls will be made to insertremove, and getRandom.
  • There will be at least one element in the data structure when getRandom is called.

思路:

想要O(1)肯定自然想起哈希表,但是这里一个哈希表是无法满足的,因为无论是std::advance还是std::next都只能做到O(n)去随机获取哈希表内容,因此我们用两个哈希表。一个<int, int>记录送进来的value和它对应的index,这个index就是哈希表的大小,比如insert了{2, 3,5},则哈希表中{{2, 1}, {3, 2}, {5, 3}};而另一个哈希表正好相反,<int, int>记录index和value。将前后两个哈希表命名为record1和record2,这里我们称呼为表一和表二。insert函数比较简单,如果表1有则直接返回false,没有则在表一加入,index为表二的长度即可,之后更新表二。remove首先如果不存在则返回false,之后我这里分了两种情况,如果是删除的本来就是最后加进去的那个数,即删除的那个数在表一的值是表一的size,那就直接删除表一中的这个数和表二中的相关index即可;如果不是,那么就用最后加进去的数去替代被删除数对应index所对应的值,这里有点点绕但是举个例子应该就很容易明白:假设表一{{1, 1}, {2, 2}, {3, 3}, {4, 5}},表二对应的{{1, 1}, {2, 2}, {3, 3}, {5, 4}},这里想要删除2,那么在表一里就应该用最后加进去的4去顶替2,同时删掉最后加进去的<key, value>,所以表一变为{{1, 1}, {4, 2}, {3, 3}},相应的,更新表二变为{{1, 1}, {2, 4}, {3, 3}},这里只要细心捋一下即可。之后getRandom只要随机取表二中的index,返回对应值即可。

代码:

class RandomizedSet {
public:
    RandomizedSet() {

    }

    bool insert(int val) {
        if (record1.count(val))
            return false;
        record1[val] = record1.size() + 1;
        record2[record2.size()] = val;
        return true;
    }

    bool remove(int val) {
        if (!record1.count(val))
            return false;
        if (record1[val] == record1.size()) {
            int index = record1[val];
            record1.erase(val);
            record2.erase(index);
            return true;
        }
        int lastval = record2[record2.size()];
        int index = record1[val];
        record2.erase(record1.size());
        record1.erase(val);
        record1.erase(lastval);
        record1[lastval] = index;
        record2[index] = lastval;
        return true;
    }

    int getRandom() {
        return record2[rand() % record2.size() + 1];
    }
private:
    unordered_map<int, int> record1;
    unordered_map<int, int> record2;
};

/**
 * Your RandomizedSet object will be instantiated and called as such:
 * RandomizedSet* obj = new RandomizedSet();
 * bool param_1 = obj->insert(val);
 * bool param_2 = obj->remove(val);
 * int param_3 = obj->getRandom();
 */

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值