算法训练营(day06)
算法训练营(day06)
哈希表理论基础
- 哈希表是根据关键码的值而直接进行访问的数据结构
- 直白来讲其实数组就是一张哈希表。哈希表中关键码就是数组的索引下标,然后通过下标直接访问数组中的元素。
- 一般哈希表都是用来快速判断一个元素是否出现在集合里
哈希表需要了解的知识点主要是 哈希函数、哈希碰撞 以及 哈希结构:
1.哈希函数
哈希函数主要是将元素映射到哈希表的索引,通过查询索引能快速查询元素是否存在。
举个例子,判断学生是否是该学校的,可以把学生的姓名直接映射为哈希表上的索引,然后就可以通过查询索引下标快速知道这位同学是否在这所学校里
这里会出现一个问题,如果哈希表的长度不足以容纳所有的元素,会发生什么情况呢?
答案是:会出现多个元素指向同一个索引下标的情况,也就是常说的 哈希碰撞(哈希冲突)
2.哈希冲突(哈希碰撞)
举个例子,小李和小王都映射到了索引下标 1 的位置,这一现象叫做哈希碰撞
解决哈希冲突一般使用两种解决方法:
- 拉链法:
上面说到,小李和小王在索引1的位置发生了冲突,那我们可以将发生冲突的元素存储在链表中。 这样我们仍可以通过索引找到小李和小王
使用拉链法,需要根据数据规模(dataSize)定义好哈希表的大小(tableSize)。防止因为数组空值而浪费大量内存,以及因为链表太长而在查找上浪费太多时间。这里就引申到哈希表的扩容机制了:https://blog.csdn.net/java_wxid/article/details/121599499
- 线性探测法:
使用线性探测法,一定要保证tableSize(哈希表的大小)大于dataSize(数据规模)。 我们需要依靠哈希表中的空位来解决碰撞问题。
例如冲突的位置,放了小李,那么就向下找一个空位放置小王的信息。所以要求tableSize一定要大于dataSize ,要不然哈希表上就没有空置的位置来存放 冲突的数据
3.哈希结构
当使用哈希法解决问题时,一般使用三种数据结构:
- 数组
- map
- set
242.有效的字母异位词
题目链接:https://leetcode.cn/problems/valid-anagram/description/
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。
解题思路
解题过程:
如果 s 字符串长度和 t 字符串长度不等,直接返回 false
判断 t 是否是 s 的字母异位词,可以考虑使用数组遍历
- 将 s 字符串 遍历成数组
char - 用 t 字符串 遍历数组
char - 如果匹配到相同的字母,则数组中除去这个元素
- 将 s 字符串 遍历成数组
t 字符串遍历结束后,判断数组
char长度- 如果为0, 则说明 t 字符串是 s 的字母异位词,返回 true
- 否则返回 false
详细代码
1 | class Solution { |
349.两个数组的交集
题目链接:https://leetcode.cn/problems/intersection-of-two-arrays/description/
给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
解题思路
解题过程:
看到了唯一且无序,可以考虑使用
set进行解题首先判定一下 两个数组的状态(null / length == 0)
将
nums1内的元素保存进set中定义一个
resSet存放 交集- 遍历
nums2 - 如果
nums2的元素 在set中能找到 - 则将这个元素保存在
resSet中
- 遍历
将
resSet转换成数组输出
详细代码
1 | class Solution { |
202.快乐数
题目链接:https://leetcode.cn/problems/happy-number/description/
编写一个算法来判断一个数 n 是不是快乐数。「快乐数」 定义为:
- 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
- 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
- 如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n 是 快乐数 就返回 true ;否则返回 false 。
解题思路
解题过程:
反向理解快乐数:如果不是快乐数,就会 无限循环 且 始终变不到 1
根据题意,可以将遍历条件以及判定结果写出
- 遍历条件:
!= 1 && 不循环 - 判定结果
return n == 1
- 遍历条件:
不循环这个条件,可以拆解成没有重复出现平方和,就可以用
set.contains()来解决平方和的循环
- 通过 取余 的方式,得到每一位上的值
- 将 平方和的值 赋值给
n - 用
set保存每一个n
当
n出现重复时,跳出循环,进行判定
详细代码
1 | class Solution { |
1.两数之和
题目链接:https://leetcode.cn/problems/two-sum/description/
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
解题思路
思路一:暴力遍历
解题过程:
- 定义两个for循环,如果存在
nums[i] + nums[j] == target,则返回数组[i,j] - 否则返回
new int[]{}
思路二:哈希法
解题过程:
- 既要找到数组中的数(key),又要返回下标(value),可以考虑使用 map 来解题
- 题目要求的返回两个整数的下标,实际就是返回
nums[i]和target - nums[i]的值(value) - 用 map 保存数组中的每个值和其下标,再用
map.containsKey()判断是否存在,即可判断答案是否存在- 存在,则返回
new int[]{map.get(target - nums[i]), i} - 不存在,则返回
new int[]{}
- 存在,则返回
详细代码
解法一:暴力遍历
1 | class Solution { |
解法二:哈希法
1 | class Solution { |
解法二优化:
1 | class Solution { |

