常数时间删除-查找数组中的任意元素

380. O(1) 时间插入、删除和获取随机元素

710. 黑名单中的随机数

提出思路

简单的梳理一下,对于「删除」「查找」「插入」操作,不同的数据结构的时间复杂度

 删除查找插入
数组O(n)O(n)O(1)
有序数组O(n)O(lgn)O(n)
链表O(n)O(n)O(1)
有序链表O(n)O(n)O(n)
二叉树最坏O(n)O(n)O(n)
二叉树一般O(n)O(n)O(n)
平衡树O(lgn)O(lgn)O(lgn)
哈希表O(1)O(1)O(1)

如果要实现常数时间复杂度内的操作,仅仅使用单个数据结构满足不了我们的需求

下面提供一种思路「当我们需要删除某一个元素的时候,快速获取该元素的下标 index,然后把该元素和 List 中最后一个元素交换,最后删除 List 最后一个元素即可」

把要删除的元素和最后一个元素交换,免去了移动删除元素后的所有元素

如何快速获得删除元素的下标呢??? -> Map<value, index>

小技巧:如果要等概率的随机获取一个元素,那么可被选择的元素必须是连续存储,然后调用random.nextInt(n),随机等概率生成[0, n)内的一个数。更多关于Random的用法可见 Random 类

O(1) 时间插入、删除和获取随机元素

题目详情可见 O(1) 时间插入、删除和获取随机元素

直接给出详细代码:(结合注释看 👀)

黑名单中的随机数

题目详情可见 黑名单中的随机数

对于例子:n = 10, blacklist = [3, 5, 8, 9]

我们的思路就是利用Mapblacklist中的元素全部映射到最后面去,即[0, 6)存放非黑名单内的元素,[6, 10)存放黑名单内的元素

需要注意的一点是:我们并非真正意义上的把元素移到最后,而是通过Map映射,其实元素的位置是没有改变的

6

如上图所示,元素 3 和 5 在非黑名单位置上,所以我们需要按序把这两个元素映射到 7 和 6,即map.put(3, 7); map.put(5, 6)

而我们随机获得非黑名单内的元素,直接对区间[0, 6)随机即可。如果刚好随机到了 3 或 5,那么我们只需要返回map.get(3) = 7 or map.get(5) = 6即可

pick()实现代码如下:

那如何构造上述的映射呢???

直接给出详细代码:(结合注释看 👀)