O(1)插入、删除和随机元素[中等]

优质博文:IT-BLOG-CN
在这里插入图片描述

一、题目

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

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

示例:
输入: ["RandomizedSet", "insert", "remove", "insert", "getRandom", "remove", "insert", "getRandom"] :[[], [1], [2], [2], [], [1], [2], []]
输出:[null, true, false, true, 2, true, false, 2]

解释:

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

-231 <= val <= 231 - 1
在调用getRandom方法时,数据结构中 至少存在一个 元素。

二、代码

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

// 空间换时间
class RandomizedSet {
    Map<Integer,Integer> map;
    List<Integer> list;
    Random random;

    public RandomizedSet() {
        map = new HashMap<>();
        list = new ArrayList();
        random = new Random();
    }
    
    public boolean insert(int val) {
        // 判断value是否存在,存在直接返回false
        if(map.containsKey(val)) {
            return false;
        }
        // 插入 0(1) 使用 map[key = val , value = index] 数组的长度=数据的下标
        map.put(val, list.size());
        // list中存放 val
        list.add(val);
        return true;
    }
    
    // 删除操作的重点在于将变长数组的最后一个元素移动到待删除元素的下标处,然后删除变长数组的最后一个元素。
    // 该操作的时间复杂度是 O(1),且可以保证在删除操作之后变长数组中的所有元素的下标都连续,方便插入操作和获取随机元素操作。
    public boolean remove(int val) {
        if (!map.containsKey(val)) {
            return false;
        }
        // 思想:list 的 udpate 是 O(1) 所以使用 list中的最后一个元素修改 index 下表的元素
        // 通过map获取指定val的下表
        int index = map.get(val);
        // 获取list中最后一个元素
        int last = list.get(list.size() - 1);
        // 使用最后一个元素替换list中的index元素
        list.set(index, last);
        // map 也需要更新最后一个元素 last 的下标
        map.put(last, index);
        // 删除list和map
        list.remove(list.size() - 1);
        map.remove(val);
        return true;
    }
    
    // 获取随机元素操作时,由于变长数组中的所有元素的下标都连续,因此随机选取一个下标,返回变长数组中该下标处的元素
    public int getRandom() {
        int randomIndex = random.nextInt(list.size());
        return list.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();
 */

变长数组 + 哈希表: 这道题要求实现一个类,满足插入、删除和获取随机元素操作的平均时间复杂度为O(1)

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

插入操作时,首先判断val是否在哈希表中,如果已经存在则返回false,如果不存在则插入val,操作如下:
1、在变长数组的末尾添加val
2、在添加val之前的变长数组长度为val所在下标index,将val和下标index存入哈希表;
3、返回true

删除操作时,首先判断val是否在哈希表中,如果不存在则返回false,如果存在则删除val,操作如下:
1、从哈希表中获得val的下标index
2、将变长数组的最后一个元素last移动到下标index处,在哈希表中将last的下标更新为index
3、在变长数组中删除最后一个元素,在哈希表中删除val
4、返回true

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

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

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);
    }
}

时间复杂度: 初始化和各项操作的时间复杂度都是O(1)
空间复杂度: O(n),其中 nnn 是集合中的元素个数。存储元素的数组和哈希表需要O(n)的空间。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/332687.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java基本算法

1.链表 链表用来存储数据&#xff0c;由一系列的结点组成。这些结点的物理地址不一定是连续的&#xff0c;即可能连续&#xff0c;也可能不连续&#xff0c;但链表里的结点是有序的。一个结点由数据的值和下一个数据的地址组成。一个链表内的数据类型可以是多种多样的。数组也是…

Debian系统写Mysql时中文出现乱码无法定入的问题解决方案

原因是操作系统可能精简安装&#xff0c;没有GBK字符集&#xff0c;只有UTF8在转换或使用的时候有问题。 使用locale -a查看系统支持的字符集。正常的比较全的字符集的操作系统如下&#xff1a; 有问题的操作系统字符集如下&#xff1a; 解决方案&#xff1a; 步骤1&#…

protobuf学习日记 | 认识protobuf中的类型

目录 前言 一、标量数据类型 二、protobuf中的 “数组” 三、特殊类型 1、枚举类型 &#xff08;1&#xff09;类型讲解 &#xff08;2&#xff09;升级通讯录 2、Any类型 &#xff08;1&#xff09;类型讲解 &#xff08;2&#xff09;升级通讯录 3、oneof类型 …

【动态规划】【二分查找】【C++算法】730. 统计不同回文子序列

作者推荐 【动态规划】【数学】【C算法】18赛车 涉及知识点 动态规划 二分查找 LeetCode730. 统计不同回文子序列 给你一个字符串 s &#xff0c;返回 s 中不同的非空回文子序列个数 。由于答案可能很大&#xff0c;请返回对 109 7 取余 的结果。 字符串的子序列可以经由…

ubuntu源码安装MySQL

mysql下载路径 创建新数组 mysql sudo groupadd mysql# 创建用户 mysql ,指定属组为 mysql&#xff0c;禁止其登录 # --no-create-home选项&#xff0c;创建用户时不会自动创建主目录 sudo adduser --system --no-create-home --ingroup mysql --shell /sbin/nologin mysql创…

第二证券:大逆转!A股强势反弹,多家机构看好后市

周四&#xff0c;A股强势反弹&#xff0c;沪指2800点合浦还珠&#xff0c;两市成交量达8767亿元&#xff0c;较周三大幅增加2000多亿元。沪深300ETF大幅放量&#xff0c;华泰柏瑞沪深300ETF、嘉实沪深300ETF、易方达沪深300ETF和华夏沪深300ETF等4只沪深300ETF算计成交额超311亿…

常用中间件漏洞

IIS6 IIS7 安装 控制面板-----打开关闭windows功能 添加角色-----添加IIS 启动之后访问localhost 复现 服务器换成IIS7 访问报错 大概就是缺少CGI模块 问题解决 添加php-cgi的路径 添加脚本映射 修改php.ini文件 将 cgi.fix_pathinfo1 然后设置一个图片 访问 在后缀加上/.…

游戏开发要注意这几个问题

游戏开发是一个充满创意和挑战的过程。对于初学者和经验丰富的开发者来说&#xff0c;每个项目都是一个新的学习机会。然而&#xff0c;成功的游戏开发不仅仅是关于编码和设计&#xff1b;它还涉及到细致的规划、测试和市场洞察。以下是在开发游戏时需要特别注意的几个关键方面…

阿里云容器服务助力万兴科技 AIGC 应用加速

作者&#xff1a;子白&#xff08;顾静&#xff09; 2023 年堪称是 AIGC 元年&#xff0c;文生图领域诞生了 Stable Diffusion 项目&#xff0c;文生文领域诞生了 GPT 家族。一时间风起云涌&#xff0c;国内外许多企业投身 AIGC 创新浪潮&#xff0c;各大云厂商紧随其后纷纷推…

ELK 分离式日志

目录 一.ELK组件 ElasticSearch&#xff1a; Kiabana&#xff1a; Logstash&#xff1a; 可以添加的其它组件&#xff1a; ELK 的工作原理&#xff1a; 二.部署ELK 节点都设置Java环境: 每台都可以部署 Elasticsearch 软件&#xff1a; 修改elasticsearch主配置文件&…

Vue以弹窗形式实现导入功能

目录 前言正文 前言 由于个人工作原因&#xff0c;偏全栈&#xff0c;对于前端的总结还有些初出茅庐&#xff0c;后续会进行规整化的总结 对应的前端框架由&#xff1a;【vue】avue-crud表单属性配置&#xff08;表格以及列&#xff09; 最终实现的表单样式如下&#xff1a;…

VSCode 插件推荐

前言 关于开发用的插件就不做赘述了&#xff0c;网上面有很多文章都做了推荐&#xff0c;本文推荐几个好看的插件。 文件图标主题 Vscode icons Material Icon Theme 字体主题 推荐 One Dark Pro 其他 推荐一个生成好看代码的网址 https://carbon.now.sh/

策略模式在工作中的运用

前言 在不同的场景下&#xff0c;执行不同的业务逻辑&#xff0c;在日常工作中是很寻常的事情。比如&#xff0c;订阅系统。在收到阿里云的回调事件、与收到AWS的回调事件&#xff0c;无论是收到的参数&#xff0c;还是执行的逻辑都可能是不同的。为了避免&#xff0c;每次新增…

如何选购一款质量好超声波清洗机呢?质量好超声波清洗机排行榜

想要选择到一款好用的超声波清洗机还是要多做功课&#xff01;现在市面上超声波清洗机品牌可见是非常多的&#xff0c;质量也是参差不齐&#xff0c;大家在选购的时候需要多看参数再下手也不迟的&#xff01;现在大多数的上班族&#xff0c;面临的都是早九晚六的工作&#xff0…

LeetCode 算法 3.无重复字符的最长子串(python版)

1.需求 #给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 #输入: s “pwwkew” #输出: 3 #解释: 因为无重复字符的最长子串是 “wke”&#xff0c;所以其长度为 3。 #请注意&#xff0c;你的答案必须是 子串 的长度&#xff0c;“pwke” 是一个…

Linux centos中find命令的多种用途:按照具体应用来详细说明find的用法举例

目录 一、find命令 二、find命令的语法 &#xff08;一&#xff09;语法格式 &#xff08;二&#xff09;选项 1、选项(option)介绍 2、控制符号链接的option 3、调试选项debugopts 4、优化选项 &#xff08;三&#xff09;表达式expression 1、选项options 2、测试…

Docker之nacos的安装和使用

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是君易--鑨&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的博客专栏《Docker之Dockerfile构建镜像》。&#x1f3af;&…

python数字图像处理基础(九)——特征匹配

目录 蛮力匹配&#xff08;ORB匹配&#xff09;RANSAC算法全景图像拼接 蛮力匹配&#xff08;ORB匹配&#xff09; Brute-Force匹配非常简单&#xff0c;首先在第一幅图像中选取一个关键点然后依次与第二幅图像的每个关键点进行&#xff08;描述符&#xff09;距离测试&#x…

Android中矩阵Matrix实现平移,旋转,缩放和翻转的用法详细介绍

一&#xff0c;矩阵Matrix的数学原理 矩阵的数学原理涉及到矩阵的运算和变换&#xff0c;是高等代数学中的重要概念。在图形变换中&#xff0c;矩阵起到关键作用&#xff0c;通过矩阵的变换可以改变图形的位置、形状和大小。矩阵的运算是数值分析领域的重要问题&#xff0c;对…

GC6139——单通道5V高细分步进电机,应用于摇头机,X,Y控制,聚焦控制等产品中,可替代MS41939

GC6139是一款单通道5V低压步进电机驱动器&#xff0c;具有低噪声、低振动的特点&#xff0c;特别适用于相机的变焦或对焦系统、万向节等精密低噪声STM控制系统。该芯片为每个通道集成了64微步驱动器。带SPl接口&#xff0c;用户可以方便地调整驱动器的参数。该芯片还内置2通道L…