題目鏈接:https://leetcode-cn.com/problems/insert-delete-getrandom-o1/
題目描述
設計一個支持在平均 時間複雜度 O(1) 下,執行以下操作的數據結構。
- insert(val):當元素 val 不存在時,向集合中插入該項。
- remove(val):元素 val 存在時,從集合中移除該項。
- getRandom:隨機返回現有集合中的一項。每個元素應該有相同的概率被返回。
示例:
// 初始化一個空的集合。
RandomizedSet randomSet = new RandomizedSet();
// 向集合中插入 1 。返回 true 表示 1 被成功地插入。
randomSet.insert(1);
// 返回 false ,表示集合中不存在 2 。
randomSet.remove(2);
// 向集合中插入 2 。返回 true 。集合現在包含 [1,2] 。
randomSet.insert(2);
// getRandom 應隨機返回 1 或 2 。
randomSet.getRandom();
// 從集合中移除 1 ,返回 true 。集合現在包含 [2] 。
randomSet.remove(1);
// 2 已在集合中,所以返回 false 。
randomSet.insert(2);
// 由於 2 是集合中唯一的數字,getRandom 總是返回 2 。
randomSet.getRandom();
思路
- 使用C++實現的問題就出在如何實現 getRandom() 功能上,需要每個元素返回的概率相同且要求 O(1) 時間複雜度。
- 由於時間複雜度平均要達到 O(1),因此需要額外建立一個數組來記錄插入的數值,哈希表存的是數組的下標,這樣返回一個隨機值就能夠達到 O(1) 的效率。
- 插入元素實現簡單,直接更新數組和哈希表即可。但如何在 O(1) 時間刪除元素?哈希表刪除元素自然是 O(1) 時間,但問題是如何 O(1) 時間刪除數組的元素?
- 這個問題也不難解決,因爲哈希表存着數組的下標。我們可以通過哈希表找到當前待刪元素的下標,然後和數組的末尾元素交換,執行 pop_back 即可。這樣就解決了數組在 O(1) 時間刪除元素的問題。
代碼如下:
class RandomizedSet {
unordered_map<int, int> dict;
vector<int> list;
public:
/** Initialize your data structure here. */
RandomizedSet() {
srand(time(0));
}
/** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
bool insert(int val) {
if(dict.find(val) != dict.end()) return false;
list.push_back(val);
dict[val] = list.size()-1;
return true;
}
/** Removes a value from the set. Returns true if the set contained the specified element. */
bool remove(int val) {
if(dict.find(val) == dict.end()) return false;
dict[list.back()] = dict[val];
swap(list.back(), list[dict[val]]);
list.pop_back();
dict.erase(val);
return true;
}
/** Get a random element from the set. */
int getRandom() {
int pos = list.empty() ? 0 : rand() % list.size();
return list[pos];
}
};
/**
* 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();
*/