LeetCode哈希表(哈希集合,哈希映射)
文章目录
- 哈希表
- 1.原理
- 2.复杂度分析
- 题目&推荐列表
- 哈希集合的应用
- 0.常用解题模板
- 1.lc217 存在重复元素
- 2.lc136 只出现一次的数字
- 3.快乐数
- 哈希映射的应用
- 0.常用解题模板
- 1. lc1 两数之和
- 2. lc387 字符串中的第一个唯一字符
- 3. lc350 两个数组的交集II
- 4. lc219 存在重复元素II
- 5.lc13 罗马数字转整数
- 6. lc1207 独一无二的出现次数
- 7. lc1365 有多少小于当前数字的数字
哈希表
哈希表是一种使用哈希函数组织数据,以支持快速插入和搜索的数据结构。
有两种不同类型的哈希表:哈希集合和哈希映射。
- 哈希集合是集合数据结构的实现之一,用于存储非重复值。
- 哈希映射是映射 数据结构的实现之一,用于存储(key, value)键值对。
1.原理
简单介绍下:
哈希表的关键思想是使用哈希函数将键映射到存储桶。更确切地说
- 当插入一个新的键时,哈希函数将决定该键应该分配到哪个桶中,并将该键存储在相应的桶中;
- 当想要搜索一个键时,哈希表将使用相同的哈希函数来查找对应的桶,并只在特定的桶中进行搜索
更深层次的底层原理以及如何设计哈希集合和哈希映射,可以参见 HashSet底层原理分析
lc705设计哈希集合
lc706设计哈希映射
2.复杂度分析
典型的空间换时间,查找的时间复杂度是O(1),空间复杂度是O(n)
题目&推荐列表
本文题目
题号&链接 | 分类/标签 | 难度 |
---|---|---|
1. lc217 存在重复元素 | 哈希集合 | easy |
2. lc316 只出现一次的数字 | 哈希集合, 哈希映射 | easy |
3. lc202快乐数 | 哈希集合,快慢指针 | easy |
4.lc1 两数之和 | 哈希映射 | easy |
5.lc387 字符串中的第一个唯一字符 | 哈希映射 | easy |
6.lc350两个数组的交集II | 哈希映射 | easy |
7.lc219存在重复元素II | 哈希映射 | easy |
推荐习题
题号&链接 | 分类/标签 | 难度 | 题解链接 |
---|---|---|---|
1. lc349 两个数组的交集 | 两个哈希集合 | easy | 题解 |
2. lc287 寻找重复数 | 哈希集合,快慢指针 | medium | 题解 |
3. lc137 只出现一次的数字II | 哈希集合 | medium | 题解 |
4. lc260 只出现一次的数字III | 哈希表,位运算 | medium | 题解 |
5. lc599两个列表的最小索引和 | 哈希映射 | easy | 题解 |
6. lc205同构字符串 | 哈希映射 | easy | 题解 |
7. lc383 赎金信 | 哈希映射(数组) | easy | 题解 |
8. lc15 三数之和 | 排序+双指针 | medium | 题解 |
注:排序+双指针在有关哈希题目中经常可以达到奇效(包括后面的四数之和,四数相加,用哈希来做其实复杂度就很高了)
哈希集合的应用
哈希集是集合的实现之一,它是一种存储不重复值的数据结构;
所以可以 使用哈希集合来查重。
注意的几个点是:
1.底层数据结构是哈希表 ;2.没有带索引的方法;3.不包含重复元素。
对于哈希集合(HashSet)用法还不熟悉的可以看看这篇 HashSet基础入门
这里还是回顾一下主要方法:
方法 | 含义 |
---|---|
boolean add(E object) | 增加元素 |
void clear() | 清楚所有元素 |
boolean contains(Object object) | 判断集合是否含有特定元素object |
boolean isEmpty() | 判断集合是否为空 |
boolean remove(Object object) | 删除元素 |
int size() | 计算集合大小 |
0.常用解题模板
(仅供参考)
// 利用HashSet查重
boolean findDuplicates(List<T> keys) {// 首先创建一个哈希集合,T表示实际中的数据类型Set<T> hashset = new HashSet<>();// 对给定的集合或者列表进行遍历for (T key : keys) {if (hashset.contains(key)) {return true;}hashset.add(key);}return false;
}
1.lc217 存在重复元素
力扣217链接
描述:
给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 ,返回 true ;如果数组中每个元素互不相同,返回 false
示例:
输入:nums = [1,2,3,1] 输出:true
Solution:
典型的查重,运用Set的去重性(与模板高度相似)
public boolean containsDuplicate(int[] nums) {Set<Integer> set = new HashSet<>();for(int num:nums){if(set.contains(num))return true;set.add(num);}return false;}
2.lc136 只出现一次的数字
力扣136链接
描述:
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
示例:
输入: [4,1,2,1,2] 输出: 4
Solution 1: 哈希集合
public static int singleNumber1(int[] nums) {// 使用集合存储数字Set<Integer> set = new HashSet<>();// 遍历数组中的每个数字for (int num:nums) {// 如果集合中没有该数字,则将该数字加入集合if (!set.contains(num))set.add(num);// 如果集合中已经有该数字,则将该数字从集合中删除 elseset.remove(num);}// 最后剩下的数字就是只出现一次的数字return set.iterator().next();
}
Solution2:哈希映射
注意,和次数相关的题目第一反应要想到哈希映射!
public static int singleNumber2(int[] nums) {// 使用哈希表存储每个数字和该数字出现的次数Map<Integer, Integer> map = new HashMap<>();// 遍历数组即可得到每个数字出现的次数,并更新哈希表for (int num : nums) {int count = 1;if (map.containsKey(num)) {count++;map.put(num, count);// 可以直接用map.put(num,map.getordefault(x,0)+1)}map.put(num, count);}// 最后遍历哈希表,得到只出现一次的数字for (Integer key : map.keySet()) {if (map.get(key) == 1)return key;}return -1;
Solution 3:位运算(官方)
时间复杂度O(n),空间复杂度O(1)
public static int singleNumber3(int[] nums) {// 相同的数异或为0,异或具有交换律int res = nums[0];for (int i = 1; i < nums.length; i++) {res = res ^ nums[i];}return res;}
3.快乐数
力扣202链接
描述:
编写一个算法来判断一个数 n 是不是快乐数。「快乐数」 定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和;然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1;如果这个过程 结果为 1,那么这个数就是快乐数。
示例:
输入:n = 19 输出:true
Solution :
哈希集合,判断每一次新数的总和是否重复
public boolean isHappy(int n) {Set<Integer> record = new HashSet<>();// 利用 HashSet 的去重性while (n != 1 && !record.contains(n)) {record.add(n);n = getNextNumber(n);}return n == 1;}
// 先去求下一个新数
private int getNextNumber(int n) {int res = 0;while (n > 0) {int temp = n % 10;res += temp * temp;n = n / 10;}return res;}
哈希映射的应用
使用哈希映射的第一个场景是,我们需要更多的信息,而不仅仅是键。然后通过哈希映射建立key与value之间的映射关系。
对HashMap主要方法还不熟悉的可以参考这篇文章,HashMap基础入门,有对方法的解释和方法运用的示例。
0.常用解题模板
(仅供参考)
场景1:提供更多信息
ReturnType aggregateByKey_hashmap(List<Type>& keys) {// Replace Type and InfoType with actual type of your key and valueMap<Type, InfoType> hashmap = new HashMap<>();for (Type key : keys) {if (hashmap.containsKey(key)) {if (hashmap.get(key) satisfies the requirement) {return needed_information;}}// Value can be any information you needed (e.g. index)hashmap.put(key, value); }return needed_information;
}
场景2:按键聚合
ReturnType aggregateByKey_hashmap(List<Type>& keys) {// Replace Type and InfoType with actual type of your key and valueMap<Type, InfoType> hashmap = new HashMap<>();for (Type key : keys) {if (hashmap.containsKey(key)) {hashmap.put(key, updated_information);}// Value can be any information you needed (e.g. index)hashmap.put(key, value); }return needed_information;
}
1. lc1 两数之和
力扣1链接
描述:
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那两个整数,并返回它们的数组下标
示例:
输入:nums = [2,7,11,15], target = 9 输出:[0,1]
Solution:
public int[] twoSum(int[] nums, int target) {// 创建一个HashMapMap<Integer,Integer> map = new HashMap<>();// 创建一个数组,用来存储结果的两个下标int[] res = new int[2];for(int i=0;i<nums.length;i++){// tmp的含义是当前的整数所需匹配的数字,如扫描到2需要的是7(9-2)int tmp = target-nums[i];// 判断hashmap中是否存在tmp的keyif(map.containsKey(tmp)){/*存在这个值为tmp的key就说明此时的i肯定是其中一个索引,另一个索引是以tmp为key的value值*/res[0]=i;res[1]=map.get(tmp);}// 表示不存在这样的key,所以将当前数字和其下标添加到map中map.put(nums[i],i);}return res;}
2. lc387 字符串中的第一个唯一字符
力扣387链接
描述:给定一个字符串 s ,找到它的第一个不重复的字符,并返回它的索引 。不存在,返回 -1
示例:输入: s = “loveleetcode” 输出: 2
Solution1:哈希映射
使用哈希表存储频数。先用map存储字符出现的次数;然后遍历string,如果在map中找到了次数为1的时候就返回就返回对应的下标
class Solution {public int firstUniqChar(String s) {Map<Character, Integer> frequency = new HashMap<Character, Integer>();for (int i = 0; i < s.length(); ++i) {char ch = s.charAt(i);frequency.put(ch, frequency.getOrDefault(ch, 0) + 1);}for (int i = 0; i < s.length(); ++i) {if (frequency.get(s.charAt(i)) == 1) {return i;}}return -1;}
}
Solution2:数组
数组实现哈希映射(时间上要快很多)
public static int firstUniqChar(String s) {int[] a = new int[26];for(int i=0;i<s.length();i++){char chs = s.charAt(i);a[chs-'a'] ++;}for(int i=0;i<s.length();i++){char chs = s.charAt(i);if(a[chs-'a']==1)return i;}return -1;
3. lc350 两个数组的交集II
力扣350链接
(有II肯定有I,可以先做I,lc349 两个数组的交集)
描述:
给你两个整数数组 nums1 和 nums2,请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。
示例:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[4,9]
Solution:
哈希映射
在这里插入代码片
4. lc219 存在重复元素II
力扣219链接
描述:给你一个整数数组 nums 和一个整数 k ,判断数组中是否存在两个 不同的索引 i 和 j ,满足 nums[i] == nums[j] 且 abs(i - j) <= k 。如果存在,返回 true ;否则,返回 false
示例:
输入:nums = [1,2,3,1], k = 3 输出:true
Solution:
public boolean containsNearbyDuplicate(int[] nums, int k) {Map<Integer,Integer> map = new HashMap<>();for(int i=0;i<nums.length;i++){int tmp = nums[i];// 判断当前tmp是否存在与hashmap中,且要满足当前索引与之前索引差值不大于kif(map.containsKey(tmp) && i-map.get(tmp)<=k) {return true;}//如果不满足要求,就把当前元素存入hashmap中map.put(tmp,i);}return false;
5.lc13 罗马数字转整数
描述:给定一个罗马数字,将其转换成整数。
示例:输入: s = “III” 输出: 3 输入: s = “IX” 输出: 9
Solution:
用一个哈希表建立映射。然后遍历给定的字符串,判断左右罗马数字的大小,如果左边的比右边的小,就减去这个数,反之就加上。
public int romanToInt(String s) {Map<Character,Integer> helper = new HashMap<>();helper.put('I',1);helper.put('V',5);helper.put('X',10);helper.put('L',50);helper.put('C',100);helper.put('D',500);helper.put('M',1000);int len = s.length();int value=0; // 记录最后的整数for(int i=0;i<len;i++){int num = helper.get(s.charAt(i)); //获取罗马数字代表的整数// 判断是加还是减if(i<len-1 && num<helper.get(s.charAt(i+1))) value -= num;elsevalue += num;}return value;}
时间复杂度:O(n),其中 n 是字符串 s 的长度。空间复杂度:O(1)
6. lc1207 独一无二的出现次数
力扣1207链接
描述:给你一个整数数组 arr,请你帮忙统计数组中每个数的出现次数。
如果每个数的出现次数都是独一无二的,就返回 true;否则返回 false。
输入:arr = [1,2,2,1,1,3] 输出:true
Solution:
看到次数,想到哈希法。。。
(本题第一反应是用哈希映射,如果想要时间效率更高,应该采取数组来进行哈希映射)
public boolean uniqueOccurrences(int[] arr) {HashMap<Integer,Integer> map = new HashMap<>();for(int num:arr){map.put(num,map.getOrDefault(num,0)+1);}Set<Integer> set = new HashSet<>();for(int value:map.values()){if(set.contains(value))return false;elseset.add(value);}return true;}
7. lc1365 有多少小于当前数字的数字
力扣1365链接
描述:
给你一个数组 nums,对其中每个元素 nums[i],请你统计数组中比它小的所有数字的数目
输入:nums = [8,1,2,2,3] 输出:[4,0,1,1,3]
solution:
第一眼,真想暴力,两层for直接跑路~
冷静一下,仔细想想,还得是哈希(先排序后哈希,哈希用来做数值和下标的映射)
public int[] smallerNumbersThanCurrent(int[] nums) {HashMap<Integer,Integer> map = new HashMap<>();int[] res = Arrays.copyOf(nums,nums.length);Arrays.sort(res);for(int i=0;i<nums.length;i++){if(!map.containsKey(res[i])){map.put(res[i],i);}}for(int i=0;i<res.length;i++){res[i] = map.get(nums[i]);}return res;}
参考链接:
https://leetcode.cn/leetbook/read/hash-table/
LeetCode哈希表(哈希集合,哈希映射)相关推荐
- 【哈希表】(一) 设计哈希表
目录 一.设计哈希表 二.设计哈希表的关键 三.设计哈希集合 3.1 题目要求 3.2 解决过程 四.设计哈希映射 4.1 题目要求 4.2 解决过程 五.设计哈希表 - 解决方案 六.复杂度分析 - ...
- 哈希表题目:设计哈希映射
文章目录 题目 标题和出处 难度 题目描述 要求 示例 数据范围 前言 解法一 思路和算法 代码 复杂度分析 解法二 思路和算法 代码 复杂度分析 题目 标题和出处 标题:设计哈希映射 出处:706. ...
- 在java中 哈希表会经常出现哈希碰撞吗
在Java中,哈希表可能会经常出现哈希碰撞.哈希表是一种根据键(Key)来访问值(Value)的数据结构,通过哈希函数将键映射到哈希表的索引位置上.由于哈希函数的映射结果可能不唯一,不同的键可能会被映 ...
- 什么是哈希表?什么又是哈希冲突?哈希冲突的解决方法?
首先,什么是哈希表?什么又是哈希冲突? ①哈希表是基于数组的一种存储方式.它主要由哈希函数和数组构成.当要存储一个数据的时候,首先用一个函数计算数据的地址,然后再将数据存进指定地址位置的数组里面.这个 ...
- C#中的集合、哈希表、泛型集合、字典
集合ArrayList 集合:集合可以看做是数组,可以将其看成"长度可变,具有很多方法的数组".使用ArrayList,首先需要导入命名空间using.system.collect ...
- 基础数据结构(二):字典树、并查集、堆、哈希表、字符串的哈希方式、STL的常见容器及其接口
文章目录 一.字典树Trie 1 原理 2 Trie字符串统计 3 [LeetCode 208. 实现 Trie (前缀树)](https://leetcode-cn.com/problems/imp ...
- 哈希表数据结构_Java数据结构哈希表如何避免冲突
前言 一.哈希表是what? 这是百度上给出的回答: 简而言之,为什么要有这种数据结构呢? 因为我们想不经过任何比较,一次从表中得到想要搜索的元素.所以就构造出来了哈希表,通过某种函数(哈希函数)使元 ...
- e - 数据结构实验之查找五:平方之哈希表_leetcode算法之哈希表
今天该来盘一盘 哈希表 这类题目 分类别解析leetcode上的一些相关的例题路,代码采用C++与python实现. 哈希表 哈希表是一种很有用的数据结构, 其作用主要是以空间换时间, 在c++中主要 ...
- c++ map 修改value_哈希表:其实需要哈希的地方都能找到map的身影
给「代码随想录」一个星标吧! ❝ 数组和set都靠边站! ❞ 第454题.四数相加II 给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A ...
- python 哈希表_数据结构-7 哈希表
python内部查找表非常快,就是用的哈希表(hash-table)实现的. 后续实现字典集合. 怎么解决冲突? 其实一种直观的想法是如果冲突了我能不能让数组中 对应的槽变成一个链式结构呢?这就是其中 ...
最新文章
- 关于微信小程序登录授权
- Zepto源码分析-架构
- 今晚直播 | 清华大学​高天宇:对比学习及其在NLP中的应用
- pandas基本数据处理
- boost::histogram::algorithm::project用法的测试程序
- Linux系统下Configure命令参数解释说明
- NSubstitute完全手册(一)入门基础
- HDOJ5547 SudoKu
- mac地址转换_mac电脑格式转化工具
- 内容生态搜索趋势研究报告
- 庆功会(信息学奥数一本通-T1269)
- Perl文件处理示例——批量添加Copyright版权信息
- 黑马python培训视频网盘下载_黑马课堂大数据全套视频课程百度云下载
- 小程序毕设作品之微信酒店预订小程序毕业设计(6)开题答辩PPT
- AD教程系列 | 5 - 绘制原理图
- 处理器仿存带宽_CPU,内存,主板带宽是怎么计算的?网上帖子说内存和主板的带宽要大于等于CPU带宽,充分利用CPU...
- 干货 | 产品助理入门攻略(一枚入行3年的PM内心独白)
- oppo云服务器怎么卸载,oppo手机小布助手卸载方法_oppo手机小布助手怎么卸载-硬件之家...
- 基于spring mvc+bootstrap 集成的返利平台 新增内容-自动对接京东数据
- 阿里云视频云正式支持AV1编码格式 为视频编码服务降本提效
热门文章
- 这样的设计太妙了!K8S 神秘架构终于揭开面纱!
- 解决Ubuntu自动更新Linux内核导致显卡驱动无法加载,致使循环在登录界面
- 支付宝二面:如何用 UDP 实现可靠传输?
- Detect-SLAM阅读笔记
- 现代循环神经网络-1.门控循环单元(GRU)【动手学深度学习v2】
- 0基础软件测试小白,如何找到一份高薪的工作?
- IT项目管理画图题【太原理工大学】
- 几个常见的B端推广渠道
- java 中 webcam类_如何在Java的Swing应用程序中集成Webcam?
- 【Python】Python3如何将汉字转化成反斜线u(\u)开头的字符串