Loading

381. [哈希表]O(1) 时间插入、删除和获取随机元素 - 允许重复

381. O(1) 时间插入、删除和获取随机元素 - 允许重复

方法一:哈希表

由于\(List\)无法直接在\(O(1)\)的时间复杂度查找元素值,所以可以考虑\(List\)\(HashMap\)联合使用,\(HashMap\)\(HashMap\)记录值和索引。考虑到一个值不会有2个相同索引,并且在删除交换等操作时需要对值得索引也进行删除等操作,所以索引的部分只需要再额外使用一个\(Set\)完成插入、删除数字的下标即可。

由于\(List\)只有在删除尾元素时,才是以\(O(1)\)的时间复杂度完成的,做法可以是先把需要删除的元素与最后一个元素交换,在删除最后一个元素。具体实现如下。

// 执行用时: 14 ms , 在所有 Java 提交中击败了 91.73% 的用户
// 内存消耗: 45.3 MB , 在所有 Java 提交中击败了 56.87% 的用户

class RandomizedCollection {
    int n ;//当前集合大小
    HashMap<Integer,Set<Integer>>map;
    ArrayList<Integer>list;
    Random random;
    /** Initialize your data structure here. */
    public RandomizedCollection() {
        this.random = new Random();
        this.map = new HashMap();
        this.n = 0;
        this.list = new ArrayList<>();
    }
    
    /** Inserts a value to the collection. Returns true if the collection did not already contain the specified element. */
    public boolean insert(int val) {
        Set set = map.get(val);
        if(set==null)   set = new HashSet<>();
        set.add(n);//添加索引
        list.add(val);
        map.put(val, set);
        n++;
        return set.size()==1;
    }
    
    /** Removes a value from the collection. Returns true if the collection contained the specified element. */
    public boolean remove(int val) {
        if(map.containsKey(val)){
            int lastIndex = n-1;//得到最后2个值索引
            Set lastset = map.get(list.get(lastIndex));
            Set set = map.get(val);
            int currIndex = (int)set.iterator().next();//得到当前值索引
            //进行删除操作
            swap(list, currIndex, lastIndex);
            list.remove(n-1);//将其在列表中删除
            set.remove(currIndex);//删除原值
            if(set.size()==0)   map.remove(val);//在图中删除
            //修改最后一个值的索引
            lastset.remove(n-1);
            lastset.add(currIndex);
            n--;
        }else{
            return false;
        }
        return true;
    }
    
    /** Get a random element from the collection. */
    public int getRandom() {
        return list.get(random.nextInt(n));
    }
    private void swap(List<Integer> list ,int i,int j){
        int temp = list.get(i);
        list.set(i, list.get(j));
        list.set(j, temp);
    }
}

/**
 * Your RandomizedCollection object will be instantiated and called as such:
 * RandomizedCollection obj = new RandomizedCollection();
 * boolean param_1 = obj.insert(val);
 * boolean param_2 = obj.remove(val);
 * int param_3 = obj.getRandom();
 */
posted @ 2020-10-31 22:44  上海井盖王  阅读(261)  评论(0)    收藏  举报