Design a data structure that supports insert, delete, getRandom in O(1) with duplicates

07 May, 2020
Design a Data Structure that can support the following operations in O(1) Time Complexity.
insert(x): Inserts x in the data structure. Returns True if x was not present and False if it was already present.remove(x): Removes x from the data structure, if present.getRandom(): Returns any value present in the stream randomly. The probability of each element being returned should be linearly proportional to the number of same valued elements the stream contains.
insert(x): Inserts x in the data structure. Returns True if x was not present and False if it was already present.
remove(x): Removes x from the data structure, if present.
getRandom(): Returns any value present in the stream randomly. The probability of each element being returned should be linearly proportional to the number of same valued elements the stream contains.
Approach: In the previous article, we have already discussed an approach for this kind of data structure. However, the previous data structure worked well only for unique values. In this article, we will design a data structure which can handle duplicate elements also.
The approach used in this article is much similar to the previous approach, but in order to handle the duplicate elements, a map of sets is used to store the indices of the elements present in the dynamic array. Let’s understand every method independently.
insert(int x):Insert x at the end of the dynamic array nums[].Insert the index of x (i.e.) nums.size() – 1 to mp[x]. This map of sets stores all the indices of the element x present in the dynamic array nums[].
Insert x at the end of the dynamic array nums[].Insert the index of x (i.e.) nums.size() – 1 to mp[x]. This map of sets stores all the indices of the element x present in the dynamic array nums[].
Insert x at the end of the dynamic array nums[].
Insert the index of x (i.e.) nums.size() – 1 to mp[x]. This map of sets stores all the indices of the element x present in the dynamic array nums[].
remove(int x):Check if x is present in the stream by mp.count(x). If it is absent, then return False.If x is present, the first element of the set mp[x] is deleted and its value is stored in a variable indexRemoved. Now, if this element (i.e.) indexRemoved is the same as nums.length() – 1 go directly to step 6 because this means that the element is already at the last index and that element is deleted in constant time.If not, then in order to delete this element in constant time, this element is swapped with the last element in the dynamic array. Therefore, delete the value nums.size() – 1 from the mp[nums[nums.size() – 1]] set.Insert the value index into mp[nums[nums.size() – 1]] set.Swap the elements at index nums.size() – 1 and indexRemoved of nums.Delete the last element from nums (Removal from the end from Dynamic Array is constant time operation).If the mp[val] set becomes empty, erase val from mp.Return True
Check if x is present in the stream by mp.count(x). If it is absent, then return False.If x is present, the first element of the set mp[x] is deleted and its value is stored in a variable indexRemoved. Now, if this element (i.e.) indexRemoved is the same as nums.length() – 1 go directly to step 6 because this means that the element is already at the last index and that element is deleted in constant time.If not, then in order to delete this element in constant time, this element is swapped with the last element in the dynamic array. Therefore, delete the value nums.size() – 1 from the mp[nums[nums.size() – 1]] set.Insert the value index into mp[nums[nums.size() – 1]] set.Swap the elements at index nums.size() – 1 and indexRemoved of nums.Delete the last element from nums (Removal from the end from Dynamic Array is constant time operation).If the mp[val] set becomes empty, erase val from mp.Return True
Check if x is present in the stream by mp.count(x). If it is absent, then return False.
If x is present, the first element of the set mp[x] is deleted and its value is stored in a variable indexRemoved. Now, if this element (i.e.) indexRemoved is the same as nums.length() – 1 go directly to step 6 because this means that the element is already at the last index and that element is deleted in constant time.
If not, then in order to delete this element in constant time, this element is swapped with the last element in the dynamic array. Therefore, delete the value nums.size() – 1 from the mp[nums[nums.size() – 1]] set.
Insert the value index into mp[nums[nums.size() – 1]] set.
Swap the elements at index nums.size() – 1 and indexRemoved of nums.
Delete the last element from nums (Removal from the end from Dynamic Array is constant time operation).
If the mp[val] set becomes empty, erase val from mp.
Return True
getRandom():Get a random number between 0 and nums.size() – 1.Return the value present at this index of nums.
Get a random number between 0 and nums.size() – 1.Return the value present at this index of nums.
Get a random number between 0 and nums.size() – 1.
Return the value present at this index of nums.
Below is the implementation of the above approach:
// C++ program to design a data structure// that supports insert, delete,// getRandom in O(1) with duplicates  #include <bits/stdc++.h>  using namespace std;  class Stream {  private:    // Stores all the numbers present    // currently in the stream    vector<int> nums;      // Unordered ensure O(1) operation    unordered_map<int, unordered_set<int> > mp;  public:    // Function to insert values    // in the stream    bool insert(int val)    {        // Inserting val to the end of array        nums.push_back(val);          // Index at which val was inserted        int index = nums.size() - 1;          // Inserting the index inside the        // set mp[val]        mp[val].insert(index);          // Return True if only one val        // is present in the stream        return mp[val].size() == 1;    }      // Function to remove the value    // from the stream    bool remove(int val)    {          // If the value is not present        // in the stream        if (!mp.count(val))            return 0;          // Get the value of the first element        // of the mp[val] and store it        // in a variable named index        int index = *(mp[val].begin());          // Last Index of nums        int lastIndex = nums.size() - 1;          // Erase the index from mp[val] set        mp[val].erase(index);          // If index == lastIndex, then the        // element was already deleted        // from the stream        if (index != lastIndex) {              // Delete the lastIndex from            // mp[nums[lastIndex]] set            mp[nums[lastIndex]].erase(lastIndex);              // Insert index into mp[nums[lastIndex]] set            mp[nums[lastIndex]].insert(index);              // Swap the values at index and lastIndex            swap(nums[index], nums[lastIndex]);        }          // Delete the last element from nums        // This operation is O(1) operation        nums.pop_back();          // If the size of mp[val] is 0,        // val is absent from the stream        // and hence it is removed        if (mp[val].size() == 0)            mp.erase(val);        return 1;    }      // Function to get a random number    // from the stream of data    int getRandom()    {          // Get any random index from 0 to        // nums.length() - 1        int randomIndex = rand() % nums.size();  // Return the value at that index        return nums[randomIndex];     }};  // Driver codeint main(){      Stream myStream;      cout << myStream.insert(5) << endl;    cout << myStream.insert(6) << endl;    cout << myStream.insert(5) << endl;    cout << myStream.remove(6) << endl;    cout << myStream.remove(6) << endl;    cout << myStream.getRandom() << endl;      return 0;}
1
1
0
1
0
5

Advanced Data Structure
Analysis
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Agents in Artificial Intelligence
Decision Tree Introduction with example
Segment Tree | Set 1 (Sum of given range)
Count of strings whose prefix match with the given string to a given length k
Binary Indexed Tree or Fenwick Tree
Analysis of Algorithms | Set 1 (Asymptotic Analysis)
Understanding Time Complexity with Simple Examples
Time Complexity and Space Complexity
Practice Questions on Time Complexity Analysis
Analysis of Algorithms | Set 3 (Asymptotic Notations)