仅自己学习参考
什么时候想到用哈希法,当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。
涉及知识点:哈希表可以存储对象
哈希碰撞有两种解决方法, 拉链法和线性探测法。
常见的三种哈希结构:数组(数值比较小 范围可控),set (集合),map(映射)
不适合数组的情况,数值很分散,数值很大
- 数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
- set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,不仅要判断y是否存在而且还要记录y的下标位置,因为要返回x 和 y的下标。所以set 也不能用。
242.有效的字母异位词
题目强调只有小写字母,故而定义一个数组来存储26位小写字母,在s中出现的字母在相应位置加1,在t中出现的字母在相应位置减一,在最后对数组进行判断,如果全为0则为字母异构词。
- 时间复杂度: O(n)
- 空间复杂度: O(1)
349. 两个数组的交集
- 时间复杂度: O(m + n)
- 空间复杂度: O(n)
可以用数组来解决但该题是set的经典实现
class Solution { public int[] intersection(int[] nums1, int[] nums2) { int [] hash=new int[1001]; ArrayList<Integer> arr=new ArrayList<Integer>(); 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) { hash[nums2[i]]=2; } } for(int i=0;i<hash.length;i++){ if(hash[i]==2){ arr.add(i); } } int [] result=new int[arr.size()]; int index=0; for(Integer num: arr){ result[index++]=num.intValue(); } return result; } }
使用set的话首先将数组1的元素全部存入到set中,然后再遍历nums2数组,如果set中存在nums2中的元素则将其加入到resultset中,最后使用foreach来遍历得到需要返回的数组。
202. 快乐数
涉及对各个位置上元素的获取
- 时间复杂度: O(logn)
- 空间复杂度: O(logn)
主要就是对每一个位置上的元素做的操作
int res=0; Set<Integer> set1=new HashSet<>(); set1.add(n); while (n!=1) { int sum=0; while(n>0){ res=n%10; sum=sum+res*res; n=n/10; } if(set1.contains(sum)){ return false; } set1.add(sum); n=sum; } return true;
然后在外面在嵌套一次while判断结果是否为1,如果出现循环即set中已经存在则直接返回false
同时注意在每一次算sum之前需要将其重新置为0
1. 两数之和
- 时间复杂度: O(n)
- 空间复杂度: O(n)
四个重点
为什么想到用哈希法
本题需要一个集合来存放我们遍历过的元素,然后在遍历数组的时候去询问这个集合,某元素是否遍历过,也就是 是否出现在这个集合。
为什么要用map
本题,我们不仅要知道元素有没有遍历过,还要知道这个元素对应的下标,需要使用 key value结构来存放,key来存元素,value来存下标,那么使用map正合适。
map究竟是用来做什么的
map目的用来存放我们访问过的元素,因为遍历数组的时候,需要记录我们之前遍历过哪些元素和对应的下标,这样才能找到与当前元素相匹配的(也就是相加等于target)
map里的key value是来存什么的
判断元素是否出现,这个元素就要作为key,所以数组中的元素作为key,有key对应的就是value,value用来存下标。
在遍历数组的时候,只需要向map去查询是否有和目前遍历元素匹配的数值,如果有,就找到的匹配对,如果没有,就把目前遍历的元素放进map中,因为map存放的就是我们访问过的元素。