380. Insert Delete GetRandom O(1)

380. Insert Delete GetRandom O(1)

Problem Solving - Day 59

ยท

4 min read

Hello, reader ๐Ÿ‘‹๐Ÿฝ ! Welcome to day 59 of the series on Problem Solving. Through this series, I aim to pick up at least one question everyday and share my approach for solving it.

Today, I will be picking up LeetCode's daily challenge problem: 380. Insert Delete GetRandom O(1).


๐Ÿค” Problem Statement

  • 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.
  • The functions need to be implemented such that each works in average O(1) time complexity.

  • E.g.:
    • ["RandomizedSet", "insert", "remove", "insert", "getRandom", "remove", "insert", "getRandom"]
    • [[], [1], [2], [2], [], [1], [2], []]
      • [null, true, false, true, 2, true, false, 2]

๐Ÿ’ฌ Thought Process - Hash Map + Array

  • We have to focus on three functions:
    1. insert()
    2. remove()
    3. getRandom()
  • Let's first focus on insert() and remove(). We know that for array insertion and removal could be O(n) in the worst case. Hence we cannot use an array to store all the integers.
  • Stack or Queue could work, but then they only support only removals from front or back.
  • The two data structures that would help us in getting an O(1) operations are: set and map.

  • Let's think about getRandom(). This function could have been easy if we had an array. Then we could have generated a random index whose range would be within the size of the array. Since random access is O(1) in an array, this works.

  • But the problem is we cannot use an array for insertion and removal. So what can we do?
  • In the worst case, removal from an array does cause O(n). But the removal (and insertion) of an element from the end of an array is only an O(1) operation.
  • So we can try to make use of this. But there's no guarantee that every time the value that needs to be removed is in the end of the array.
  • The way around this is that whenever we have to remove a value val, we can swap it with last element in the array.
  • But then for that we should know in which index the value val is stored in. Hence, we need a quick way of accessing the indices in the array where every value is stored.
  • So the idea behind this problem's approach boils down to this:
    1. Use a map to store <value, index> pairs and an array to store all the values
    2. Insert an element val to the array at index i and save the val, i pair in the map
    3. Remove an element val at index i by swapping it with the last element last in the array at index j. Remove the val, i value and update the pair last, j to last, i in the map.
    4. Generate a random index random whose range is between [0, array size] and return the value of the array in random.

๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿ’ป Solution - Hash Map + Array

  • Below is the code for the approach using hash map and array. ``` class RandomizedSet { Map values; List valueIndices; public RandomizedSet() {

      values = new HashMap();
      valueIndices = new ArrayList();
    

    }

    public boolean insert(int val) {

      if(values.containsKey(val)) return false;
    
      // insert the current value in the last index
      int index = values.size();
      values.put(val, index);
      // insert the current value in the last index
      valueIndices.add(index, val);
    
      return true;
    

    }

    public boolean remove(int val) {

      if(!values.containsKey(val)) return false;
    
      // Get the index of current val
      int valIndex = values.get(val);
      // Get the last index and the last val
      int lastIndex = valueIndices.size() - 1;
      int lastVal = valueIndices.get(lastIndex);
    
      // removes curr element from map
      values.remove(val);
      // removes curr element from index
      valueIndices.remove(valIndex);
      if(val == lastVal) {
          return true;
      }
    
      // add the last value to valIndex in the list
      valueIndices.add(valIndex, lastVal);
      // set the lastVal index as valIndex
      values.put(lastVal, valIndex);
      // remove the last index from the list
      valueIndices.remove(lastIndex);
      return true;
    

    }

    public int getRandom() {

      Random random = new Random();
      int randomIndex = random.nextInt(valueIndices.size());
    
      return valueIndices.get(randomIndex);
    

    } }

/**

  • Your RandomizedSet object will be instantiated and called as such:
  • RandomizedSet obj = new RandomizedSet();
  • boolean param_1 = obj.insert(val);
  • boolean param_2 = obj.remove(val);
  • int param_3 = obj.getRandom(); */
    
    
    Time Complexity:
    • insert: O(1)
    • remove: O(1)
    • getRandom: O(1) Space Complexity: O(n) ```


Conclusion

That's a wrap for today's problem. If you liked my explanation then please do drop a like/ comment. Also, please correct me if I've made any mistakes or if you want me to improve something!

Thank you for reading!