代码随想录第六天哈希表+双指针(待补充)

目录

今日学习的文章

四数相加II 

看到题目的第一想法

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

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

赎金信  

看到题目的第一想法

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

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

三数之和 

看到题目的第一想法

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

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

四数之和

看到题目的第一想法

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

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


今日学习的文章

四数相加II 

建议:本题是 使用map 巧妙解决的问题,好好体会一下 哈希法 如何提高程序执行效率,降低时间复杂度,当然使用哈希法 会提高空间复杂度,但一般来说我们都是舍空间 换时间, 工业开发也是这样。

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

看到题目的第一想法

     其实没什么思路,想着用哈希,审题出错,计算有多少个元组,我以为是两数相加那种,要返回下表

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

          其实和两数之和的做法和这个思路比较雷同,

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

           用一个双重for循环存入nums1 和nums2 的和,到map的key中,value为出现的次数

           再用一个for循环num3 num4 get(0-(nums1+nums2)),获得出现多少次

        
    

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

               

              

/*class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        //n为长度
        //有四个数组用哈希?
        //当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法
        //数组的值加起来
        //我审题有问题,题目要求是计算有多少个元组,而我想的是要把每个元组都要查出来
        //卡哥的视频思路,:先处理前面两个数组,将用map集合将nums1和nums2 的所有得到的和当成key存起来,
        //而value存放的是,在前两个数组中有多少个组合能组成所得到的和,存放的是这个和出现的次数
        //而在遍历nums3和nums4时,利用0-(nums3+nums4)得到的值,作为key去map中查找有没有符合的,
        //如果有则得到相关的value(次数)
        Map<Integer,Integer> map = new HashMap<Integer,Integer>();
        for(int i=0;i<nums1.length;i++){
            for(int j=0;j<nums2.length;j++){
                if(map.containsKey(nums1[i]+nums2[j])){
                    int num = map.get(nums1[i]+nums2[j]);
                    num++;
                    map.put(nums1[i]+nums2[j],num);
                }else{
                    //这里应该为1  写的时候为0
                    map.put(nums1[i]+nums2[j],1);
                }
            }
        }
        int count = 0;
        for(int i=0;i<nums3.length;i++){
            for(int j=0;j<nums4.length;j++){
                int offset = 0-(nums3[i]+nums4[j]);
                if(map.containsKey(offset)){
                    count+=map.get(offset);
                }
            }

        }    
        return count;
    }   
}*/
class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        //n为长度
        //有四个数组用哈希?
        //当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法
        //数组的值加起来
        //我审题有问题,题目要求是计算有多少个元组,而我想的是要把每个元组都要查出来
        //卡哥的视频思路,:先处理前面两个数组,将用map集合将nums1和nums2 的所有得到的和当成key存起来,
        //而value存放的是,在前两个数组中有多少个组合能组成所得到的和,存放的是这个和出现的次数
        //而在遍历nums3和nums4时,利用0-(nums3+nums4)得到的值,作为key去map中查找有没有符合的,
        //如果有则得到相关的value(次数)
        Map<Integer,Integer> map = new HashMap<Integer,Integer>();
        //map.getOrDefault方法获取指定 key 对应的 value,如果找不到 key ,则返回设置的默认值。
        for(int i :nums1){
            for(int j:nums2){
                int sum = i+j;
                map.put(sum,map.getOrDefault(sum,0)+1);
            }
        }
        int count = 0;
        for(int i :nums3){
            for(int j:nums4){
                count+=map.getOrDefault(0-(i+j),0);
            }
        }    
        return count;
    }   
}

赎金信  

建议:本题 和 242.有效的字母异位词 是一个思路 ,算是拓展题 

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

看到题目的第一想法

     和242一样的逻辑,用一个26位的数组来判断每个字符出现了多少次

        但是也有不同,它是判断一个单词,能不能由另一个单词组成,所以数组中存储长单词,短单词的时候减减,结束时判断是否出现负数

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

          

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

           

        
    

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

               

class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        //判断magazine中的字符是否在ransomNote中出现
        //字符异位是怎么做的?用一个数组
        //用一个int数组将26为字符一一对应
        //记录每个字符出现的次数,如果最后都为0则返回true,反之为false
        int[] note = new int[26];
        for(int i=0;i<magazine.length();i++){
            note[magazine.charAt(i)-'a']++;
        }
        for(int i=0;i<ransomNote.length();i++){
            note[ransomNote.charAt(i)-'a']--;
        }
        //还是有区别,这个题只是判断A是否在B中出现,我先讲数量大的数据存入数组,然后再判断数量小的数组是否在数组中
        //其实在本题的情况下,使用map的空间消耗要比数组大一些的,因为map要维护红黑树或者哈希表,而且还要做哈希函数,是费时的!数据量大的话就能体现出来差别了。 所以数组更加简单直接有效!
        for(int i=0;i<note.length;i++){
            if(note[i]<0){
                return false;
            }
        }
        return true;
    }
}

三数之和 

建议:本题虽然和 两数之和 很像,也能用哈希法,但用哈希法会很麻烦,双指针法才是正解,可以先看视频理解一下 双指针法的思路,文章中讲解的,没问题 哈希法很麻烦。 

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

看到题目的第一想法

     用哈希,先存入map再循环

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

          

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

          双指针,细节比较多

1 先排序

双指针,一个指针指向i,另外设置left和right指针,left指向i的后一个指针,right指向数组的最后位置来

进行相加操作来分别判断
        其中题干要求返回三元组,但是数值不能重复(返回的是数值数组不是下标)
        需要考虑去重问题,当i与后面的相等,重复值不用处理了,往后continue,当left和right处理完后,left++,right--,
        直到不相等为止
        其中i的处理需要额外考虑相同值的问题,返回的三元组是会出现相同的值的[nums[i],nums[j],nums[k]] 
        因为要允许结果出现 nums[i]==nums[j],所以不能i与后面的相等直接就continue,需要考虑结果有相同值i>0的问题,
        先要让i处理了一次,所以要i>0后再continue

        
    

自己实现过程中遇到的困难
class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        //三个不同的下标,同时满足nums[i]+nums[j]+nums[k]==0
        //哈希做法,先存入map再双重循环?
        //卡哥做法,用双指针来实现,先对数组排序
        //1双指针,一个指针指向i,另外设置left和right指针,left指向i的后一个指针,right指向数组的最后位置
        //来进行相加操作来分别判断
        //其中题干要求返回三元组,但是数值不能重复(返回的是数值数组不是下标)
        //需要考虑去重问题,当i与后面的相等,重复值不用处理了,往后continue,当left和right处理完后,left++,right--,
        //直到不相等为止
        //其中i的处理需要额外考虑相同值的问题,返回的三元组是会出现相同的值的[nums[i],nums[j],nums[k]] 
        //其中允许出现 nums[i]==nums[j],所以不能i与后面的相等直接就continue,需要考虑相同值的问题,
        //先要让i处理了一次后再continue
        Arrays.sort(nums);
        List<List<Integer>> resultList = new ArrayList<List<Integer>>();
        
        for(int i=0;i<nums.length;i++){
            //这个点没想到
            if(nums[i]>0){
                return resultList;
            }
            int left = i+1;
            int right = nums.length-1;
            //去重处理,注意nums[i]==nums[i-1]这个判定,注定i必须要执行了一次后再进行去重处理,要考虑重复的nums[i]也满足
            if(i>0&&nums[i]==nums[i-1]){
                continue;
            }
            while(left<right){
                int sum = nums[i]+nums[left]+nums[right];
                if(sum>0){
                    right--;
                }else if(sum<0){
                    left++;
                }else{
                    //等于0时记录这三个数同时让left和right去重
                    resultList.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    /*List<Integer> list = new ArrayList<Integer>();
                    list.add(nums[i]);
                    list.add(nums[left]);
                    list.add(nums[right]);
                    resultList.add(list);*/
                    //去重操作
                    while(left<right&&nums[left]==nums[left+1]) left++;
                    while(left<right&&nums[right]==nums[right-1]) right--;
                    //注意这里最后还要进行一次left++和right--,因为left之后指的位置应该是下一个元素了
                    //但是上面的while循环走完,nums[left]!=nums[left+1]时,我们应该把指针指向left+1所以还要走一位
                    left++;
                    right--;
                }
            }
        }
        return resultList;
 
 
 
    }
}

四数之和

建议: 要比较一下,本题和 454.四数相加II 的区别,为什么 454.四数相加II 会简单很多,这个想明白了,对本题理解就深刻了。 本题 思路整体和 三数之和一样的,都是双指针,但写的时候 有很多小细节,需要注意,建议先看视频。 

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

看到题目的第一想法

     和三数之和一样,不过要加个for

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

          

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

           只有当nums[i]>0且nums[i]>target时,才剪枝,同样进行剪枝(i>0&&nums[i]>target)和

           需要给第二个for循环里面的j 去重(j>i+1&&nums[j]==nums[j-1])操作

        
    

自己实现过程中遇到的困难
class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        //四数相加II返回的是个数,而这个返回的是每个内容
        //四数相加II 是有四个数组
        //在三数之和上再加一个循环?ij,left right?
        //三个不同的下标,同时满足nums[i]+nums[j]+nums[k]==0
        //哈希做法,先存入map再双重循环?
        //卡哥做法,用双指针来实现,先对数组排序
        //1双指针,一个指针指向i,另外设置left和right指针,left指向i的后一个指针,right指向数组的最后位置
        //来进行相加操作来分别判断
        //其中题干要求返回四元组,但是数值不能重复(返回的是数值数组不是下标)
        //需要考虑去重问题,当i与后面的相等,重复值不用处理了,往后continue,当left和right处理完后,left++,right--,
        //直到不相等为止
        //其中i的处理需要额外考虑相同值的问题,返回的三元组是会出现相同的值的[nums[i],nums[j],nums[k]] 
        //其中允许出现 nums[i]==nums[j],所以不能i与后面的相等直接就continue,需要考虑相同值的问题,
        //先要让i处理了一次后再continue
        //j也同理,需要考虑j去重的问题j>i+1&&nums[j]==nums[j-1]
        Arrays.sort(nums);
        List<List<Integer>> resultList = new ArrayList<List<Integer>>();
        
        for(int i=0;i<nums.length;i++){
            //这个点没想到,剪枝操作,负数不用这样考虑,正数可以
            if(nums[i]>0&&nums[i]>target){
                return resultList;
            }
            //去重处理,注意nums[i]==nums[i-1]这个判定,注定i必须要执行了一次后再进行去重处理,要考虑重复的nums[i]也满
            if(i>0&&nums[i]==nums[i-1]){
                continue;
            }
            for(int j=i+1;j<nums.length;j++){
            int left = j+1;
            int right = nums.length-1;
            //下面这个j>i+1如果不加的话也会报错,如果没加这个判断,j的第一步可能没有考虑到去重的
            if(j>i+1&&nums[j]==nums[j-1]){
                continue;
            }
            while(left<right){
                int sum = nums[i]+nums[j]+nums[left]+nums[right];
                if(sum>target){
                    right--;
                }else if(sum<target){
                    left++;
                }else{
                    //等于0时记录这三个数同时让left和right去重
                    resultList.add(Arrays.asList(nums[i], nums[j],nums[left], nums[right]));
                    /*List<Integer> list = new ArrayList<Integer>();
                    list.add(nums[i]);
                    list.add(nums[left]);
                    list.add(nums[right]);
                    resultList.add(list);*/
                    //去重操作
                    while(left<right&&nums[left]==nums[left+1]) left++;
                    while(left<right&&nums[right]==nums[right-1]) right--;
                    //注意这里最后还要进行一次left++和right--,因为left之后指的位置应该是下一个元素了
                    //但是上面的while循环走完,nums[left]!=nums[left+1]时,我们应该把指针指向left+1所以还要走一位
                    left++;
                    right--;
                }
            }
            }
        }
        return resultList;
 
 
 
    }
}

  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值