HashMap的应用
对于数据结构 HashMap/HashSet,它不仅可以用于去重,还可以用于快速查找(复杂度 O(1))。针对查找功能,整理了下面几道题目,用于体会其用法。
具体的,我们首先对几道题目进行分析,给出代码,最后统一的进行总结。
题1- 两数之和
题目:给定一个整数数组 nums
和一个整数目标值 target
,请你在该数组中找出 和为目标值 target
的那 两个 整数,并返回它们的数组下标。LeetcodeLink
分析:这道题目最简单的做法是直接进行暴力枚举,使用两重 for 循环寻找枚举所有的两数之和,再判断和是否为目标 target,这样的算法时间复杂度为 O(n^2)
。降低时间复杂度的方法是转换枚举答案的思维,而是将问题转为 已知两数之和 target
和其中 一个整数 x1
,求解另一个数字 x2
,从而将问题变为寻找特定数字的问题。具体编程中,我们可以在遍历的同时,将遍历到的数字放入到 HashMap 中,key 值为数值量,value 值为该数字在数组中位置的下标。参考如下的代码:
1 | class Solution { |
题2- 和相同的二元子数组
题目:给你一个二元数组 nums
(数组中不是0就是1),和一个整数 goal
,请你统计并返回有多少个和为 goal
的 非空 子数组。(子数组 是数组的一段连续部分。) leetcodeLink
分析:与上一题类似,本题也是寻找 “和为特定值” 的数据。但与上一题不同的是,本题不再是寻找两个数字的和为特定值,而是寻找一个区间的和为特定值。对于区间和 sum[a, b)
, 实际上可以写成两个前缀和的差值的形式,即 sum[a, b) = sum[0,b) - sum[0, a)
。因此,类似的,本题可以将 原问题转换为 知道两个前缀区间和的差值 goal
与一个前缀区间和 x
, 求 前缀区间 x
前面的满足前缀和等于 x-goal
的区间。具体的,我们可以在遍历数组的同时,将前缀和放置在 HashMap 中,key 值为前缀和的值,value 值为该前缀和出现的次数。代码如下:
1 | class Solution { |
由于本题数据的特殊性,数组中的数值只有 0 和 1,因此 前缀和一定是连续的整数。根据 key 值的特殊性,我们可以使用 数组 来实现 HashMap 的效果。具体地,数组的下标等效于 key 值,value 值为对应前缀和出现的次数。代码如下:
1 | class Solution { |
题3- 大餐计数
题目:大餐 是指 恰好包含两道不同餐品 的一餐,其美味程度之和等于 2 的幂。给你一个整数数组 deliciousness
,其中 deliciousness[i]
是第 i 道餐品的美味程度,返回你可以用数组中的餐品做出的不同 大餐 的数量。结果需要对 1e9 + 7
取余。注意,只要餐品下标不同,就可以认为是不同的餐品,即便它们的美味程度相同。链接
分析: 与求解 “两数之和” 类似,本题要求的也是 两数之和 为特定值。只不过这里的特定值不是一个值,而是一类值:2的整数次幂。整体的思路实际上是相同的,首先将数据放置到 HashMap 中,key值为“美味值”,value 值则为对应美味值出现的次数。由于存在多个目标值,遍历到数值 x
时,我们要枚举各个目标和 target
,来寻找不同的 target - x
。此外,一些需要注意的细节包括:
- 需要根据两个加数(美味值)是否相同分类进行讨论;
- 当两个加数不相同时,可能出现重复计算,我们可以在判断条件中添加 两个加数之间的大小关系要求,来避免重复。
具体参考下面的代码实现:
1 | class Solution { |
总结
上面的三道例题 都使用了 HashMap 来实现快速查找的目的。题1 是最为经典的模型,即求一组数中,和为固定值的两个数的组合。处理方法是将相加问题,转为“相减”问题,即已知两个数的和为 target
及其中一个数x
,求 target-x
是否存在或求它在数组中的位号。
后面两道题目都是第一题的变形。题2中,将求解问题变为了区间和,我们可以根据区间和 与前缀和的关系,将问题转换为类似求解两数和的问题。问题3 是求解两数和的问题,只是和为一组确定的值,方法也很简单,遍历这组和即可。