题目:
Implement the RandomizedSet
class:
RandomizedSet()
Initializes theRandomizedSet
object.bool insert(int val)
Inserts an itemval
into the set if not present. Returnstrue
if the item was not present,false
otherwise.bool remove(int val)
Removes an itemval
from the set if present. Returnstrue
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 toinsert
,remove
, andgetRandom
. - 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();
*/