一、哈希函数的抉择
数组:哈希值小而且范围小
set:哈希值大且范围大
map:需要有key value 的对应
二、有效的字母异位词
----要点:s.charAt(i)这里涉及一个string取字符的操作 ,取得第i个位置的字符
因为之前没有做过哈希的题目所以整个人是很懵的,但是听完讲解后,写出算法逻辑是没问题的
但是对于一些代码的书写还是有误的,例如
hasharray[s.charAt[i]-"a"]++; //错误代码
hasharray[s.charAt(i)-'a']++; //正确代码
例如[]里写双引号还有charAt(i)写出charAt[i]
数组的长度是 .length 然而 字符串String的长度是.length()
以下为实现代码
public boolean isAnagram(String s, String t) {
int[] hasharray = new int[26]; //因为是26个字母
//然后给哈希数组赋初值0
for(int i=0;i<hasharray.length;i++){
hasharray[i]=0;
}
//接下来遍历第一个字符串s,进行操作
//s.charAt(i)这里涉及一个string取字母的操作
for(int i=0;i<s.length();i++){
hasharray[s.charAt(i)-'a']++;
}
for(int i =0;i<t.length(); i++){
hasharray[t.charAt(i)-'a']--;
}
//操作完毕后对哈希数组进行遍历检查
for(int i =0;i<hasharray.length;i++ ){
if(hasharray[i]!=0){
return false;
}
}
return true;
}
三、两个数组的交集
重点---用数组来做哈希的题目,是因为题目都限制了数值的大小
而这道题目没有限制数值的大小,就无法使用数组来做哈希表了。
而且如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费。
-->做这种不熟悉的题目其实就是一个完全新的学习过程,其实运行的逻辑并不复杂,但是需要多熟悉一下集合的操作,然后还有一个遍历集合转数组的操作
public int[] intersection(int[] nums1, int[] nums2) {
//-------这题选择用set解决,因为不知道数组里的值的大小,
// 如果是很大并且数据分散的话,用数组就会很浪费
Set<Integer> set1 = new HashSet<>(); //建立一个hashset
Set<Integer> resSet = new HashSet<>();
for(int i =0 ;i<nums1.length;i++){
set1.add(nums1[i]); //这里直接用hashset add 值就可以了,他会自己转化的
}
for(int i =0; i<nums2.length;i++){
if (set1.contains(nums2[i])) { //判断是否contains
resSet.add(nums2[i]); //用新的哈希表进行增加,哈希表的好处是可以去重
}
}
//--------这里还有一个挺上流的操作,将set转化为数组
int[] intersection = new int[resSet.size()];
int index = 0;
for (int num : resSet) {
intersection[index++] = num;
}
//将结果几何转为数组
return intersection;
}
四、快乐数
题目灵魂:使用哈希法,来判断这个sum是否重复出现
------他不是一个纯纯的重复循环的题目,我们需要有一种合理的措施来判断计算出来的值是否出现过的,所以这个时候用hashset就很舒服啦
-->这题都没有看视频就懂了诶~~(写完才发现原来也没有视频....) ,虽然那个对一个数按位置不断的遍历的操作是真滴上流,还是看了给的代码。
使用hashset做(随想录做法)
public boolean isHappy(int n) {
Set<Integer> set1 = new HashSet<>(); //建立一个hashset
//问题点一:题设给的int 我怎么去获得十位和个位的值
int i = n;
int all = 0;
while(!set1.contains(i)){
set1.add(i);
//问题解决点:int temp = n % 10;这可是数学问题嗷
/* int ge = i%10;
int shi = i/10;
i = ge*ge+shi*shi; //但很显然我这样做其实是有一点问题的,无法对每一个位置的值进行操作
*/ n = i;
while (n > 0) {
int temp = n % 10;
all += temp * temp;
n = n / 10;
} //这个算法就很吊,他通过循环直接就不断的对每一位进行操作
if(all==1 ){
return true;
}
System.out.println(all);
i=all; all=0;
}
return false;
}
}
------ //问题点一:题设给的int 我怎么去获得十位和个位的值
-------//问题解决点:int temp = n % 10;这可是数学问题嗷
---->用个循环遍历的算法,每次一位一位的挪动,当/10后判断<0后脱离循环即可!!!!
(这种思想嘎嘎重要)
使用双指针做(力扣做法)--》经典的循环追击问题
public boolean isHappy(int n) {
//力扣推荐双指针算法
int fast =culmulate(n);
int slow = n;
while(fast!=slow && fast!=1){ //这里必须是&&--->不然如果fast!=1,即便相等还是会不断地循环
//原因:快乐数的条件是能fast=1;并且不成环
//如果触碰到了1,那么循环的值就会是一直是1,所以循环判出条件还有1
fast=culmulate(fast);
fast=culmulate(fast);
slow=culmulate(slow);
System.out.println("fast"+fast);
System.out.println("slow"+slow)
}
return fast==1;
}
//---这里先写下n的各个位置平方和的算法
public int culmulate(int n ){
int all = 0;
while(n>0){
int a = n%10;
all=all+a*a;
n=n/10;
}
return all;
}
------->这里的判断环的思路和链表那道题的思路是一毛一样的
五、两数之和
因为本地,我们不仅要知道元素有没有遍历过,还有知道这个元素对应的下标,需要使用 key value结构来存放,key来存元素,value来存下标,那么使用map正合适。
再来看一下使用数组和set来做哈希法的局限。
- 数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
- set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,不仅要判断y是否存在而且还要记录y的下标位置,因为要返回x 和 y的下标。所以set 也不能用
-------->去看了卡哥的视频后理解了整个map的操作了,自己也能盲写出来了
public int[] twoSum(int[] nums, int target) {
int [] result = new int[2];
HashMap<Integer, Integer> hmap = new HashMap<Integer, Integer>();
for(int i =0; i<nums.length;i++){
int need = target-nums[i];
if(hmap.containsKey(need)){
result[0]=hmap.get(need);
result[1]=i;
}else{
hmap.put(nums[i],i);
}
}
return result;
}
----哈希表总结:之前因为对于哈希表的恐惧导致我一直不敢写,然后拖到不能再拖的时候,才发现其实不会写是正常的,对于一个陌生的东西就是一个学习的过程,边看视频,边写,其实真的没问题啦