1.知识点
1.1哈希表
哈希表也叫散列表,是根据关键码值(key value)而直接访问元素的数据结构。他通过把关键码值映射到表中一个位置来访问记录,以加快访问速度.
给定表 M,存在函数 f(key) ,对任意给定的关键字值 key,放入函数后若可以得到包含改关键字的记录在表 M 中的位置,则称该表为哈希表,函数f为哈希函数
1.2哈希函数
将键映射到正确的位置的函数就是哈希函数,常用的哈希函数分为:
加法Hash,位运算Hash,乘法Hash,除法Hash,查表Hash等
1.3哈希碰撞
哈希函数将两个不同的键映射到同一个索引的情况,就产生了哈希碰撞
1.4解决哈希碰撞
解决哈希碰撞的方法有
1.4.1开发地址法
哈希碰撞时,去寻找一个新的空闲的哈希地址
1.4.2再哈希法
同时构造多个不同的哈希函数,等发生冲突时就使用第2个,第3个...等其他的哈希函数计算地址,直到不发生冲突为止.虽然不易发生聚集,但是增加了计算时间.
1.4.3链地址法
将虽有哈希地址相同的记录记录在同一个链表中
1.4.4建立公共溢出区
将哈希表分为基本表和溢出表,将发生冲突的存在溢出表中
参考:解决哈希冲突(四种方法)_哈希冲突的解决方法_君诀的博客-CSDN博客
1.5常见哈希结构
数组,HashSet,HashMap
2.刷题
242.有效的字母异位词
LeetCode链接 242. 有效的字母异位词 - 力扣(LeetCode)
题目描述
方法1:比较两个HashMap是否相等
package daimasuixiangshuati.day06_haxibiao;
import java.util.HashMap;
/**
* @Author LeiGe
* @Date 2023/10/10
* @Description todo
*/
public class YouXiaoDeZiMuYiWeiCi242_2 {
/**
* 方法1-hashmap
* 1.两个map分别计算出s和t两个字符串中每个字符出现的次数
* 2.比较两个map的属性是否相等
*
* @param s
* @param t
* @return
*/
public static boolean isAnagram(String s, String t) {
HashMap<Character, Integer> sMap = wordFrequency(s);
HashMap<Character, Integer> tMap = wordFrequency(t);
return sMap.equals(tMap);
}
public static HashMap<Character, Integer> wordFrequency(String s) {
HashMap<Character, Integer> map = new HashMap<>();
for (int i = 0; i < s.length(); i++) {
map.put(s.charAt(i), map.getOrDefault(s.charAt(i), 0) + 1);
}
return map;
}
}
时间复杂度:O(N)
空间复杂度:O(1)
方法2:数组作为哈希表
package daimasuixiangshuati.day06_haxibiao;
/**
* @Author LeiGe
* @Date 2023/10/10
* @Description todo
*/
public class YouXiaoDeZiMuYiWeiCi242_3 {
/**
* 方法2-数组作为哈希表
* 1.将第一个字符串的每个字符存放在数组中(下标表示字符,下标对应的值表示该字符出现的频率)
* 2.遍历第二个字符串,每遇到一个字符,就将该字符对应的值减1
* 3.再次遍历数组,如果数组中出现不为0的值,则返回false,否则返回true
*
* @param s
* @param t
* @return
*/
public static boolean isAnagram(String s, String t) {
int[] ints = new int[26];
//1.将第一个字符串的每个字符存放在数组中(下标表示字符,下标对应的值表示该字符出现的频率)
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
//a对应数组0下标
int idx = c - 'a';
ints[idx] += 1;
}
//2.遍历第二个字符串,每遇到一个字符,就将该字符对应的值减1
for (int i = 0; i < t.length(); i++) {
char c = t.charAt(i);
int idx = c - 'a';
ints[idx] = ints[idx] - 1;
}
//3.再次遍历数组,如果数组中出现不为0的值,则返回false,否则返回true
for (int anInt : ints) {
if (anInt != 0) {
return false;
}
}
return true;
}
}
时间复杂度:O(N)
空间复杂度:O(1)
349.两个数组的交集
LeetCode链接 349. 两个数组的交集 - 力扣(LeetCode)
题目描述
方法1:HashSet
package daimasuixiangshuati.day06_haxibiao;
import java.util.HashSet;
/**
* @Author LeiGe
* @Date 2023/10/11
* @Description todo
*/
public class LiangGeShuZuDeJiaoJi349_2 {
/**
* 方法1:hashSet
* 1.将nums1中的数放入hashSet中
* 2.遍历nums2,如果num2存在于hashSet中,将num2加入到结果中
*
* @param nums1
* @param nums2
* @return
*/
public static int[] intersection(int[] nums1, int[] nums2) {
if (nums1 == null || nums1.length == 0 || nums2 == null || nums2.length == 0) {
return new int[0];
}
HashSet<Integer> set = new HashSet<>();
HashSet<Integer> resSet = new HashSet<>();
//遍历数组1
for (int i : nums1) {
set.add(i);
}
//遍历数组2的过程中判断哈希表中是否存在该元素
for (int i : nums2) {
if (set.contains(i)) {
resSet.add(i);
}
}
int[] resArr = new int[resSet.size()];
int index = 0;
//将结果转换为数组
for (int i : resSet) {
resArr[index++] = i;
}
return resArr;
}
}
时间复杂度:O(N+M)
空间复杂度:O(N)
方法2:数组
package daimasuixiangshuati.day06_haxibiao;
import java.util.ArrayList;
/**
* @Author LeiGe
* @Date 2023/10/11
* @Description todo
*/
public class LiangGeShuZuDeJiaoJi349_3 {
/**
* 方法2-散列表-数组
* 0.因为数组最大元素是1000,用一个数组hash表示,hash 下标为元素,值为该元素出现的次数
* 1.遍历nums1
* 1.1如果nums1[i]在hash中对应的值为0,就+1
* 1.2如果nums1[i]在hash中对应的值为1,则维持1,(达到去重效果)
* 2.遍历数组nums2
* 2.1如果nums2[i]在hash中对应的值为0,那么此元素不可能是公共值
* 2.2如果nums2[i]在hash中对应的值为1,那么表示是公共元素,则+1
* 2.3如果nums2[i]在hash中对应的值为2,那么表示是公共元素,维持2不变,(达到nums2的去重效果)
* 3.此时hash中值为2的就是公共部分
* 4.将ArrayList转化为数组
*
* @param nums1
* @param nums2
* @return
*/
public static int[] intersection(int[] nums1, int[] nums2) {
//0.因为数组最大元素是1000,用一个数组hash表示,
// hash 下标为元素,值为该元素出现的次数
int[] hash = new int[1000];
ArrayList<Integer> result = new ArrayList<>();
//1.遍历nums1,
//1.1如果nums1[i]在hash中对应的值为0,就+1
//1.2如果nums1[i]在hash中对应的值为1,则维持1,(达到去重效果)
for (int i : nums1) {
if (hash[i] == 0) {
hash[i] = 1;
continue;
}
if (hash[i] == 1) {
hash[i] = 1;
}
}
//2.遍历数组nums2.
//2.1如果nums2[i]在hash中对应的值为0,那么此元素不可能是公共值
//2.2如果nums2[i]在hash中对应的值为1,那么表示是公共元素,则+1
//2.3如果nums2[i]在hash中对应的值为2,那么表示是公共元素,维持2不变,(达到nums2的去重效果)
for (int j : nums2) {
if (hash[j] == 1) {
hash[j] = 2;
continue;
}
if (hash[j] == 2) {
hash[j] = 2;
}
}
//3.此时hash中值为2的就是公共部分
for (int i = 0; i < hash.length; i++) {
if (hash[i] == 2) {
result.add(i);
}
}
//4.将ArrayList转化为数组
int[] res = new int[result.size()];
for (int i = 0; i < result.size(); i++) {
res[i] = result.get(i);
}
return res;
//4.将ArrayList转化为数组
//return result.stream().mapToInt(x -> x).toArray();
}
}
时间复杂度:O(N+M)
空间复杂度:O(1)
202.快乐数
LeetCode链接 202. 快乐数 - 力扣(LeetCode)
题目描述
方法1:HashSet保存之前计算过的数
package daimasuixiangshuati.day06_haxibiao;
import java.util.HashSet;
/**
* @Author LeiGe
* @Date 2023/10/11
* @Description todo
*/
public class KuaiLeShu202_2 {
/**
* 方法1-用set记录之前计算过的数的结果
*
* @param n
* @return
*/
public boolean isHappy(int n) {
//0.set中记录计算过的数
HashSet<Integer> record = new HashSet<>();
//1.进入循环
while (true) {
int sum = getNextNumber(n);
//1.1如果等于1,则是快乐数
if (sum == 1) {
return true;
}
//1.2查找当前这个数是否在set中
//1.2.1如果在,说明计算过,要进入死循环了,退出
if (record.contains(sum)) {
return false;
} else {
//1.2.2如果没有,则加入到set中
record.add(sum);
}
//1.3更新n,进入下一次循环
n = sum;
}
}
//计算一个数上各个位上的数平方和
private int getNextNumber(int n) {
int sum = 0;
while (n > 0) {
//取余
int temp = n % 10;
sum += temp * temp;
//计算下一位
n = n / 10;
}
return sum;
}
}
1.两数之和
LeetCode链接 1. 两数之和 - 力扣(LeetCode)
题目描述
方法1:HashMap
package daimasuixiangshuati.day06_haxibiao;
import java.util.HashMap;
/**
* @Author LeiGe
* @Date 2023/10/11
* @Description todo
*/
public class LiangShuZhiHe1_2 {
/**
* 方法2-hashmap方法
* 用一个map存储:key表示数组中的元素,value表示元素的下标
*
* @param nums
* @param target
* @return
*/
public static int[] twoSum(int[] nums, int target) {
HashMap<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
//另外一个加数
int sum = target - nums[i];
//如果另外一个加数在map中,表示找到了
if (map.containsKey(sum)) {
return new int[]{i, map.get(sum)};
}
//将元素和下标加入到map中
map.put(nums[i], i);
}
return new int[]{-1, -1};
}
}
时间复杂度:O(N)
空间复杂度:O(N)
3.小结
1.哈希表理论基础
2.当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法了