Java每日一题——>剑指 Offer II 030. 插入删除和随机访问都是 O 的容器
Posted stormzhuo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java每日一题——>剑指 Offer II 030. 插入删除和随机访问都是 O 的容器相关的知识,希望对你有一定的参考价值。
这是LeetCode上的 [030,插入、删除和随机访问都是 O(1) 的容器],难度为 [中等]
题目
设计一个支持在平均 时间复杂度 O(1) 下,执行以下操作的数据结构:
- insert(val):当元素 val 不存在时返回 true ,并向集合中插入该项,否则返回 false 。
- remove(val):当元素 val 存在时返回 true ,并从集合中移除该项,否则返回 false 。
- getRandom:随机返回现有集合中的一项。每个元素应该有 相同的概率 被返回。
题解
思路分析
根据题意的前两个条件,插入和删除要求时间复杂度为O(1),很容易想到用哈希表,哈希表的插入,删除,查找一个元素都只需要O(1)的时间,题意的最后一个条件随机返回一个数据,且要求返回的每个数据概率都相等,显然哈希表不满足这个条件,下面通过在java中实现哈希表的HashMap为例来说明
底层采用的是数组+链表+红黑树,数组的每一个元素除存放元素外,还有一个引用变量用于指向下一个元素(链表)。它查找元素是通过元素的哈希值求余数(散列函数)的方式确定元素在数组的位置,数组的位置可能存在一个链表来存放其他元素(哈希值相同),故不能等概率返回其中的每一个数值。
等概率的返回每个元素,显然数组满足这个条件,假设数组长度为n,则每个元素被返回的概率为1/n
综上,我们应该设计一个包含哈希表,数组的的容器
由于需要等概率的返回每个元素,故数据只能存放在数组中,可以使用java的动态数组ArrayList,则它满足第1个和第3个条件,但他不满足第2个条件,例如删除元素它需要做下面两个操作
- 遍历数组找到要删除的元素,当删除最后一个元素时,需要遍历完数组,时间复杂度为O(n),当删除第一个元素时,为O(1)
- 当找到要删除的元素时,如果删除的是最后一个元素,时间复杂度为O(1),当删除第一个元素时,需要把第一个元素的后面所有元素前移,时间复杂度为O(n)
综上,数组的删除元素的时间复杂度为O(n),因此我们需要借助HashMap来解决上面两个问题
解决第一个问题
使用HashMap的键来存放元素,值来存放元素在数组的索引,因此当删除元素时,不需要遍历数组找到删除元素,通过map键即可获取删除元素的索引,时间复杂度为O(1)
解决第二个问题
当在数组找到删除元素的位置时,我们只需把它的值体换成数组的最后一个元素的值,然后删除最后一个元素,而数组删除最后一个元素的时间复杂度为O(1),不需要移动元素。由于数组的最后一个元素的值赋给了删除元素的位置,因此需要改变HashMap的最后一个元素的索引
代码实现
public class RandomizedSet
private HashMap<Integer, Integer> numToLocation;
private ArrayList<Integer> nums;
Random random = new Random();
public RandomizedSet()
numToLocation = new HashMap<>();
nums = new ArrayList<>();
public boolean insert(Integer val)
// 通过map判断插入的元素是否存在与数组
if (numToLocation.containsKey(val))
return false;
// 不存在执行逻辑
// 记录插入元素在数组中的位置,每次插入都是在数组尾部插入,故索引为数组的长度
numToLocation.put(val, nums.size());
// 向数组尾部添加元素
nums.add(val);
return true;
public boolean remove(Integer val)
// 通过map判断删除的元素是否存在与数组中
if (!numToLocation.containsKey(val))
return false;
// 存在执行逻辑
// 通过map获取删除元素在数组的索引
Integer location = numToLocation.get(val);
// 获取数组最后一个元素
Integer lastNum = nums.get(nums.size() - 1);
// 把数组中要删除的元素的值替换成数组的最后一个元素
nums.set(location, lastNum);
// 删除数组最后一个元素
nums.remove(nums.size() - 1);
// 通过map把数组最后一个元素的索引改成删除元素的索引
numToLocation.put(lastNum, location);
// 把要删除元素的索引从map中删除
numToLocation.remove(val);
return true;
public Integer getRandom()
// 假设数组长度为n,则生成[0 ~ n-1]之间的随机数
int i = random.nextInt(nums.size());
return nums.get(i);
以上是关于Java每日一题——>剑指 Offer II 030. 插入删除和随机访问都是 O 的容器的主要内容,如果未能解决你的问题,请参考以下文章
Java每日一题——>剑指 Offer II 035. 最小时间差(三解,蛮力,排序,哈希)
Java每日一题——> 剑指 Offer II 028. 展平多级双向链表
Java每日一题——>剑指 Offer II 027. 回文链表
Java每日一题——>剑指 Offer II 030. 插入删除和随机访问都是 O 的容器