@[toc](380. Insert Delete GetRandom O(1))
Design a data structure that supports all following operations in average O(1) time.
insert(val): Inserts an item val to the set if not already present.
remove(val): Removes an item val from the set if present.
getRandom: Returns a random element from current set of elements. Each element must have the same probability of being returned.
Example:
// Init an empty set.
RandomizedSet randomSet = new RandomizedSet();
// Inserts 1 to the set. Returns true as 1 was inserted successfully.
randomSet.insert(1);
// Returns false as 2 does not exist in the set.
randomSet.remove(2);
// Inserts 2 to the set, returns true. Set now contains [1,2].
randomSet.insert(2);
// getRandom should return either 1 or 2 randomly.
randomSet.getRandom();
// Removes 1 from the set, returns true. Set now contains [2].
randomSet.remove(1);
// 2 was already in the set, so return false.
randomSet.insert(2);
// Since 2 is the only number in the set, getRandom always return 2.
randomSet.getRandom();
方法1:
思路:
作为380题的follow up,现在允许duplicate,但仍然要在O(1)时间内完成所有操作。此时hashmap里面必须存储着该值的所有index。
insert:将num 放入数组的最后一个,并且在hash中加入这个新index。判断此时hash这一个值有几个index,一个则返回true,多余一个返回false。
remove:先查找hash,如果不存在返回false。如果存在,在hash中找到这个值对应着的某一个坐标, 这是我们打算删除的数字。首先把这个index从hash 里去掉,然后把这个数与vector里的最后一个数交换位置,这个index要转交给接替它的数字:把接替者的坐标集里加入它的新坐标,删掉旧坐标(末位)。
random:在当前vector中随便选一个位置,选中的概率与数字出现次数成正比。
易错点
- 这里每个坐标集不能用heap或者set,因为会变成logn的复杂度,要用unordered_set
- comment 标注的位置:这里要先insert再erase,因为如果index = nums.size() - 1,val = last,翻过来会导致division by zero的错误
class RandomizedCollection {
public:
/** Initialize your data structure here. */
RandomizedCollection() {
}
/** Inserts a value to the collection. Returns true if the collection did not already contain the specified element. */
bool insert(int val) {
hash[val].insert(nums.size());
nums.push_back(val);
if (hash[val].size() == 1) return true;
return false;
}
/** Removes a value from the collection. Returns true if the collection contained the specified element. */
bool remove(int val) {
if (hash[val].empty()) return false;
int index = *hash[val].begin();
hash[val].erase(index);
int last = nums.back();
// 这里要先insert再erase,因为如果index = nums.size() - 1,val = last,翻过来会导致division by zero的错误
hash[last].insert(index);
hash[last].erase(nums.size() - 1);
nums[index] = last;
nums.pop_back();
return true;
}
/** Get a random element from the collection. */
int getRandom() {
return nums[rand() % nums.size()];
}
private:
vector<int> nums;
unordered_map<int, unordered_set<int>> hash;
};
/**
* Your RandomizedCollection object will be instantiated and called as such:
* RandomizedCollection* obj = new RandomizedCollection();
* bool param_1 = obj->insert(val);
* bool param_2 = obj->remove(val);
* int param_3 = obj->getRandom();
*/
方法2:
huahua:http://zxi.mytechroad.com/blog/hashtable/leetcode-381-insert-delete-getrandom-o1-duplicates-allowed/
思路:
把vector里面的存储值变成pair<int, int>的形式,第二个值可以回查在hash里index vector中的值。