1. 程式人生 > >[leetcode] 381. Insert Delete GetRandom O(1)

[leetcode] 381. Insert Delete GetRandom O(1)

Design a data structure that supports all following operations in average O(1) time.

Note: Duplicate elements are allowed.
  1. insert(val): Inserts an item val to the collection.
  2. remove(val): Removes an item val from the collection if present.
  3. getRandom: Returns a random element from current collection of elements. The probability of each element being returned is linearly related
     to the number of same value the collection contains.

Example:

// Init an empty collection.
RandomizedCollection collection = new RandomizedCollection();

// Inserts 1 to the collection. Returns true as the collection did not contain 1.
collection.insert(1);

// Inserts another 1 to the collection. Returns false as the collection contained 1. Collection now contains [1,1].
collection.insert(1);

// Inserts 2 to the collection, returns true. Collection now contains [1,1,2].
collection.insert(2);

// getRandom should return 1 with the probability 2/3, and returns 2 with the probability 1/3.
collection.getRandom();

// Removes 1 from the collection, returns true. Collection now contains [1,2].
collection.remove(1);

// getRandom should return 1 and 2 both equally likely.
collection.getRandom();

這道題是設計實現一個<插入、刪除、隨機取>三種操作平均時間複雜度均為O(1)的資料結構,允許出現重複元素,題目難度為Hard。

題目和第380題相關,大家可以先看下第380題(傳送門)。由於存在重複元素,並且各元素隨機取到的概率和元素數量呈線性相關,所以為了滿足隨機取O(1)的時間複雜度,這裡將所有插入的數字均儲存下來。很自然在儲存各元素下標的Hash Table中需要再用vector來儲存所有相同元素的下標。資料儲存形式確定後實現起來就比較簡單了,插入操作沒什麼難度不再贅述;刪除操作只刪除多個相同元素中的一個,這裡將Hash Table中該元素所有下標的最後一個和儲存所有資料的陣列中最後一個元素交換,然後刪除陣列最後一個元素(注意判斷兩者是否相等),其他更新Hash Table的操作不再詳細說明,有了第380題的基礎相信不難理解,如果刪除元素所對應的下標陣列為空則在Hash Table中刪除該元素;隨機取和第380相同,不再詳述。具體程式碼:

class RandomizedCollection {
    vector<int> data;
    unordered_map<int, vector<int>> hash;
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) {
        bool ret = (hash.find(val) == hash.end());
        data.push_back(val);
        hash[val].push_back(data.size()-1);
        return ret;
    }
    
    /** Removes a value from the collection. Returns true if the collection contained the specified element. */
    bool remove(int val) {
        if(hash.find(val) == hash.end()) return false;
        if(data.back() != val) {
            data[hash[val].back()] = data.back();
            hash[data.back()].back() = hash[val].back();
        }
        hash[val].pop_back();
        data.pop_back();
        if(hash[val].empty()) hash.erase(val);
        return true;
    }
    
    /** Get a random element from the collection. */
    int getRandom() {
        return data[rand()%data.size()];
    }
};

/**
 * 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();
 */