• 算法:O(1) 时间插入、删除和获取随机元素---哈希表+动态数组


    在这里插入图片描述


    1、题目:

    实现RandomizedSet 类:

    • RandomizedSet() 初始化 RandomizedSet 对象
    • bool insert(int val) 当元素 val 不存在时,向集合中插入该项,并返回 true ;否则,返回 false
    • bool remove(int val) 当元素 val 存在时,从集合中移除该项,并返回 true ;否则,返回 false
    • int getRandom() 随机返回现有集合中的一项(测试用例保证调用此方法时集合中至少存在一个元素)。每个元素应该有 相同的概率 被返回。

    你必须实现类的所有函数,并满足每个函数的 平均 时间复杂度O(1)


    2、分析特点:

    • 题目要求:插入、删除和获取随机元素的时间复杂度都是 O(1)

    • 在遍历获取查询方面,数组可以实现 时间复杂度都是 O(1),但是插入和删除,要求判断val是否存在,导致了插入和删除会超过O(1)

    • 哈希表可以在 O(1) 的时间内完成插入和删除操作

    • 所以:哈希表+动态数组

    变长数组可以在 O(1) 的时间内完成获取随机元素操作,但是由于无法在 O(1) 的时间内判断元素是否存在,因此不能在 O(1) 的时间内完成插入和删除操作。哈希表可以在 O(1) 的时间内完成插入和删除操作,但是由于无法根据下标定位到特定元素,因此不能在 O(1) 的时间内完成获取随机元素操作。为了满足插入、删除和获取随机元素操作的时间复杂度都是 O(1),需要将变长数组和哈希表结合,变长数组中存储元素,哈希表中存储每个元素在变长数组中的下标。

    插入操作时,首先判断 val 是否在哈希表中,如果已经存在则返回 false,如果不存在则插入 val,操作如下:

    在变长数组的末尾添加 val;
    在添加 val 之前的变长数组长度为 val 所在下标 index,将 val 和下标 index 存入哈希表;
    返回 true。

    删除操作时,首先判断 val是否在哈希表中,如果不存在则返回 false,如果存在则删除 val,操作如下:

    从哈希表中获得 val 的下标 index;
    将变长数组的最后一个元素 last 移动到下标 index 处,在哈希表中将 last 的下标更新为 index;
    在变长数组中删除最后一个元素,在哈希表中删除 val;
    返回 true。

    删除操作的重点在于将变长数组的最后一个元素移动到待删除元素的下标处,然后删除变长数组的最后一个元素。该操作的时间复杂度是 O(1),且可以保证在删除操作之后变长数组中的所有元素的下标都连续,方便插入操作和获取随机元素操作。

    获取随机元素操作时,由于变长数组中的所有元素的下标都连续,因此随机选取一个下标,返回变长数组中该下标处的元素。


    3、代码:

    class RandomizedSet {
        List<Integer> nums;
        Map<Integer, Integer> indices;
        Random random;
    
        public RandomizedSet() {
            nums = new ArrayList<Integer>();
            indices = new HashMap<Integer, Integer>();
            random = new Random();
        }
    
        public boolean insert(int val) {
            if (indices.containsKey(val)) {
                return false;
            }
            int index = nums.size();
            nums.add(val);
            indices.put(val, index);
            return true;
        }
    
        public boolean remove(int val) {
            if (!indices.containsKey(val)) {
                return false;
            }
            int index = indices.get(val);
            int last = nums.get(nums.size() - 1);
            nums.set(index, last);
            indices.put(last, index);
            nums.remove(nums.size() - 1);
            indices.remove(val);
            return true;
        }
    
        public int getRandom() {
            int randomIndex = random.nextInt(nums.size());
            return nums.get(randomIndex);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    4、复杂度分析:

    • 时间复杂度:初始化和各项操作的时间复杂度都是 O(1)。

      空间复杂度:O(n),其中 n 是集合中的元素个数。存储元素的数组和哈希表需要 O(n) 的空间。


    5、总结:

    关于O(1)的时间平均复杂度的设计都离不开哈希表
    一般插入、删除、获取,数组可以实现,就选数组,简单些
    可以根据题目,对两种数据结构进行组合使用,比如:数组+哈希表




    如果本文对你有帮助的话记得给一乐点个赞哦,感谢!

  • 相关阅读:
    虹科分享 | 为工业机器人解绑,IO-Link wireless无线通讯技术可实现更加轻量灵活的机器人协作
    Spring框架学习 -- 创建与使用
    python爬虫-基本原理(简单好学)
    天天项目管理软件
    81.(前端)分配权限实现——用路由来接收参数实现展开行中选数据功能
    CAS:1604673-42-8 (Biotin-PEG4-Mal, 生物素PEG-MAL)
    使用fastlane match自动化管理证书和描述文件
    MySQL字符串函数
    BI财务分析 – 反映盈利水平利润占比的指标如何分析(下)
    三翼鸟:产品不会变,场景实时变
  • 原文地址:https://blog.csdn.net/weixin_45630258/article/details/133265909