代码随想录第五天哈希表

目录

今日学习的文章

哈希表理论基础

有效的字母异位词 

看到题目的第一想法

看到代码随想录之后的想法

自己实现过程中遇到的困难

两个数组的交集 

看到题目的第一想法

看到代码随想录之

自己实现过程中遇到的困难

快乐数

看到题目的第一想法

看到代码随想录之后的想法

自己实现过程中遇到的困难

两数之和

看到题目的第一想法

看到代码随想录之后的想法

自己实现过程中遇到的困难


今日学习的文章

哈希表理论基础

建议:大家要了解哈希表的内部实现原理,哈希函数,哈希碰撞,以及常见哈希表的区别,数组,set 和map。  

什么时候想到用哈希法,当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法。  这句话很重要,大家在做哈希表题目都要思考这句话。 

文章讲解:代码随想录

有效的字母异位词 

建议: 这道题目,大家可以感受到 数组 用来做哈希表 给我们带来的遍历之处。 

题目链接/文章讲解/视频讲解: 代码随想录

看到题目的第一想法

        判断是否存在异位词

                1 我首先想到用一个数组记录所有26个字母出现的次数,定义一个int数组,长度为0~26,每个下标分别对应a~z

                2 两个字符串用两个数组来记录,最后用一个数组来判断值是否相等

当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法

                这道题就是判断一个字符串中的字符是否在另一个字符串中出现过

看到代码随想录之后的想法

                代码随想录和我的想法不尽相同,但是代码随想录的想法更加优化

                1 代码随想录只用了一个数组,当遍历第一个字符串时,把对应元素的值+1,然后当遍历第二个字符串时,把对应位置的值-1,得出一个最终数组,看最终数组中每个值是否为0

                2 关于字符对应数组的下标,我们不需要去记住'a'的ASCII码值,只需要用对应的char-'a' 对应的字符自然而然就是下标了

        
    

自己实现过程中遇到的困难

               

                1 空间复杂度过高,我用了三个数组,代码随想录只用了一个数组,当遍历第一个字符串时,把对应元素的值+1,然后当遍历第二个字符串时,把对应位置的值-1,得出一个最终数组,看最终数组中每个值是否为0

                2 关于字符对应数组的下标,我想的时是用每个字符减去对应的ASCII码值来一一对应,太麻烦,我们不需要去记住'a'的ASCII码值,只需要用对应的char-'a' 对应的字符自然而然就是下标了

                3 字符的String.charAt(index)可以获取对应的字符

/*class Solution {
    public boolean isAnagram(String s, String t) {
        int[] charArrays = new int[26];
        int[] charArrayt = new int[26];
        //如果是A则插入0,如果是B则插入1
        //数组中每个值都为0
        //差点去记住char的ascII这样是不对的
        for(int i=0;i<s.length();i++){
            int indexs = s.charAt(i)-'a';
            charArrays[indexs]++;
        }
        for(int j=0;j<t.length();j++){
            int indext = t.charAt(j)-'a';
            charArrayt[indext]++;
        }
        //判断两个数组值是否相同
        for(int z=0;z<26;z++){
            if(charArrayt[z]!=charArrays[z]){
                return false;
            }
        }
        return true;
    }
}*/
class Solution {
    public boolean isAnagram(String s, String t) {
        int[] charArrays = new int[26];
        //第一个先加,第二个再减,看是否全部为0
        //用char-'a' 来判断下标从而不需要判断ascII码值
        //s.length() 来获取长度,s.charAt(i) 来获取下标
        //当我们遇到了要快速判断一个元素是否出现集合里的时候,判断某一个元素是否在集合里出现过,就要考虑哈希法了,用哈希数据结构辅助。
        // 遇到哈希想数组(数值很小) map(key和value) 和set(数值很大)
        for(int i = 0;i< s.length();i++){
            charArrays[s.charAt(i)-'a']++;
        }
        for(int j = 0;j< t.length();j++){
            charArrays[t.charAt(j)-'a']--;
        }
        for(int z = 0;z<charArrays.length;z++){
            if(charArrays[z]!=0){
                return false;
            }
        }
        return true;
    }
}

两个数组的交集 

建议:本题就开始考虑 什么时候用set 什么时候用数组,本题其实是使用set的好题,但是后来力扣改了题目描述和 测试用例,添加了 0 <= nums1[i], nums2[i] <= 1000 条件,所以使用数组也可以了,不过建议大家忽略这个条件。 尝试去使用set

 。

题目链接/文章讲解/视频讲解:代码随想录

给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序

看到题目的第一想法

当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法

                判断nums1是否在nums2中出现过

                1 用两个set 将nums1 和nums2去重,然后再放入一个Result中进行终极去重,最后再转换为int返回

                

看到代码随想录之后的想法

                代码随想录比我的方法优化太多

                1 总共只需要两个set,第一个set对nums1 进行去重,第二个resultSet,通过set1.contains 来判断数据是否存在于nums1中,如果存在则放入resultSet中(本质就是看第二个数组中的元素是否在数组1中存在,如果存在就放入resultSet)

    

自己实现过程中遇到的困难

               1 set有很多api不是很熟练,感觉目前用的最多的是set.contains

                2 set转换成int数组也不是很熟练,代码随想录中给出了比较好的办法,在下图代码中

import java.util.HashSet;
import java.util.Set;
/*class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        //输出是唯一的,则放入set中
        //用两个set 把数据存入 用两个for循环
        Set set1 = new HashSet<Integer>();
        Set set2 = new HashSet<Integer>();
        for(int i=0;i<nums1.length;i++){
            set1.add(nums1[i]);
        }
        for(int i=0;i<nums2.length;i++){
            set2.add(nums2[i]);
        }
        
        Set resultSet = new HashSet<Integer>();
        //toArray使用不了
        int[] int1 = set1.toArray();
        int[] int2 = set2.toArray();
        for(int i=0;i<int1.length;i++){
            for(int j=0;i<int2.length;j++){
                if(int1[i] == int2[j]){
                    resultSet.add(int1[i]);
                    break;
                }
            }
        }
        //这个toArray 不知为何用不了,但是在这里应该不需要使用 toArray
        return resultSet.toArray();

        
    }
}*/
class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        //代码随想录中 用一个set存nums1 另外一个直接作为resultSet,存nums2 和 set1中的元素
        //这里用到了set的contains方法,set中方便查询,contains时间复杂度快
        Set set1 = new HashSet<Integer>();
        Set<Integer> resultSet = new HashSet<Integer>();
        for(int i=0;i<nums1.length;i++){
            set1.add(nums1[i]);
        }
        for(int i=0;i<nums2.length;i++){
            if(set1.contains(nums2[i])){
                resultSet.add(nums2[i]);
            }
        }
        // return resSet.stream().mapToInt(x -> x).toArray();也可以用这个方法
        int[] resultInt = new int[resultSet.size()];
        int j = 0;
        //把resultSet 转换为数组进行返回 这个对于java的增强for遍历技巧可以学一下
        for(int i:resultSet){
            resultInt[j++] = i;
        }
        return resultInt;
 
    }
}

快乐数

建议:这道题目也是set的应用,其实和上一题差不多,就是 套在快乐数一个壳子 

 。

题目链接/文章讲解:代码随想录

看到题目的第一想法

当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法

               题干中给出了一个无限循环的提示,其实就是告诉我们,计算出的数据可能之前会出现过

                我看到这个题目没有正确的思路

                1 不知道一个整形的每一位用什么方法取(脑子短路了其实就是N%10)

看到代码随想录之后的想法

                1 对输入进行计算后将值存到一个set中,通过set.contain来判断该值是否出现过,如果出现过则是无限循环,不满足快乐数的要求,如果最后为1,则满足快乐数

                2 对n的计算,用一个循环,每次取n%10 的平方来加到sum中,然后n/10继续往下走,当n<0时结束

    

自己实现过程中遇到的困难

        1 没思路,其实要看到无限循环这个关键信息

        2 实现的过程中把下图的s.add(n)和n=getNumbers(n);这两句搞反了,导致结果出错,最后为1又进行了一次计算结果变成0了,不满足return n==1

             

class Solution {
    public boolean isHappy(int n) {
        //每个位置上数字的平方和
        //用一个map,存放1~9每个数字的平方?没理解题意的想法
        //问题在于怎么把数字拆分成每一位?每次对10取余即可
        // 要注意到题目的第二点,要么变成1要么无限循环始终变不到1
        //无限循环要怎么验证?考虑到去重,当出现重复的时就跳出循环 contains这个函数很关键
        HashSet<Integer> set = new HashSet<Integer>();
        while(n!=1&&!set.contains(n)){
            //下面这两条,顺序不能反 先存入之后,再进行计算,若先计算再存入,会报错,最后为1又进行了一次计算结果变成0了
            set.add(n);
            n=getNumbers(n);
        }
        //return这个写法也很好
        return n==1;
    }
    //这个函数获取平方和
    public int getNumbers(int n){
        int sum = 0;
        while(n>0){
            sum+= (n%10) * (n%10);
            n=n/10;
        }
        return sum;
    }
}

两数之和

建议:本题虽然是 力扣第一题,但是还是挺难的,也是 代码随想录中 数组,set之后,使用map解决哈希问题的第一题。 

建议大家先看视频讲解,然后尝试自己写代码,在看文章讲解,加深印象。 

题目链接/文章讲解/视频讲解:代码随想录

看到题目的第一想法

当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法

               其实就是来判断target-当前下标的值,是否在之前的数组中出现过,但是我没想到target-值 ==出现过的旧值 这个点

               没有思路,只想到了用暴力的方式来,每个数的平方相加看是否等于,然后再返回

看到代码随想录之后的想法

                 1,代码随想录使用了map来解决,这个题的关键在于你需要通过满足条件的值返回数组的下标,于是我们可以通过值和下标来建立一个map

                2,通过 map.containsKey(target-当前值)判断  target-当前值 这个数,是否在之前的数组中出现过,如果出现过则满足题目所给,返回当前的下标和map.get(target-当前值) 的下标

               

    

自己实现过程中遇到的困难

       1自己没有思路,卡哥给的思路不错,看完之后马上就会写了

        2map的相关API也需要再熟悉一下 map.containsKey

class Solution {
    public int[] twoSum(int[] nums, int target) {
        //和为目标值的那两个整数
        //如果用暴力的话,把数组中每个值加上一遍
        //哈希是快速从目标数组中找到对应的值
        //map 是能在最快的时间内,判断这个key是否在map里出现过
        //我的思路:只想到了暴力解,没有想到用哈希能怎么优化
        //卡哥的思路:遍历的时候用一个map存数组的值和下标,因为我们是要看值是否遍历过所以,key应该为值
        //而target - 遍历到的当前值 - 差值,通过这个差值当作key来遍历map判断数组中是否遍历过该元素
        //从而得到目标的两个下标
        Map map = new HashMap<Integer,Integer>();
        for(int i=0;i<nums.length;i++){
            int offset = target-nums[i];
            if(map.containsKey(offset)){
                return new int[]{(Integer)map.get(offset),i};        
            }
            map.put(nums[i],i);
        }
        return null;
    }
}

  • 23
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值