###### tags: `Leetcode` `medium` `design` `hash` `python` `c++` # 380. Insert Delete GetRandom O(1) ## [題目連結:] https://leetcode.com/problems/insert-delete-getrandom-o1/ ## 題目: 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. * There will be at least one element in the data structure when getRandom is called. **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. ``` ## 解題想法: * 此題為,實作一個資料結構,能夠加入元素(insert)、刪除元素(remove)以及可以從元素裡面隨機挑選一個元素出來(getRandom),並且所有操作都必須要在 O(1) 的時間完成。 * 分析: time * insert: * list: O(1) * dict: O(1) * remove: * list: O(n) * **dict: O(1)** * getRandom: * **list: O(1)** * dict: O(n) * 實作要點: * init: 初始定義 * self.list * self.dict * bool insert(val): * 同時將val加入於self.list、self.dict中 * 用self.dict找是否有出現重複:O(1) * 對於self.dict * key為val * self.dict[key]為在self.list中的位置 * bool remove(val): * 對於上述分析: * 用list:O(n) * 用dict:O(1) * **所以先交換list內容於list[-1]** * **再刪除list[-1]這樣才O(1)** * 作法: * **Step1**:先紀錄self.list[-1]的元素 * last_val=self.list[-1] * **Step2**:紀錄要刪除的val於self.dict之中,所存的pos * cur_pos=self.dict[val] * **Step3**: 將list[-1]的值移到list[cur_pos] * **Step4**: 將dict[last]的內容改成cur_pos * **Step5**: * 刪除self.dict[val] * 刪除self.list[-1] * int getRandom: * 用list: O(1) * 用dict: O(n) * 所以直接random.choice(self.list)即可 (for python : import random) ## Python: ``` python= import random class RandomizedSet(object): def __init__(self): self.list=[] self.dict={} def insert(self, val): """ :type val: int :rtype: bool """ #用dict找是否有出現重複:O(1) if val in self.dict: return False self.dict[val]=len(self.list) #key為val dict[key]為list中所在位置 self.list.append(val) return True def remove(self, val): """ :type val: int :rtype: bool """ #用list:O(n) 用dict:O(1) #所以交換list內容於list[-1] #刪除list[-1]這樣才O(1) if val not in self.dict: return False last_val=self.list[-1] cur_pos=self.dict[val] #將list[-1]的值移到list[cur_pos] self.list[cur_pos]=last_val #將dict[last]的內容改成cur_pos self.dict[last_val]=cur_pos del self.dict[val] del self.list[-1] return True def getRandom(self): """ :rtype: int """ #用list:O(1) 用dict:O(n) return random.choice(self.list) result = RandomizedSet() r1 = result.insert(1) r2 = result.remove(2) r3 = result.insert(2) r4 = result.getRandom() r5 = result.remove(1) r6 = result.insert(2) r7 = result.getRandom() print(r1,r2,r3,r4,r5,r6,r7) ``` ## C++: * unordered_map: * 刪除key用 **.erase(key)** * return隨機數 * 數組[ **rand()** % 數組.size() ] ``` cpp= class RandomizedSet { public: RandomizedSet() { } //list、dict:O(1) bool insert(int val) { if (dict.find(val)!=dict.end()) //same as dict.count(val) return false; dict[val]=list.size(); list.push_back(val); return true; } //dict:O(1) bool remove(int val) { if (!dict.count(val)) return false; int last_val=list.back(); int cur_pos=dict[val]; list[cur_pos]=last_val; dict[last_val]=cur_pos; //delete val info in dict、list list.pop_back(); //pop last item dict.erase(val); return true; } int getRandom() { return list[rand() % list.size()]; } private: vector<int> list; unordered_map<int,int> dict; }; /** * 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(); */ ```