目录
前言
记录一下自己刷代码随想录的过程,希望能坚持下去,思路、代码均来自于代码随想录。
1.理论基础
哈希表是根据关键码的值而直接进行访问的数据结构,一般哈希表都是用来快速判断一个元素是否出现在集合里。牺牲了空间换取了时间。
哈希碰撞:拉链法、线性探测法
常见的三种哈希结构:数组、set(集合)、map(映射)
2.有效的字母异位词
题目:给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
数组其实就是一个简单的哈希表,而且题目中字符串只有小写字符,那么可以定义一个数组来记录字符串里字符出现的次数。因为字符a到字符z的ASCII是26个连续的数值,所以字符a映射为下标0,相应的字符z映射为下标25。
3.两个数组的交集
如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费!
输出元素是唯一的——set
数组1存进set中,遍历数组2判断set中是否存在该元素,若有则将该元素存进rerSet,最后将rerSet转换为数组。
4.快乐数
题目:编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。
如果 n 是快乐数就返回 True ;不是,则返回 False 。
示例:
输入:19
输出:true
解释:
1^2 + 9^2 = 82
8^2 + 2^2 = 68
6^2 + 8^2 = 100
1^2 + 0^2 + 0^2 = 1
题目中说了会 无限循环,那么也就是说求和的过程中,sum会重复出现,这对解题很重要!
当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法了。
所以这道题目使用哈希法,来判断这个sum是否重复出现,如果重复了就是return false, 否则一直找到sum为1为止。
5.两数之和
题目:给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
Eg. target为9,当访问元素为2时,需要寻找是否有7
- 为什么想到哈希法:需要一个集合来存放我们遍历过的元素,然后在遍历数组的时候去询问这个集合,某元素是否遍历过,也就是 是否出现在这个集合。
- 为什么用map:不仅要知道元素有没有遍历过,还有知道这个元素对应的下标,需要使用 key value结构来存放,key来存元素,value来存下标。
- Map用来做什么:用来存放我们访问过的元素。
6.四数相加Ⅱ
题目:给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。
与两数之和思路类似,eg.在遍历CD数组时,若C[k] + D[l]=2,那么需要寻找A[i] + B[j]=-2的情况有几种。
- 为什么想到哈希法:需要一个集合来存放AB数组中所有的和的情况,然后在遍历CD数组的时候去询问这个集合,某元素(0- C[k] - D[l])是否出现在这个集合。
- 为什么用map:不仅要知道元素是否存在,还有知道这个元素出现过几次,即有几种情况,需要使用 key value结构来存放,key来存a和b两数之和,value来存a和b两数之和出现的次数。
- Map用来做什么:用来存放AB数组中所有和的情况。
7.赎金信
题目:给定一个赎金信 (ransom) 字符串和一个杂志(magazine)字符串,判断第一个字符串 ransom 能不能由第二个字符串 magazines 里面的字符构成。如果可以构成,返回 true ;否则返回 false。
(题目说明:为了不暴露赎金信字迹,要从杂志上搜索各个需要的字母,组成单词来表达意思。杂志字符串中的每个字符只能在赎金信字符串中使用一次。)
思路与有效的字母异位词一样,只不过有效的字母异位词中两字符串除了字符顺序不一致其余完全一致,而本题只要求ransom能由magazines构成。
8.三数之和
题目:给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
可以用哈希法来解决,但是本题要求不可重复,用哈希法去重的过程不好处理。
所以采用双指针法:索引i、left、right。
- 首先将数组排序,然后有一层for循环,i从下标0的地方开始,同时定一个下标left 定义在i+1的位置上,定义下标right 在数组结尾的位置上。
- 在数组中找到abc,使得a+b+c=0,a = nums[i],b = nums[left],c = nums[right]。
- 如果a+b+c>0,三数之和偏大,right--;<0,三数之和偏小,left++;直到left与right相等。
去重的话,考虑abc三个数的去重
- 对a,应与它之前的元素进行比较,因为它之后的元素是left和right的范围,三元组内的元素可以重复。
- 对b、c,在a+b+c=0,移动left、right时对其去重。
9.四数之和
题目:给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
注意:答案中不可以包含重复的四元组。
思路与三数之和类似,只不过多了一层for循环,即i、j、left、right。两层for循环nums[i] + nums[j]为确定值,依然是循环内有left和right下标作为双指针,找出nums[i] + nums[j] + nums[left] + nums[right] == target的情况。
除此之外,在剪枝方面略有不同:
- 三数之和因为要满足和为0,所以排序后,当第一个元素已经大于0时,left、right无论怎么组合都是大于0的,所以直接返回结果集。
- 四数之和的target可以为正也可以为负,当第一个元素大于target且第一个元素的值大于0时(若第一个元素的值为负,那么虽然它大于target,但是再加负数的话是有可能满足题意的),直接返回结果集。
总结
一般来说哈希表都是用来快速判断一个元素是否出现集合里。
哈希函数是把传入的key映射到符号表的索引上。
哈希碰撞处理有多个key映射到相同索引上时的情景,处理碰撞的普遍方式是拉链法和线性探测法。
常见的三种哈希结构:
- 数组
- set(集合)
- map(映射)
数组:数组的索引和值就是一种映射方式,即数组就是简单的哈希表。
- 但是数组的大小是受限的。
- 如果数组空间够大,但哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费。
Set:去重,是一个集合,里面放的元素只能是一个key。
Map:<key, value>,键值对结构。