一、哈希表理论基础
1.概念
- 哈希表是根据关键码的值而直接进行访问的数据结构,例如数组。
- 哈希表中关键码就是数组的索引下标,然后通过下标直接访问数组中的元素
- 一般哈希表都是用来快速判断一个元素是否出现集合里
2.哈希碰撞
- 拉链法
- 线性探测法
3.常见的哈希结构
- 数组
- set (集合)
- map(映射)
4.Java实现哈希表
set
- HashSet用于需要快速查找元素时
- TreeSet用于需要对元素进行排序时
- LinkedHashSet用于需要保持插入顺序时
HashSet
- add(E element): 添加元素到集合中。
- remove(Object element): 从集合中移除指定的元素。
- contains(Object element): 检查集合中是否包含指定的元素。
- size(): 返回集合中的元素个数。
TreeSet
- add(E element): 添加元素到集合中。
- remove(Object element): 从集合中移除指定的元素。
- contains(Object element): 检查集合中是否包含指定的元素。
- size(): 返回集合中的元素个数。
- first(): 返回集合中的第一个元素。
- last(): 返回集合中的最后一个元素。
LinkedHashSet
- add(E element): 添加元素到集合中。
- remove(Object element): 从集合中移除指定的元素。
- contains(Object element): 检查集合中是否包含指定的元素。
- size(): 返回集合中的元素个数。
map
- 使用 key value结构来存放,key来存元素,value来存下标
hashmap
- clear() : 删除 hashMap 中的所有键/值对
- put(K key,V value) :增添数据
- remove(Object Key) :根据键删除键值对元素
- void clear() 移除所有的键值对元素
- boolean containsKey(Object key) :判断集合是否包含指定的键
- boolean containsValue(Object value) :判断集合是否包含指定的值
- boolean isEmpty():判断集合是否为空
- get(Object key)():根据键获取值
- Set keySet() 获取所有键集合
5.适用情况
- 当需要查询一个元素是否出现过,或者一个元素是否在集合里的时候,第一时间想到哈希法。
二、算法题
242.有效的字母异位词
class Solution {
public boolean isAnagram(String s, String t) {
int []result=new int[26];
for(int i=0;i<s.length();i++){
result[s.charAt(i)-'a']++;
}
for(int i=0;i<t.length();i++){
result[t.charAt(i)-'a']--;
}
for(int i=0;i<26;i++){
if(result[i]!=0){
return false;
}
}
return true;
}
}
- s.charAt(i)-'a'能在不知道a的ASCII码时,仍然可以从0到25进行排列
- 因为如果是'a',那'a'-'a'=0,a就从0开始,'b'会从1开始,'c'会从2开始,以此类推
349. 两个数组的交集
方法一:使用set
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Set<Integer> set1=new HashSet<>();
Set<Integer> set2=new HashSet<>();
Set<Integer> result=new HashSet<>();
//把nums1和nums2的数值分别加入到哈希表中
for(int num:nums1){
set1.add(num);
}
for(int num:nums2){
set2.add(num);
}
//set1更长
if(set1.size()>set2.size()){
//遍历Set1中的所有元素
for(int num:set1){
//set2中包含set1中的元素
if(set2.contains(num)){
result.add(num);
}
}
}
else{
//遍历Set2中的所有元素
for(int num:set2){
//set1中包含set1中的元素
if(set1.contains(num)){
result.add(num);
}
}
}
int []res=new int[result.size()];
int j=0;
for(int num:result){
res[j]=num;
j++;
}
return res;
}
}
- 因为题目要求返回的是int数组,所以最后要把哈希set转化为int数组
方法二:使用数组
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
//数组
int [] arr1=new int [1002];
int [] arr2=new int [1002];
for(int num:nums1){
arr1[num]++;
}
for(int num:nums2){
arr2[num]++;
}
List<Integer> arr3=new ArrayList<>();
for(int i=0;i<1002;i++){
if(arr1[i]!=0&&arr2[i]!=0){
//要找的是对应的下标,因为下标才是给定数组里重复的元素
//arr3下标对应的数字是这个重复元素出现的次数
arr3.add(i);
}
}
int []res=new int[arr3.size()];
int j=0;
for(int num:arr3){
res[j]=num;
j++;
}
return res;
}
}
- 哈希表解法是用哈希表去重然后找两个哈希表里的相同元素
- 数组解法是在对应数字的位置++,最后找两个数组里数字位置都不为0的数字
202. 快乐数
class Solution {
public boolean isHappy(int n) {
Set<Integer> res=new HashSet<>();
//说明既没有得到1也不是重复出现过的数字,也就是继续循环
while(n!=1&&!res.contains(n)){
//把这个新数字添加到哈希表中
res.add(n);
n=getnum(n);
}
//如果n=1,说明是找到了才退出循环的,此时返回true
//如果n!=1,说明是出现了重复元素,也就是会陷入死循环,返回false
return n==1;
}
//对数字进行处理
public int getnum(int n){
int sum=0;
int i=0;
while(n>0){
i=n%10;
sum+=i*i;
n=n/10;
}
return sum;
}
}
- 一个元素重复出现说明会进入死循环的原因如下
1. 两数之和
class Solution {
public int[] twoSum(int[] nums, int target) {
//因为题目要求两个整数
int []res=new int[2];
if(nums==null){
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[0]=i;
res[1]=map.get(temp);
return res;
}
//如果没找到,则把元素加入到哈希表中,进入下一次循环
map.put(nums[i],i);
}
return res;
}
}
三、其他
List
- ArrayList:基于动态数组实现,支持随机访问和快速遍历,适用于读取和修改操作较多的场景。
- LinkedList:基于双向链表实现,支持高效的插入和删除操作,适用于频繁的插入和删除操作。
- Vector:与ArrayList类似,但是线程安全,适用于多线程环境。
ArrayList
- add(E element): 在列表的末尾添加元素
- get(int index): 获取指定索引位置的元素
- set(int index, E element): 替换指定索引位置的元素
- remove(int index): 移除指定索引位置的元素
- size(): 返回列表的大小
LinkedList
- add(E element): 在列表的末尾添加元素
- get(int index): 获取指定索引位置的元素
- set(int index, E element): 替换指定索引位置的元素
- remove(int index): 移除指定索引位置的元素
- size(): 返回列表的大小
Vector
- add(E element): 在列表的末尾添加元素
- get(int index): 获取指定索引位置的元素
- set(int index, E element): 替换指定索引位置的元素
- remove(int index): 移除指定索引位置的元素
- size(): 返回列表的大小