当前位置:网站首页>常数时间删除/查找数组中的任意元素
常数时间删除/查找数组中的任意元素
2022-06-12 12:28:00 【Joey Liao】
实现随机集合
这是力扣第 380 题「 常数时间插入、删除和获取随机元素」,看下题目:
就是让我们实现如下一个类:
class RandomizedSet {
public:
/** 如果 val 不存在集合中,则插入并返回 true,否则直接返回 false */
bool insert(int val) {
}
/** 如果 val 在集合中,则删除并返回 true,否则直接返回 false */
bool remove(int val) {
}
/** 从集合中等概率地随机获得一个元素 */
int getRandom() {
}
}
难度在于2点:
- 插入,删除,随机获取元素三个操作的时间复杂度都是O(1)
getRandom方法返回的元素必须是等概率返回的
我们先来分析一下:对于插入,删除,查找这几个操作,哪种数据结构的时间复杂度是 O(1)?
HashSet 肯定算一个对吧。哈希集合的底层原理就是一个大数组,我们把元素通过哈希函数映射到一个索引上;如果用拉链法解决哈希冲突,那么这个索引可能连着一个链表或者红黑树。
那么请问对于这样一个标准的 HashSet,你能否在 O(1) 的时间内实现 getRandom 函数?
其实是不能的,因为根据刚才说到的底层实现,元素是被哈希函数「分散」到整个数组里面的,更别说还有拉链法等等解决哈希冲突的机制,所以做不到 O(1) 时间「等概率」随机获取元素。
LinkedHashSet 只是给 HashSet 增加了有序性,依然无法按要求实现我们的 getRandom 函数,因为底层用链表结构存储元素的话,是无法在 O(1) 的时间内访问某一个元素的。
根据上面的分析,对于 getRandom 方法,如果想「等概率」且「在 O(1) 的时间」取出元素,一定要满足:底层用数组实现,且数组必须是紧凑的。
所以,如果我们想在 O(1) 的时间删除数组中的某一个元素 val,可以先把这个元素交换到数组的尾部,然后再 pop 掉。
交换两个元素必须通过索引进行交换对吧,那么我们需要一个哈希表 valToIndex 来记录每个元素值对应的索引。
class RandomizedSet {
//<val,index>记录每个元素对应在 nums 中的索引
private HashMap<Integer,Integer> valToIndex;
// 存储元素的值
private List<Integer> list;
private Random random=new Random();
public RandomizedSet() {
valToIndex=new HashMap<>();
list=new ArrayList<>();
}
public boolean insert(int val) {
// 若 val 已存在,不用再插入
if (valToIndex.containsKey(val)) return false;
// 若 val 不存在,插入到 nums 尾部,
// 并记录 val 对应的索引值
valToIndex.put(val,list.size());
list.add(val);
return true;
}
public boolean remove(int val) {
// 若 val 不存在,不用再删除
if(!valToIndex.containsKey(val)) return false;
// 先拿到 val 的索引
int removePo=valToIndex.get(val);
int lastVal=list.get(list.size()-1);
// 将最后一个元素对应的索引修改为 index
valToIndex.put(lastVal,removePo);
// 将位置val设置为最后一个元素
list.set(removePo,lastVal);
//删除最后一个位置
valToIndex.remove(val);
list.remove(list.size()-1);
return true;
}
public int getRandom() {
return list.get(random.nextInt(list.size()));
}
}
至此,这道题就解决了,每个操作的复杂度都是 O(1),且随机抽取的元素概率是相等的。
避开黑名单的随机数
有了上面一道题的铺垫,我们来看一道更难一些的题目,力扣第 710 题「 黑名单中的随机数」

题目要求,在 pick 函数中应该尽可能少调用随机数生成函数 rand()。
思路:还是使用map存储黑名单中元素和对应的映射
class Solution {
int size = 0;
HashMap<Integer, Integer> map = new HashMap<>();
public Solution(int n, int[] blacklist) {
size = n - blacklist.length;
//map存放blackList中的元素
for(int item : blacklist){
map.put(item, -1);
}
int last = n - 1;
for(int item : blacklist){
//若本来就在后面就不动
if(item >= size){
continue;
}
//不然找到最后面不在blacklist中的位置
while(map.containsKey(last)){
last--;
}
//将黑名单元素存在该位置
map.put(item, last);
last--;
}
}
public int pick() {
int index = (int)(Math.random()*size);
return map.getOrDefault(index, index);
}
}
边栏推荐
- 爱可可AI前沿推介(6.12)
- NDT registration principle
- Difference between Definition and Declaration
- 【vim】vim插件YouCompleteMe配置文件
- [译] Go语言测试进阶版建议与技巧
- JS pre parsing, object, new keyword
- Boot entry directory
- C语言进阶篇——万字详解指针和qsort函数
- Matlab install license manager error -8
- Examples of Cartesian product and natural connection of relational algebra
猜你喜欢

Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference

Time series database - incluxdb2 docker installation

Problems encountered in installing canvas and errors encountered in running the project

wx. Login and wx Getuserprofile simultaneous use problem

拿来就能用的网页动画特效,不来看看?

Video speed doubling in PC browser

Point cloud registration -- GICP principle and its application in PCL

InfluxDB2.x 基准测试工具 - influxdb-comparisons

Lightweight ---project

MySQL 分区表介绍与测试
随机推荐
The direction of this
回溯法, 八皇后
【您编码,我修复】WhiteSource正式更名为Mend
一个ES设置操作引发的“血案”
[译] QUIC Wire Layout Specification - Packet Types and Formats | QUIC协议标准中文翻译(2) 包类型和格式
[translation] go references - the go memory model | memory model for Chinese translation of official golang documents
Introduction, installation and use of core JS
ITK 多阶段配准
银行布局元宇宙:数字藏品、数字员工成主赛道!
vtk 图像序列鼠标交互翻页
Invalid date of moment conversion timestamp
itk 多分辨率图像 itk::RecursiveMultiResolutionPyramidImageFilter
Difference between Definition and Declaration
鸡尾酒排序
JS string array converted to numeric array and how to add the numbers in the array
Quic wire layout specification - packet types and formats | quic protocol standard Chinese translation (2) package type and format
The difference between bind, call and apply, and the encapsulation of bind()
Iterator, generator generator details
【数据库】navicat --oracle数据库创建
Ace configures IPv6, vs statically compiles ace Library