[Leetcode 380] Insert Delete GetRandom O(1)

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

  1. insert(val): Inserts an item val to the set if not already present.
  2. remove(val): Removes an item val from the set if present.
  3. getRandom: Returns a random element from current set of elements. Each element must have the same probability of being returned.

Example:

// Init an empty set.
RandomizedSet randomSet = new RandomizedSet();

// Inserts 1 to the set. Returns true as 1 was inserted successfully.
randomSet.insert(1);

// Returns false as 2 does not exist in the set.
randomSet.remove(2);

// Inserts 2 to the set, returns true. Set now contains [1,2].
randomSet.insert(2);

// getRandom should return either 1 or 2 randomly.
randomSet.getRandom();

// Removes 1 from the set, returns true. Set now contains [2].
randomSet.remove(1);

// 2 was already in the set, so return false.
randomSet.insert(2);

// Since 2 is the only number in the set, getRandom always return 2.
randomSet.getRandom()

思路

  1. For inserting and deleting, we need to check if a value exists before in O(1) time. Consider hash table.

  2. For getting random the array is a good choice because:

    • Get every number with same possibility
    • Get number in O(1) time
  3. 因此该data structure需要2个数据结构来支撑:

    • ArrayList<Integer> 用于存放values
    • Map <Integer, Integer>用于存放输入的value的值和value在ArrayList中的位置的mapping
      key: value的值。 value: Value在ArrayList中的index

    Example

  items : (value/ index)  
       [ 1 ]  `0`                               
       [ 0 ]  `1`
       [ 4 ]  `2`
 Mapping: (value/ index in items array)
      <1, 0>
      <0, 1>
      <4, 2>
  1. Insert operation

    • Check if mapping contains current val, only insert if it doesn't contain
      1)向arraylist中加入val。
      2) 将该val和array list的size - 1作为mapping set加入hash table。(因为insert的时候都是加入到arraylist的尾部, 所以size - 1就是当前val在arraylist中的index)
  2. remove operation

    • Check if mapping contains current val, only remove if it doesn't contain
      1. 题目并未要求保持顺序,而且要求remove的time complexity为1, 所以不能直接从中间remove, 这样会导致所有其后面的元素都需要顺序移位。
        solution => Array List中将最后一个item replace 掉需要被remove的item,然后delete掉最后一个item。这样就能在 **O(1) **时间内完成remove
      2. 除了需要从Array List中移除item,还需要update hash table。
        • 用remove item在Array List中的index,替代hash table中 移除item之前 array list里last item的index。 (因为,array list 中last item会与remove item交换位置,从而其location index就是remove item 的location)
        • 再从Hash Table中remove掉val所在的map entry set

注意 :因为需要用到Array List中last item index, 所以在真正从array list中移除item之前,先更新hash table,再更新array list

  1. Random Operation
    用Random object在【0,ArrayList.size()】范围内生成一个随机int,用于array list的随机获取指针

Code

class RandomizedSet {

    private List<Integer> items;
    private Map<Integer, Integer> itemToLocation;
        
    /** Initialize your data structure here. */
    public RandomizedSet() {
        items = new ArrayList<Integer>();
        itemToLocation = new HashMap<Integer, Integer>();
    }
    
    /** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
    public boolean insert(int val) {
        if (itemToLocation.containsKey(val))
        {
            return false;
        }
        
        itemToLocation.put(val, items.size());
        items.add(val);
        return true;
    }
    
    /** Removes a value from the set. Returns true if the set contained the specified element. */
    public boolean remove(int val) {
        if (!itemToLocation.containsKey(val))
        {
            return false;
        }
        
        // update hashtable
        int lastItem = items.get (items.size() - 1);
        int itemToRemoveLocation = itemToLocation.get(val);
        itemToLocation.put (lastItem, itemToRemoveLocation);
        itemToLocation.remove (val);
        
        // update arraylist: swap val and last item, and then remove the last item from the array list
        items.set (itemToRemoveLocation, lastItem);
        items.remove (items.size() - 1);
        
        return true;
    }
    
    /** Get a random element from the set. */
    public int getRandom() {
        Random random = new Random ();
        int ranEleIndx = random.nextInt (items.size ());
        return items.get(ranEleIndx);
    }
}

/**
 * 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();
 */
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • pyspark.sql模块 模块上下文 Spark SQL和DataFrames的重要类: pyspark.sql...
    mpro阅读 9,516评论 0 13
  • Lua 5.1 参考手册 by Roberto Ierusalimschy, Luiz Henrique de F...
    苏黎九歌阅读 13,937评论 0 38
  • 背景 一年多以前我在知乎上答了有关LeetCode的问题, 分享了一些自己做题目的经验。 张土汪:刷leetcod...
    土汪阅读 12,779评论 0 33
  • 空白的颜色 是炽热的灯泡 发着暗黄的光 被筛成黑白色调 空白的气味 是冰箱里的剩菜 在低温下隔开味蕾 空白的时间 ...
    空蛹满梦阅读 127评论 0 0
  • 1、今天,社会调查老师上课,提到自己任课、调研一年多没有好好看本书了,顺口问我们什么情况,一片寂静……随即说我们趁...
    晨沐阅读 339评论 0 2