• LeetCode 380: 常数时间插入、删除和获取随机元素 Insert Delete GetRandom O(1)


    题目:

    设计一个支持在平均 时间复杂度 O(1) 下,执行以下操作的数据结构。

    1. insert(val):当元素 val 不存在时,向集合中插入该项。
    2. remove(val):元素 val 存在时,从集合中移除该项。
    3. getRandom:随机返回现有集合中的一项。每个元素应该有相同的概率被返回。

    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.

    示例 :

    // 初始化一个空的集合。
    RandomizedSet randomSet = new RandomizedSet();
    
    // 向集合中插入 1 。返回 true 表示 1 被成功地插入。
    randomSet.insert(1);
    
    // 返回 false ,表示集合中不存在 2 。
    randomSet.remove(2);
    
    // 向集合中插入 2 。返回 true 。集合现在包含 [1,2] 。
    randomSet.insert(2);
    
    // getRandom 应随机返回 1 或 2 。
    randomSet.getRandom();
    
    // 从集合中移除 1 ,返回 true 。集合现在包含 [2] 。
    randomSet.remove(1);
    
    // 2 已在集合中,所以返回 false 。
    randomSet.insert(2);
    
    // 由于 2 是集合中唯一的数字,getRandom 总是返回 2 。
    randomSet.getRandom();
    

    解题思路:

    • 要求时间复杂度 O(1) 插入删除操作: 可以从零开始设计一个哈希算法, 也可以借助高级程序语言中已设计好的哈希集合/映射

    • 要求相同概率随随机返回元素: 哈希集合无法做到随机返回一个元素, 可以再借助一个顺序存储如数组, 随机产生索引下标, 返回对应元素值

    那么就需要用哈希映射存储元素, key 为元素值, value 为元素存储在辅助数组中的索引下标值

    插入操作就是数组, 哈希映射的插入操作

    难点在于删除操作, 首先删除哈希映射中的该键值对, 其次删除数组中的该元素值, 不能简单的通过赋一个不可能出现的数值伪删除, 因为这种伪删除会导致数组越来越大撑爆内存。

    代码:

    Java:

    class RandomizedSet {
        List<Integer> list;
        Map<Integer, Integer> map;
        Random rand;
    
        /** Initialize your data structure here. */
        public RandomizedSet() {
            list = new ArrayList();
            map = new HashMap();
            rand = new Random();
        }
    
        /**
         * Inserts a value to the set. Returns true if the set did not already contain the specified element.
         * 常规插入操作
         */
        public boolean insert(int val) {
            if (map.containsKey(val))
                return false;
            map.put(val, list.size()); // value 表示存储在 list 中的索引下标
            list.add(val); // 添加在数组 list 尾部
            return true;
        }
    
        /**
         * Removes a value from the set. Returns true if the set contained the specified element.
         * 
         */
        public boolean remove(int val) {
            if (!map.containsKey(val)) // 如果哈希映射中不存在该键 直接返回 False
                return false;
            int tmp = list.get(list.size() - 1); // 暂存数组最后一位元素值
            int index = map.get(val); // 获取待删除元素在 list 数组中对应的索引下标 index
            list.set(index, tmp); // 将 list 中该元素值改为暂存的数组最后一位值
            map.put(tmp, index); // 更新哈希映射中代表数组最后一位的键值对 对应的索引下标为 index
            list.remove(list.size() - 1); // 删除数组最后一位
            map.remove(val); // 删除哈希映射中该键值对
            return true;
        }
    
        /** Get a random element from the set. */
        public int getRandom() {
            return list.get(rand.nextInt(list.size())); // 产生一个大小为 [0, 数组大小) 的随机索引下标
        }
    }
    

    Python:

    from random import choice
    
    class RandomizedSet:
    
        def __init__(self):
            """
            Initialize your data structure here.
            """
            self.val_map = dict()
            self.val_list = list()
    
        def insert(self, val: int) -> bool:
            """
            Inserts a value to the set. Returns true if the set did not already contain the specified element.
            """
            if val not in self.val_map:
                self.val_map[val] = len(self.val_list) # value 表示存储在 val_list 中的索引下标
                self.val_list.append(val) # 添加在数组 val_list 尾部
                return True
            return False
    
        def remove(self, val: int) -> bool:
            """
            Removes a value from the set. Returns true if the set contained the specified element.
            """
            if val in self.val_map:
                index = self.val_map[val] # 获取待删除元素在 list 数组中对应的索引下标 index
                last_val = self.val_list[-1] # 暂存数组最后一位元素值
                self.val_list[index] = last_val # 将 list 中该元素值改为暂存的数组最后一位值
                self.val_map[last_val] = index # 更新哈希映射中代表数组最后一位的键值对 对应的索引下标为 index
                self.val_map.pop(val) # 删除哈希映射中该键值对
                self.val_list.pop() # 删除数组最后一位
                return True
            return False
    
        def getRandom(self) -> int:
            """
            Get a random element from the set.
            """
            return choice(self.val_list) # 返回数组中的随机一个元素
    

    欢迎关注微_信公众号: 爱写Bug
    爱写Bug.jpeg

  • 相关阅读:
    【矩阵乘法优化dp】[Codeforces 621E] Wet Shark and Blocks
    【2016常州一中夏令营Day7】
    【2016常州一中夏令营Day6】
    【2016常州一中夏令营Day5】
    【2016常州一中夏令营Day4】
    【2016常州一中夏令营Day3】
    【2016常州一中夏令营Day2】
    Aiopr的中文意思
    Bloom filter
    redis4.0.2集群搭建
  • 原文地址:https://www.cnblogs.com/zhangzhe532/p/12511701.html
Copyright © 2020-2023  润新知