Skip to content
geeksforgeeks
  • Tutorials
    • Python
    • Java
    • Data Structures & Algorithms
    • ML & Data Science
    • Interview Corner
    • Programming Languages
    • Web Development
    • CS Subjects
    • DevOps And Linux
    • School Learning
    • Practice Coding Problems
  • Courses
    • DSA to Development
    • Get IBM Certification
    • Newly Launched!
      • Master Django Framework
      • Become AWS Certified
    • For Working Professionals
      • Interview 101: DSA & System Design
      • Data Science Training Program
      • JAVA Backend Development (Live)
      • DevOps Engineering (LIVE)
      • Data Structures & Algorithms in Python
    • For Students
      • Placement Preparation Course
      • Data Science (Live)
      • Data Structure & Algorithm-Self Paced (C++/JAVA)
      • Master Competitive Programming (Live)
      • Full Stack Development with React & Node JS (Live)
    • Full Stack Development
    • Data Science Program
    • All Courses
  • DSA
  • Algorithms
  • Analysis of Algorithms
  • Sorting
  • Searching
  • Greedy
  • Recursion
  • Backtracking
  • Dynamic Programming
  • Divide and Conquer
  • Geometric Algorithms
  • Mathematical Algorithms
  • Pattern Searching
  • Bitwise Algorithms
  • Branch & Bound
  • Randomized Algorithms
Open In App
Next Article:
Design a data structure that supports insert, delete, getRandom in O(1) with duplicates
Next article icon

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

Last Updated : 24 Jan, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

Design a Data Structure that can support the following operations in O(1) Time Complexity.

  1. insert(x): Inserts x in the data structure. Returns True if x was not present and False if it was already present.
  2. remove(x): Removes x from the data structure, if present.
  3. getRandom(): Returns any value present in the stream randomly. The probability of each element being returned should be linearly proportional to the number of the 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 that 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):
    1. Insert x at the end of the dynamic array nums[].
    2. 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):
    1. Check if x is present in the stream by mp.count(x). If it is absent, then return False.
    2. 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.
    3. 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.
    4. Insert the value index into mp[nums[nums.size() - 1]] set.
    5. Swap the elements at index nums.size() - 1 and indexRemoved of nums.
    6. Delete the last element from nums (Removal from the end from Dynamic Array is constant time operation).
    7. If the mp[val] set becomes empty, erase val from mp.
    8. Return True
  • getRandom():
    1. Get a random number between 0 and nums.size() - 1.
    2. Return the value present at this index of nums.

Below is the implementation of the above approach: 

CPP
// 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 code int 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; } 
Java
// Java program to design a data structure // that supports insert, delete, // getRandom in O(1) with duplicates import java.util.*;  class Stream {      List<Integer> nums;     Map<Integer, Set<Integer> > mp;      public Stream()     {         nums = new ArrayList<>();         mp = new HashMap<>();     }      public boolean insert(int val)     {         nums.add(val);         int index = nums.size() - 1;         if (!mp.containsKey(val)) {             mp.put(val, new HashSet<>());         }         mp.get(val).add(index);         return mp.get(val).size() == 1;     }      public boolean remove(int val)     {         if (!mp.containsKey(val)) {             return false;         }         Set<Integer> valIndices = mp.get(val);         int index = valIndices.iterator().next();         int lastIndex = nums.size() - 1;         valIndices.remove(index);         if (index != lastIndex) {             int lastNum = nums.get(lastIndex);             mp.get(lastNum).remove(lastIndex);             mp.get(lastNum).add(index);             Collections.swap(nums, index, lastIndex);         }         nums.remove(lastIndex);         if (valIndices.size() == 0) {             mp.remove(val);         }         return true;     }      public int getRandom()     {         int randomIndex             = (int)(Math.random() * nums.size());         return nums.get(randomIndex);     } }  public class Main {     public static void main(String[] args)     {         Stream myStream = new Stream();         System.out.println(myStream.insert(5));         System.out.println(myStream.insert(6));         System.out.println(myStream.insert(5));         System.out.println(myStream.remove(6));         System.out.println(myStream.remove(6));         System.out.println(myStream.getRandom());     } } 
Python3
''' Python program to design a data structure  that supports insert, delete,  getRandom in O(1) with duplicates''' import random   class Stream:     def __init__(self):          # Stores all the numbers present         # currently in the stream         self.nums = []          # Unordered ensure O(1) operation         self.mp = {}      '''Function to insert values     in the stream'''      def insert(self, val):          # Inserting val to the end of array         self.nums.append(val)          # Index at which val was inserted         index = len(self.nums) - 1          if val not in self.mp:             self.mp[val] = set()          # Inserting the index inside the         # set mp[val]         self.mp[val].add(index)          # Return True if only one val         # is present in the stream         return len(self.mp[val]) == 1      # Function to remove the value     # from the stream      def remove(self, val):          # If the value is not present         # in the stream         if val not in self.mp:             return False          # Get the value of the first element         # of the mp[val] and store it         # in a variable named index         index = next(iter(self.mp[val]))          # Last Index of nums         last_index = len(self.nums) - 1          # Erase the index from mp[val] set         self.mp[val].remove(index)          # If index == lastIndex, then the         # element was already deleted         # from the stream         if index != last_index:             last_num = self.nums[last_index]              # Delete the lastIndex from             # mp[nums[lastIndex]] set             self.mp[last_num].remove(last_index)              # Insert index into mp[nums[lastIndex]] set             self.mp[last_num].add(index)              # Swap the values at index and lastIndex             self.nums[index], self.nums[last_index] = self.nums[last_index], self.nums[index]          # Delete the last element from nums         # This operation is O(1) operation         self.nums.pop()          # If the size of mp[val] is 0,         # val is absent from the stream         # and hence it is removed         if not self.mp[val]:             del self.mp[val]         return True      # Function to get a random number     # from the stream of data      def getRandom(self):          #  Get any random index from 0 to         # nums.length() - 1         random_index = random.randint(0, len(self.nums) - 1)          # Return the value at that index         return self.nums[random_index]   # Driver code myStream = Stream() print(myStream.insert(5)) print(myStream.insert(6)) print(myStream.insert(5)) print(myStream.remove(6)) print(myStream.remove(6)) print(myStream.getRandom())   # This code is contributed by shivhack999 
C#
using System; using System.Collections.Generic; using System.Linq;  // Class representing a stream with O(1) insert, delete, and getRandom operations class Stream {     private List<int> nums; // Stores all the numbers present currently in the stream     private Dictionary<int, HashSet<int>> mp; // Dictionary to ensure O(1) operation      // Constructor initializes the stream     public Stream()     {         nums = new List<int>();         mp = new Dictionary<int, HashSet<int>>();     }      // Function to insert values in the stream     public bool Insert(int val)     {         nums.Add(val);         int index = nums.Count - 1;          if (!mp.ContainsKey(val))             mp[val] = new HashSet<int>();          mp[val].Add(index);          return mp[val].Count == 1;     }      // Function to remove the value from the stream     public bool Remove(int val)     {         if (!mp.ContainsKey(val))             return false;          int index = mp[val].First();         int lastIndex = nums.Count - 1;          mp[val].Remove(index);          if (index != lastIndex)         {             mp[nums[lastIndex]].Remove(lastIndex);             mp[nums[lastIndex]].Add(index);             nums[index] = nums[lastIndex];         }          nums.RemoveAt(lastIndex);          if (mp[val].Count == 0)             mp.Remove(val);          return true;     }      // Function to get a random number from the stream of data     public int GetRandom()     {         int randomIndex = new Random().Next(0, nums.Count);         return nums[randomIndex];     } }  // Driver code class Program {     static void Main()     {         Stream myStream = new Stream();          Console.WriteLine(myStream.Insert(5));         Console.WriteLine(myStream.Insert(6));         Console.WriteLine(myStream.Insert(5));         Console.WriteLine(myStream.Remove(6));         Console.WriteLine(myStream.Remove(6));         Console.WriteLine(myStream.GetRandom());     } } 
JavaScript
class Stream {   constructor() {     // Stores all the numbers present currently in the stream     this.nums = [];     // Map to store indices of each value in the stream     this.mp = new Map();   }    // Function to insert values in the stream   insert(val) {     // Inserting val to the end of array     this.nums.push(val);      // Index at which val was inserted     const index = this.nums.length - 1;      // Inserting the index inside the set mp[val]     if (!this.mp.has(val)) {       this.mp.set(val, new Set());     }     this.mp.get(val).add(index);      // Return 1 if only one val is present in the stream     return this.mp.get(val).size === 1 ? 1 : 0;   }    // Function to remove the value from the stream   remove(val) {     // If the value is not present in the stream     if (!this.mp.has(val)) {       return 0;     }      // Get the value of the first element of the mp[val] and store it in a variable named index     const index = this.mp.get(val).values().next().value;      // Last Index of nums     const lastIndex = this.nums.length - 1;      // Erase the index from mp[val] set     this.mp.get(val).delete(index);      // If index == lastIndex, then the element was already deleted from the stream     if (index !== lastIndex) {       // Delete the lastIndex from mp[nums[lastIndex]] set       this.mp.get(this.nums[lastIndex]).delete(lastIndex);        // Insert index into mp[nums[lastIndex]] set       this.mp.get(this.nums[lastIndex]).add(index);        // Swap the values at index and lastIndex       [this.nums[index], this.nums[lastIndex]] = [this.nums[lastIndex], this.nums[index]];     }      // Delete the last element from nums     // This operation is O(1) operation     this.nums.pop();      // If the size of mp[val] is 0, val is absent from the stream and hence it is removed     if (this.mp.get(val).size === 0) {       this.mp.delete(val);     }     return 1;   }    // Function to get a random number from the stream of data   getRandom() {     // Get any random index from 0 to nums.length - 1     const randomIndex = Math.floor(Math.random() * this.nums.length);      // Return the value at that index     return this.nums[randomIndex];   } }  // Driver code const myStream = new Stream();  console.log(myStream.insert(5)); console.log(myStream.insert(6)); console.log(myStream.insert(5)); console.log(myStream.remove(6)); console.log(myStream.remove(6)); console.log(myStream.getRandom()); 

Output
1 1 0 1 0 5 

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

V

veedee
Improve
Article Tags :
  • Analysis of Algorithms
  • Advanced Data Structure
  • Computer Subject
  • DSA
Practice Tags :
  • Advanced Data Structure

Similar Reads

    Design a data structure that supports insert, delete, search and getRandom in constant time
    Design a data structure that supports the following operations in O(1) time.insert(x): Inserts an item x to the data structure if not already present.remove(x): Removes item x from the data structure if present. search(x): Searches an item x in the data structure.getRandom(): Returns a random elemen
    5 min read
    Design a structure which supports insertion and first non-repeating element in O(1) time
    Design a Data structure which supports insertion and first non-repeating element in O(1) time. Operations that are supported by the data structure: Insertion: Insert a element into the data structure.First non-repeating Element: First non-repeating element into the array. Note: If there is no non-re
    12 min read
    Design a stack that supports getMin() in O(1) time
    Design a Data Structure SpecialStack that supports all the stack operations like push(), pop(), peek() and an additional operation getMin() which should return minimum element from the SpecialStack. All these operations of SpecialStack must have a time complexity of O(1). Example: Input: queries = [
    15+ min read
    Design a Data Structure that performs add in O(n) and getMinimum & deleteMinimum in O(1)
    Design a data structure which can do following operations add() in O(n)getMinimum() in O(1)deleteMinimum() in O(1)Source : MakeMyTrip Interview. Maintain a linkedlist with elements in increasing order.Move head to next position in case of delete Min operation.Return First element in case of get Min
    7 min read
    Implementation of Search, Insert and Delete in Treap
    We strongly recommend to refer set 1 as a prerequisite of this post.Treap (A Randomized Binary Search Tree)In this post, implementations of search, insert and delete are discussed.Search: Same as standard BST search. Priority is not considered for search.   C++ // C function to search a given key in
    15+ min read
geeksforgeeks-footer-logo
Corporate & Communications Address:
A-143, 7th Floor, Sovereign Corporate Tower, Sector- 136, Noida, Uttar Pradesh (201305)
Registered Address:
K 061, Tower K, Gulshan Vivante Apartment, Sector 137, Noida, Gautam Buddh Nagar, Uttar Pradesh, 201305
GFG App on Play Store GFG App on App Store
Advertise with us
  • Company
  • About Us
  • Legal
  • Privacy Policy
  • In Media
  • Contact Us
  • Advertise with us
  • GFG Corporate Solution
  • Placement Training Program
  • Languages
  • Python
  • Java
  • C++
  • PHP
  • GoLang
  • SQL
  • R Language
  • Android Tutorial
  • Tutorials Archive
  • DSA
  • Data Structures
  • Algorithms
  • DSA for Beginners
  • Basic DSA Problems
  • DSA Roadmap
  • Top 100 DSA Interview Problems
  • DSA Roadmap by Sandeep Jain
  • All Cheat Sheets
  • Data Science & ML
  • Data Science With Python
  • Data Science For Beginner
  • Machine Learning
  • ML Maths
  • Data Visualisation
  • Pandas
  • NumPy
  • NLP
  • Deep Learning
  • Web Technologies
  • HTML
  • CSS
  • JavaScript
  • TypeScript
  • ReactJS
  • NextJS
  • Bootstrap
  • Web Design
  • Python Tutorial
  • Python Programming Examples
  • Python Projects
  • Python Tkinter
  • Python Web Scraping
  • OpenCV Tutorial
  • Python Interview Question
  • Django
  • Computer Science
  • Operating Systems
  • Computer Network
  • Database Management System
  • Software Engineering
  • Digital Logic Design
  • Engineering Maths
  • Software Development
  • Software Testing
  • DevOps
  • Git
  • Linux
  • AWS
  • Docker
  • Kubernetes
  • Azure
  • GCP
  • DevOps Roadmap
  • System Design
  • High Level Design
  • Low Level Design
  • UML Diagrams
  • Interview Guide
  • Design Patterns
  • OOAD
  • System Design Bootcamp
  • Interview Questions
  • Inteview Preparation
  • Competitive Programming
  • Top DS or Algo for CP
  • Company-Wise Recruitment Process
  • Company-Wise Preparation
  • Aptitude Preparation
  • Puzzles
  • School Subjects
  • Mathematics
  • Physics
  • Chemistry
  • Biology
  • Social Science
  • English Grammar
  • Commerce
  • World GK
  • GeeksforGeeks Videos
  • DSA
  • Python
  • Java
  • C++
  • Web Development
  • Data Science
  • CS Subjects
@GeeksforGeeks, Sanchhaya Education Private Limited, All rights reserved
We use cookies to ensure you have the best browsing experience on our website. By using our site, you acknowledge that you have read and understood our Cookie Policy & Privacy Policy
Lightbox
Improvement
Suggest Changes
Help us improve. Share your suggestions to enhance the article. Contribute your expertise and make a difference in the GeeksforGeeks portal.
geeksforgeeks-suggest-icon
Create Improvement
Enhance the article with your expertise. Contribute to the GeeksforGeeks community and help create better learning resources for all.
geeksforgeeks-improvement-icon
Suggest Changes
min 4 words, max Words Limit:1000

Thank You!

Your suggestions are valuable to us.

What kind of Experience do you want to share?

Interview Experiences
Admission Experiences
Career Journeys
Work Experiences
Campus Experiences
Competitive Exam Experiences