哈希表的基础知识
哈希表:用来快速判断一个元素是否出现在集合里。
哈希函数:通过hashcode把名字转化为数值,一般hashcode是通过特定的编码方式,可以将其他数据格式转化为不同的数值。
哈希碰撞的处理方法:
- 拉链法:在冲突的位置上进行链表存储
- 线性探测法:需要保证tablesize大于datasize,依靠哈希表中的空位来解决碰撞问题。
常用的三种哈希结构:
- 数组
- set(集合)(java中的set是无序的、不重复的)
- map(映射)
242.有效字母异位词
题目:给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。
基本思想:先定义一个长度为26的整型数组,26个元素分别对应着26个字母。首先对第一个数组进行一次便利,每检测到一个字母出现,在对应的整型数组元素上+1,之后再对第二个数组进行遍历,每检测到一个字母出现,在对应的整型数组元素上-1。之后再对这个整型数组进行遍历,如果发现有一个元素不为0,则认为非有效字母异位词。
class Solution {
public boolean isAnagram(String s, String t) {
int[] hash = new int[26];
for(int i = 0; i < s.length(); i++){
hash[s.charAt(i) - 'a']++;
}
for(int i = 0; i < t.length(); i++){
hash[t.charAt(i) - 'a']--;
}
for(int i = 0; i < hash.length; i++){
if(hash[i] != 0){
return false;
}
}
return true;
}
}
349.两个数组的交集
题目: 给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
基本思路:这道题需要考虑到大规模数据的出现(>100000),所以数组便不再适用,可以使用set.Java中的set是无序的\不允许重复的,在C++中对应的应该是unorderset
。解题思路就是定义两个set,首先对第一个数组进行遍历,对出现的每一个数字均添加到set中,然后对第二个数组进行遍历,如果set中包含这个数字,向第二个set中添加这个数字。最后返回这个set转化为数组的形式。
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
int[] hash = new int[1005];
int[] result = new int[1001];
int n = 0;
for(int i = 0; i< result.length; i++){
result[i] = -1;
}
for(int i = 0; i< nums1.length; i++){
hash[nums1[i]] = 1;
}
for(int i = 0; i< nums2.length; i++){
if(hash[nums2[i]] == 1){
result[nums2[i]] = nums2[i];
}
}
for(int i = 0; i < result.length; i++){
if(result[i] != -1){
n++;
}
}
int[] res = new int[n];
for(int i = 0,j = 0; i < result.length; i++){
if(result[i] != -1){
res[j++] = result[i];
}
}
return res;
}
}
202.快乐数
快乐数 定义为:
- 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
- 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
- 如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n 是 快乐数 就返回 true ;不是,则返回 false 。
基本思路:首先进行对一个数字的每一位上的数字进行分离操作(198分离为1、9、8),然后计算分离之后的数字的平方和,定义一个set来存储这些平方和,如果发现计算出来的平方和已经存在,则认为这个数字并不是一个快乐数。重点注意分离操作的实现方式
class Solution {
public boolean isHappy(int n) {
Set<Integer> record = new HashSet<>();
while(n != 1 && !record.contains(n)){
record.add(n);
n = getSum(n);
}
return n == 1;
}
public int getSum(int number){
int sum = 0;
int temp = 0;
while(number > 0){
temp = number % 10;
sum += temp * temp;
number = number / 10;
}
return sum;
}
}
1.两数之和
题目: 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
什么时候想到用哈希算法: 当我们需要查询一个元素是否出现过,或者一个元素是否在集合里的时候,第一时间想到哈希法.
基本思路:因为这道题要求返回下标,便非常适合使用map的哈希表(即使用key value结构)。定义一个长度为2整形数组,第一个元素用于存储数字,第二个元素用于存储其对应的下标,因为题目中做了只有一种答案的要求,所以以上做法就满足了。
要考虑清楚四个问题:
- 什么时候用哈希表
- 使用哈希表的那种结构(array/set/map)
- 为什么使用这种结构
- 这种结构的存储特点是什么(map中的key和value是用来存什么的)
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] res = new int[2];
if(nums == null || nums.length == 0){
return res;
}
Map<Integer, Integer> map = new HashMap<>();
for(int i = 0; i < nums.length; i++){
int temp = target - nums[i];
if(map.containsKey(temp)){
res[1] = i;
res[0] = map.get(temp);
}
map.put(nums[i], i);
}
return res;
}
}