LeetCode 哈希表 380. 常数时间插入、删除和获取随机元素(设计数据结构 List HashMap底层 时间复杂度)

比起之前那些问计数哈希表的题目,这道题好像更接近哈希表的底层机制。
java中hashmap的实现是通过List<Node>,即链表的list,如果链表过长则换为红黑树,如果容量不足(装填因子下)则扩充数组容量。解决冲突的方式是直接接在对应位置的链表上。
首先看看哈希表几个操作的时间复杂度:
HashMap的新增:
- 计算key的哈希值
- 哈希值作为index,找到对应的数组位置
- 如果数组位置为空,直接存入
- 如果数组位置不为空,遍历该链表,插入末尾
这里考虑理想情况(无冲突),时间复杂度为O1
HashMap的删除,查询都是一样的理解,如果没得冲突,都是O1的复杂度。
如果冲突,可能出现On情况(链表),Ologn情况(红黑树)
返回随机元素,这个则不好实现,因为HashMap是无序的,又没得类似List那样的索引,很难返回一个random的值。
接着考虑的一个方式就是,能不能把HashMap的key以0,1。。。的方式存到一个数组中,用random得到一个随机的序号,然后在通过序号去找。
然而这里犯了一个错误。这样的方式其实无疑与把这个HashMap变成了一个LIst。当然插入是O1,但是删除则不好操作了。
第二个想法是Hashset,但问题其实也一样,这是一个无序的set,没办法搞random。这里的无序set指的是插入进去之后放到的位置就是hash算出来的位置,显然无法用随机的方式使得每一个元素返回的概率相同。
第三个想法则是List作为基础,再用HashMap来补缺陷。
LIst的操作复杂度:
- append,直接在尾端加,O1
- pop,直接去掉尾端,O1
- 特定位置插入/删除,都需要萝卜挪坑,On
- 访问特定位置元素,索引直接访问,O1
- 查,要跑一遍整个数组,On
所以Random很好做到,其余的需要用append和pop搞事
append需要去重,我们把索引和值分别存入HashMap作为辅助
这样要插入时,先用HashMap判断有无(O1),然后直接插尾端(O1)
删除稍麻烦一些,我们如果直接删除真正位置,则需要挪位置变为On
所以用HashMap找到位置后,将该位置和List末尾做交换,然后PoP,这样就是O1了。
class RandomizedSet {
Map<Integer, Integer> dict;
List<Integer> list;
Random rand = new Random();
/** Initialize your data structure here. */
public RandomizedSet() {
dict = new HashMap();
list = new ArrayList();
}
/** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
public boolean insert(int val) {
if (dict.containsKey(val)) return false;
dict.put(val, list.size());
list.add(list.size(), val);
return true;
}
/** Removes a value from the set. Returns true if the set contained the specified element. */
public boolean remove(int val) {
if (! dict.containsKey(val)) return false;
// move the last element to the place idx of the element to delete
int lastElement = list.get(list.size() - 1);
int idx = dict.get(val);
list.set(idx, lastElement);
dict.put(lastElement, idx);
// delete the last element
list.remove(list.size() - 1);
dict.remove(val);
return true;
}
/** Get a random element from the set. */
public int getRandom() {
return list.get(rand.nextInt(list.size()));
}
}
LeetCode 哈希表 380. 常数时间插入、删除和获取随机元素(设计数据结构 List HashMap底层 时间复杂度)的更多相关文章
- Java实现 LeetCode 380 常数时间插入、删除和获取随机元素
380. 常数时间插入.删除和获取随机元素 设计一个支持在平均 时间复杂度 O(1) 下,执行以下操作的数据结构. insert(val):当元素 val 不存在时,向集合中插入该项. remove( ...
- LeetCode 381. Insert Delete GetRandom O(1) - Duplicates allowed O(1) 时间插入、删除和获取随机元素 - 允许重复(C++/Java)
题目: Design a data structure that supports all following operations in averageO(1) time. Note: Duplic ...
- LeetCode380 常数时间插入、删除和获取随机元素
LeetCode380 常数时间插入.删除和获取随机元素 题目要求 设计一个支持在平均 时间复杂度 O(1) 下,执行以下操作的数据结构. insert(val):当元素 val 不存在时,向集合中插 ...
- Java实现 LeetCode 381 O(1) 时间插入、删除和获取随机元素 - 允许重复
381. O(1) 时间插入.删除和获取随机元素 - 允许重复 设计一个支持在平均 时间复杂度 O(1) 下, 执行以下操作的数据结构. 注意: 允许出现重复元素. insert(val):向集合中插 ...
- 381. O(1) 时间插入、删除和获取随机元素 - 允许重复
381. O(1) 时间插入.删除和获取随机元素 - 允许重复 LeetCode_381 题目详情 题解分析 代码实现 package com.walegarrett.interview; impor ...
- Leetcode 381. O(1) 时间插入、删除和获取随机元素 - 允许重复
1.题目描述 设计一个支持在平均 时间复杂度 O(1) 下, 执行以下操作的数据结构. 注意: 允许出现重复元素. insert(val):向集合中插入元素 val. remove(val):当 va ...
- Leetcode 380. 常数时间插入、删除和获取随机元素
1.题目描述 设计一个支持在平均 时间复杂度 O(1) 下,执行以下操作的数据结构. insert(val):当元素 val 不存在时,向集合中插入该项. remove(val):元素 val 存在时 ...
- LeetCode 380. Insert Delete GetRandom O(1) 常数时间插入、删除和获取随机元素(C++/Java)
题目: Design a data structure that supports all following operations in averageO(1) time. insert(val): ...
- [Swift]LeetCode380. 常数时间插入、删除和获取随机元素 | Insert Delete GetRandom O(1)
Design a data structure that supports all following operations in averageO(1) time. insert(val): Ins ...
随机推荐
- 几种常见的dfs模板
判断从v出发是否能走到终点 bool dfs(v){ if(v is 终点)return true; if(v is 旧点)return false; 将v标记为旧点: 对和v相邻的每个节点u{ if ...
- 5.keras-Dropout剪枝操作的应用
keras-Dropout剪枝操作的应用 1.载入数据以及预处理 import numpy as np from keras.datasets import mnist from keras.util ...
- k8s学习-资源清单
4.kubernetes使用 4.1.资源清单 api 文档.api 描述 4.1.2.说明 必须存在的属性 主要的对象 额外的参数项 例子 vim my-app.yml apiVersion: v1 ...
- sql 获取当前时间的前一天,不加时分秒
select convert(datetime,convert(char(20),dateadd(day,-1,getdate()),102)) -1 为减去天数 getdate 为 获取当前时间
- 【JAVA进阶架构师指南】之五:JVM性能调优
前言 首先给大家说声对不起,最近属实太忙了,白天上班,晚上加班,回家还要收拾家里,基本每天做完所有事儿都是凌晨一两点了,没有精力再搞其他的了. 好了,进入正题,让我们来聊聊JVM篇最后一个章节 ...
- 【转载】自动化魔方求解器的Bug——选择合适的色彩空间
目录 1. 准备工作-- 2. RGB颜色空间 3. LAB色彩空间 4. YCrCb色彩空间 5. HSV色彩空间 Color spaces in OpenCV (C++ / Python) 几天前 ...
- 在VisualStudio中为GUI程序添加console
1.使用WINDOWS提供的一系列ReadConsole,WriteConsole等API来完成这个功能,具体参见MSDN HANDLE hOut = GetStdHandle(STD_OUTPUT_ ...
- drf之框架基础
(一)drf基础 全称:django-rest framework 接口:什么是接口.restful接口规范(协议) CBV(基于FBV的基础上形成).CBV生命周期源码----基于restful规范 ...
- vue事件修饰符与按钮修饰符
事件修饰符:(当事件无需传参数时可直接写成以下形式,有参数时则为@click.stop="handleLiClick($event)") stop:阻止事件冒泡行为(子元素被点击, ...
- position两种绝对定位的区别
position绝对定有两种,分别为absolute和fixed 一.共同点: 1.改变行内元素的呈现方式,display被置为inline:block 2.让元素脱离普通流,不占据空间 3.默认会覆 ...