题意
同380 - Insert Delete GetRandom O(1),只不过支持重复元素。
思路
pre
我们先考虑还是用unordered_map
+vector
来做,既然支持重复元素,那么我们可以将重复元素穿成一条链,即unordered_map
的结构为unordered_map<int, vector<int>> has
,其中vector存储的为对应在arr里的下标。
insert(val)
:has[val].push_back()
, O(1)getRandom()
:arr[rand() % size]
, O(1)remove(val)
: 取has[val]
对应vector
的最后一个元素的位置pos
,并且将arr[]
最后一个位置lastPos
上的元素x
放到pos
上达到删除的目的,并且需要修改has[x]
的映射关系:我们会发现,我们需要在has[x]
里面先找到vector
里面存储的下标为lastPos
的位置,然后修改成pos
,时间复杂度会上升到 O(n) 。
now
所以,需要修改我们的数据结构。
既然,导致我们时间复杂度上升到
O(n)
的操作是在has[x]
对应的vector
里面去遍历找到对应值为lastPos
对应的位置并修改,那么我们能否直接在arr[]
里面存储lastPos
在has[x]
的vector
里面对应的位置呢?
显然我们可以将arr[]
的数据结构修改为vector<pair<int, int>> arr
。
其中,arr[pos].first
代表当前位置pos
存储的元素值val
,arr[pos].second
代表当前位置存储的元素值val
在has[val]
连接的vector
里面出现的位置。
假设我们依次插入:
1, 2, 1, 1, 4, 4, 3
那么,表示为:
代码
class RandomizedCollection {
private:
unordered_map<int, vector<int>> has;
vector<pair<int, int>> arr;
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) {
auto flag = (has.find(val) == has.end());
has[val].push_back(arr.size());
arr.push_back(make_pair(val, has[val].size() - 1));
return flag;
}
/** Removes a value from the collection. Returns true if the collection contained the specified element. */
bool remove(int val) {
auto flag = (has.find(val) != has.end());
if (flag) {
int pos = has[val].back();
auto last = arr.back();
arr[pos] = last;
has[last.first][last.second] = pos;
has[val].pop_back();
arr.pop_back();
if (has[val].empty()) has.erase(val);
}
return flag;
}
/** Get a random element from the collection. */
int getRandom() {
return arr[rand() % arr.size()].first;
}
};
/**
* 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();
* **/