Leetcode 剑指 Offer II 030. 插入、删除和随机访问都是 O(1) 的容器
题目难度: 中等
原题链接
今天继续更新 Leetcode 的剑指 Offer(专项突击版)系列, 大家在公众号 算法精选 里回复
剑指offer2
就能看到该系列当前连载的所有文章了, 记得关注哦~
题目描述
设计一个支持在平均 时间复杂度 O(1) 下,执行以下操作的数据结构:
- insert(val):当元素 val 不存在时返回 true ,并向集合中插入该项,否则返回 false 。
- remove(val):当元素 val 存在时返回 true ,并从集合中移除该项,否则返回 false 。
- getRandom:随机返回现有集合中的一项。每个元素应该有 相同的概率 被返回。
示例 :
- 输入: inputs = [“RandomizedSet”, “insert”, “remove”, “insert”, “getRandom”, “remove”, “insert”, “getRandom”]
[[], [1], [2], [2], [], [1], [2], []] - 输出: [null, true, false, true, 2, true, false, 2]
- 解释:
RandomizedSet randomSet = new RandomizedSet(); // 初始化一个空的集合
randomSet.insert(1); // 向集合中插入 1 , 返回 true 表示 1 被成功地插入
randomSet.remove(2); // 返回 false,表示集合中不存在 2
randomSet.insert(2); // 向集合中插入 2 返回 true ,集合现在包含 [1,2]
randomSet.getRandom(); // getRandom 应随机返回 1 或 2
randomSet.remove(1); // 从集合中移除 1 返回 true 。集合现在包含 [2]
randomSet.insert(2); // 2 已在集合中,所以返回 false
randomSet.getRandom(); // 由于 2 是集合中唯一的数字,getRandom 总是返回 2
提示:
- -2^31 <= val <= 2^31 - 1
- 最多进行 2 * 10^5 次 insert , remove 和 getRandom 方法调用
- 当调用 getRandom 方法时,集合中至少有一个元素
题目思考
- 需要用到哪些数据结构?
解决方案
思路
- 分析题目, 最容易想到的思路就是利用 set, 这样插入和删除都是 O(1) 时间
- 但 set 的问题是 getRandom 无法做到 O(1), 必须得先转成数组, 然后取其随机下标才行
- 要想 getRandom 操作是 O(1) 时间, 我们必须维护一个数组, 但其删除元素不是 O(1), 如何解决呢?
- 回顾数组的性质, 其删除末尾元素只需要 O(1) 时间, 我们如果可以将删除任意元素转换成删除末尾元素, 就能做到所有操作都是 O(1) 了, 这要如何实现呢?
- 我们如果能够知道任意元素的下标, 那么在删除它时, 可以将它与末尾元素进行交换, 这样就转换成了删除末尾元素
- 不难想到我们可以使用一个元素到下标的映射字典来实现, 然后在插入和删除时增加一些额外的操作来更新该字典
- 插入时, 我们先利用该字典判断元素是否存在 (O(1)), 不存在时只需要将元素插入到数组末尾 (O(1)), 然后在字典中增加一项, 即它到新的末尾下标的映射 (O(1))
- 删除时, 同样先判断元素是否存在于字典中 (O(1)), 存在时拿到元素对应下标 (O(1)), 如果该下标不是末尾, 则将其与末尾元素交换 (O(1)), 同时更新映射字典 ((O(1))), 最后再移除数组的末尾元素 (O(1)), 以及字典中该元素的映射关系即可 ((O(1)))
- 取随机项时, 利用 random 库直接得到一个数组范围内的下标, 并返回数组对应元素即可 (O(1))
- 综上所述, 所有操作都只需要 O(1) 时间
- 下面代码有详细的注释, 方便大家理解
复杂度
- 时间复杂度 O(1): 每种操作都只需要常数时间
- 空间复杂度 O(N): 数组和字典各需要 O(N) 空间
代码
class RandomizedSet:def __init__(self):"""Initialize your data structure here."""# 初始化数组(用于取随机数)和v2i字典(用于维护值和下标的对应关系)self.arr = []self.v2i = {}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 in self.v2i:# 该值已存在, 不进行操作return False# 追加到数组末尾, 并更新v2i字典self.arr.append(val)self.v2i[val] = len(self.arr) - 1return Truedef remove(self, val: int) -> bool:"""Removes a value from the set. Returns true if the set contained the specified element."""if val in self.v2i:# 该值存在, 找到它的下标i = self.v2i[val]end = len(self.arr) - 1if i != end:# 如果待移除下标不是末尾, 则将它和末尾下标交换, 并更新v2i字典self.arr[i], self.arr[end] = self.arr[end], self.arr[i]self.v2i[self.arr[i]] = i# 这样只需要O(1)时间移除数组末尾元素和v2i字典对应项即可self.arr.pop()del self.v2i[val]return Truereturn Falsedef getRandom(self) -> int:"""Get a random element from the set."""# 使用randrange获取[0,n)的随机下标i = random.randrange(len(self.arr))return self.arr[i]
大家可以在下面这些地方找到我~😊
我的 GitHub
我的 Leetcode
我的 CSDN
我的知乎专栏
我的头条号
我的牛客网博客
我的公众号: 算法精选, 欢迎大家扫码关注~😊
相关文章:

Leetcode 剑指 Offer II 030. 插入、删除和随机访问都是 O(1) 的容器
题目难度: 中等 原题链接 今天继续更新 Leetcode 的剑指 Offer(专项突击版)系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~ 题目描述 设计一个支持在平均 时间复杂度 O(1) 下,执行以下操作…...

django实现读取数据导出生成excel表格
目录 一、简单示例: 1.创建文件对象: 2.添加工作表: 3.写入数据: 二、实践出真理 需要先安装xlwt模块 pip install -i https://pypi.douban.com/simple xlwt一、简单示例: import xlwt# 创建一个Excel文件对象 …...

DevOps系列文章之 Docker-compose
一,Docker-compose全集 1,Docker-compose简介 Docker-Compose项目是Docker官方的开源项目,负责实现对Docker容器集群的快速编排。 Docker-Compose将所管理的容器分为三层,分别是工程(project),…...
Vue Router入门:轻松构建单页应用程序
Vue.js是一种流行的前端JavaScript框架,可以让开发人员轻松构建动态用户界面。Vue.js的一个关键特性是其路由系统,它使得开发人员可以轻松创建具有多个视图和页面的单页应用程序(SPA)。在本文中,我们将探讨如何使用Vue Router在Vue.js中构建SPA。我们将介绍如何安装和配置…...

ITSM 如何帮助制造业企业
ITSM在现代制造业中的作用 在过去的几年中,制造业已经看到了快速的数字化,以智能制造技术改进生产技术。在工业4.0和工业5.0的推动下,制造商正在摆脱陈旧 以及利用物联网、人工智能、机器学习和大数据等先进技术的互联智能制造系统ÿ…...
leecode
leecode20,有效的括号,栈 class Solution:def isValid(self, s: str) -> bool:def check(ch1,ch2):if ch1 [ and ch2 ]:return Trueelif ch1 ( and ch2 ):return Trueelif ch1 { and ch2 }:return Trueelse:return Falsestack []for i in ran…...
2023-06-09 LeetCode每日一题(修改图中的边权)<未来补全>
2023-06-09每日一题 一、题目编号 2699. 修改图中的边权二、题目链接 点击跳转到题目位置 三、题目描述 给你一个 n 个节点的 无向带权连通 图,节点编号为 0 到 n - 1 ,再给你一个整数数组 edges ,其中 edges[i] [ai, bi, wi] 表示节点…...
Linux 应用程序信号量使用实战
背景 在项目实施过程中,有个机制需要做两个线程之间的同步。 具体需求如下: 首先,线程1需要把资源读取到缓存 其次,线程2才可以操作这块缓存 上述两个动作顺序交替重复。 思路 使用信号量解决思路,申请两个信号…...

【Java多线程进阶】synchronized工作原理
前言 本期讲解 synchronized 工作的原理以及常见的锁优化机制,相信大家在看完这篇博文后对 synchronized 工作流程有一定的理解。话不多说,让我们快速进入学习吧~ 目录 1. 锁的工作流程 2. 偏向锁 3. 轻量级锁和重量级锁 3.1 轻量级锁 3.2 重量级锁…...

C语言经典题目(三)
C站的小伙伴们,大家好呀!😊😊✨✨这一篇是C语言之经典题目篇,除程序设计,还有一些不错的程序分析,快来和我一起进入C语言的世界吧!✨✨✨ 💕C语言其他刷题篇在这里哦&…...

九、(补充文章四)Arcgis实现深度学习训练样本数据的批量制作——只靠原图+shp如何批量制作样本图片
之前写了一些个深度学习系列文 其中先是单张样本的制作方法 最后通过构造模型批量处理 大大提高了生成样本的速度 四、Arcgis实现深度学习河流训练样本数据的制作(使用软件批量获取样本图片)——对已经获取到的完整面状样本数据进行处理 但是这个方法不仅仅需要shp和原图 还需要…...

MKS SERVO4257D 闭环步进电机_系列8 CAN通讯示例
第1部分 产品介绍 MKS SERVO 28D/35D/42D/57D 系列闭环步进电机是创客基地为满足市场需求而自主研发的一款产品。具备脉冲接口和RS485/CAN串行接口,支持MODBUS-RTU通讯协议,内置高效FOC矢量算法,采用高精度编码器,通过位置反馈&a…...

UnityVR--组件9--视频组件VideoPlayer
目录 前言 参数解释 RenderMode渲染方式 VideoPlayer类中的API 前言 在之前的VR场景中已经使用过VideoPlayer播放视频(Unity.UI的交互(6)-播放视频),不过在VR中设置是有些不同的,这里更详细地说明一下V…...
Java 深拷贝和浅拷贝
Java 中的深拷贝和浅拷贝是针对对象复制而言的。 浅拷贝(Shallow Copy) 当对象进行浅拷贝时,只会复制对象本身和其中的基本数据类型属性,而不会复制引用对象的实际内容。具体而言,浅拷贝只会创建一个新的对象&#x…...
[ruby on rails] docker
docker安装 ubuntu14.04后自带docker安装包,可以直接安装 sudo apt-get updatesudo apt-get install -y docker.io# 安装后启动sudo service docker start查看docker信息 docker infodocker命令 sudo service docker start sudo service docker stop sudo servic…...

网络协议——STP协议是什么?是如何实现的?
作者:Insist-- 个人主页:insist--个人主页 作者会持续更新网络知识和python基础知识,期待你的关注 目录 一、STP协议是什么 二、为什么需要STP协议 三、STP的实现过程 编辑 1、选举跟桥 2、给非跟桥交换机选举跟端口 3、给每个网段选…...

【C++】智能指针 学习总结 |std::shared_ptr |std::unique_ptr | std::weak_ptr
文章目录 前言一、智能指针介绍二、普通指针和智能指针的比较案例三、std::shared_ptr四、std::unique_ptr五、std::weak_ptr六、std::shared_ptr |std::unique_ptr | std::weak_ptr三大智能指针的区别 前言 参考答案:chatgpt 一、智能指针介绍 智能指针是C的一种…...
iptables防火墙
文章目录 一.linux防火墙基础1.linux 包过滤防火墙概述1.1netfilter1.2 iptables 2.包过滤的工作层次2.1 通信的五元素和四元素 3.iptables 的表、链结构3.1 规则链3.2 默认包括5种规则链3.3 规则表3.4 默认包括4个规则表 二.数据包过滤的匹配流程1.规则表之间的顺序2.规则链之…...

properties、yaml作为配置文件的特点
说明:在软件开发中,经常需要把一些配置写在文件中,如数据库配置、MyBatis配置等。这样,后续如果数据库参数有改动,就可以避免直接对代码做修改,只要修改配置文件中关于数据库的配置。关于配置文件的选择&am…...

JavaSE-03 【流程控制语句】
文章目录 JavaSE-03 【流程控制语句】第一章 流程控制1.1 流程概述1.2 顺序结构 第二章 判断语句2.1 判断语句---if2.2 判断语句---if...else2.3 判断语句---if...else if ... else 第三章 选择语句3.1 选择语句--switch3.2 case的穿透性 第四章 循环语句4.1 循环概述4.2 循环语…...

7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...

微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...

Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...

C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...

有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...

GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...