leetcode381. Insert Delete GetRandom O(1) - Duplicates allowed

news/2024/9/9 13:51:37

题目要求

Design a data structure that supports all following operations in average O(1) time.Note: Duplicate elements are allowed.
insert(val): Inserts an item val to the collection.
remove(val): Removes an item val from the collection if present.
getRandom: Returns a random element from current collection of elements. The probability of each element being returned is linearly related to the number of same value the collection contains.
Example:// Init an empty collection.
RandomizedCollection collection = new RandomizedCollection();// Inserts 1 to the collection. Returns true as the collection did not contain 1.
collection.insert(1);// Inserts another 1 to the collection. Returns false as the collection contained 1. Collection now contains [1,1].
collection.insert(1);// Inserts 2 to the collection, returns true. Collection now contains [1,1,2].
collection.insert(2);// getRandom should return 1 with the probability 2/3, and returns 2 with the probability 1/3.
collection.getRandom();// Removes 1 from the collection, returns true. Collection now contains [1,2].
collection.remove(1);// getRandom should return 1 and 2 both equally likely.
collection.getRandom();

设计一个数据结构,支持能够在O(1)的时间内完成对数字的插入,删除和获取随机数的操作,允许插入重复的数字,同时要求每个数字被随机获取的概率和该数字当前在数据结构中的个数成正比。

强烈建议先看一下这个问题的基础版本,传送门在这里。

思路和代码

遵循之前基础版本的思路,当解决这种问题的时候我们会用数组和hashmap来做位置的存储,从而更新的时候无需检索。但是在这题的情境下,存在一个问题,举个例子:
假如现在插入1,2,3,3,4,3,3
此时的map中应当是如下:1:[0] 2:[1] 3:[2,3,5,6] 4:[4]
我们先执行删除1,按照之前的规则,我们会删除数组中最后一个元素,并将其值移动到这个位置上map应当被更新为2:[1] 3:[2,3,5,0] 4:[4]
接着我们再删除2,此时虽然最后一个元素还是3,但是这个3在位置数组中的位置却是需要O(n)的时间来查询的,这就违反了O(1)的删除时间复杂度。

网上有一些java实现采用OrderSet来解决,这是不合理的。因为有序堆本质上底层是一个最大堆或最小堆,它的插入和删除操作都需要O(lgn)的时间复杂度来完成

这里我们采用的方式是继续冗余,即我们在插入每一个元素的时候,同时记录该元素在下标数组中的位置,举个例子:
先插入1,则map的值为[1:[0]],list的值为[[1,0]] 此处的0代表1这个值在下标数组[0]中位于第0个位置上。
在插入2,则map的值为[1:[0], 2:[1]], list的值为[[1,0],[2,0]]
再插入1,此时map=[1:[0, 2], 2:[1], list的值为[[1,0],[2,0],[1,1]]
此时删除2,同理,我们还是会将数组中最后一个元素的值替换在删除掉元素的位置,此处我们从map中得出2最后一次在数组中出现的下标为1,我们需要将最后位置上的1替换掉当前2的值,之后我们还能从数组中得知,1这个数字它对应的位置下标的索引为2,因此我们再将map[1]map[1][2]的值替换为2所在的新的位置,即1。此时的map=[1:[0, 1], 2:[] list=[[1,0], [1,1]]

代码如下:

public class InsertDeleteGetRandomDuplicatesallowed_381 {private List<Pair> list;private Map<Integer, List<Integer>> index;/** Inserts a value to the collection. Returns true if the collection did not already contain the specified element. */public InsertDeleteGetRandomDuplicatesallowed_381() {list = new ArrayList<>();index = new HashMap<>();}public boolean insert(int val) {boolean contains = true;if(!index.containsKey(val) || index.get(val).isEmpty()) {contains = false;}List<Integer> tmp = index.getOrDefault(val, new ArrayList<>());tmp.add(list.size());index.put(val, tmp);list.add(new Pair(val,  tmp.size()-1));return !contains;}/** Removes a value from the collection. Returns true if the collection contained the specified element. */public boolean remove(int val) {if(!index.containsKey(val) || index.get(val).isEmpty()) {return false;}List<Integer> tmp = index.get(val);int position = tmp.remove(tmp.size()-1);if(position != list.size()-1) {Pair lastPair = list.get(list.size()-1);int lastValue = lastPair.value;            List<Integer> lastValuePositions = index.get(lastValue);lastValuePositions.set(lastPair.position, position);list.set(position, lastPair);}list.remove(list.size()-1);return true;}/** Get a random element from the collection. */public int getRandom() {int position = (int)Math.floor((Math.random() * list.size()));return list.get(position).value;}public static class Pair{int value;int position;public Pair(int value, int position) {this.value = value;this.position = position;}}}

http://lihuaxi.xjx100.cn/news/235372.html

相关文章

iOS分析崩溃日志

前言 iOS分析定位崩溃问题有很多种方式&#xff0c;但是发布到AppStore的应用如果崩溃了&#xff0c;我们该怎么办呢&#xff1f;通常我们都会在系统中接入统计系统&#xff0c;在系统崩溃的时候记录下崩溃日志&#xff0c;下次启动时将日志发送到服务端&#xff0c;比较好的第…

JavaScript数据结构与算法——字典

1.字典数据结构 在字典中&#xff0c;存储的是【键&#xff0c;值】对&#xff0c;其中键名是用来查询特定元素的。字典和集合很相似&#xff0c;集合以【值&#xff0c;值】的形式存储&#xff0c;字典则是用【键&#xff0c;值】对的形式存储。字典也称作映射。 2.创建字典 f…

2016cocoapods安装流程及使用

一&#xff1a;参考安装流程&#xff1a;http://blog.csdn.NET/showhilllee/article/details/38398119/。 二&#xff1a;我的安装步骤。 1:安装cocoapods需要ruby&#xff0c;先查看ruby环境是不是最新版本。如果不是最新版本&#xff0c;需要先升级到最新版本。在终端输入以下…

JS异步编程之callback

为什么 JS 是单线程&#xff1f; 众所周知&#xff0c;Javascript 语言的执行环境是"单线程"&#xff08;single thread&#xff09;。 所谓"单线程"&#xff0c;就是指一次只能完成一件任务。如果有多个任务&#xff0c;就必须排队&#xff0c;前面一个任…

Docker学习笔记_安装ActiveMQ

一、实验环境 1、宿主机OS:Win10 64位 2、虚拟机OS:Ubuntu18.04,虚拟机名称&#xff1a;Ubuntu18VM1&#xff0c;虚拟机IP:192.168.8.25 3、操作账号 &#xff1a;Docker 4、在虚拟机上已安装Docker 二、安装 简要步骤&#xff1a; 1.搜索镜像 sudo …

MBProgressHUD 使用详解

MBProgressHUD是一个显示HUD窗口的第三方类库&#xff0c;用于在执行一些后台任务时&#xff0c;在程序中显示一个表示进度的loading视图和两个可选的文本提示的HUD窗口。我想最多是应用在加载网络数据的时候。其实苹果官方自己有一个带有此功能的类UIProgressHUD&#xff0c;只…

Google Earth Engine(GEE)——不同时期的光谱信息差异

ee.Image.spectralDistance 算法,它可以用于我的研究目的。我想提取图像之间光谱距离较大的年份。所以这个想法是: 1. 在image1-image2, image2-image3, image3-image4...之间连续运行ee.Image.spectralDistance算法,从第一张图片到最后一张。 2.要求更大的价值。 3. 提取…

LeetCode-135-Candy

算法描述&#xff1a; There are N children standing in a line. Each child is assigned a rating value. You are giving candies to these children subjected to the following requirements: Each child must have at least one candy.Children with a higher rating get…