代码随想录算法训练营第六天/454.四数相加2、383.赎金信、15.三数之和、18.四数之和

目录

今日内容:

454.四数相加2

383.赎金信

15.三数之和

18.四数之和


454.四数相加2

题目链接:https://leetcode.cn/problems/4sum-ii/submissions/

第一想法:之前有做“二数之和”,想着应该都有相通之处,都是不知道该如何进行处理。

学习代码随想录后:和“二数之和”总体是一样的流程,理解过程也是如此,唯一发生变化的是Mao集合的key-value发生变化;四个数组分别找到里面的数相加等于0,每次找到一个四个数的集合,最后统计共有几个符合要求的集合,那么先遍历前两个数组,获取到这两个数组内数相加得的任何情况,然后将得到相加后值作为key,这个相加值出现次数为value,需要注意:先要判断map中是否已经包含此相加值,若包含则需要更新此相加值对应的出现次数也就是value值(重新put);之后遍历余下的两个数组,获取到后两个数相加的和,用0减去获得目标数,判断map集合中是否包含有此目标数,若包含则获取到对应的value值,即出现次数,直到循环结束后返回最终的总次数值。

注意:在完成此题过程中在更新value值时,想法出现了误区:认为只要将对应次数即value进行改变,那么Map集合中key对应的这个value值就会自动更新;正确的是当发生改变要重新put。

class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        Map<Integer,Integer> map=new HashMap<Integer,Integer>();
        int sum=0;
        int count=0;
        int countsum=0;
        for(int i:nums1){
            for(int j:nums2){
                sum=i+j;
                if(map.containsKey(sum)){
                    count=map.get(sum)+1;
                    map.put(sum,count);
                }else{
                map.put(sum,1);
                }
            }
        }

        for(int i:nums3){
            for(int j:nums4){
                int target=0-(i+j);
                if(map.containsKey(target)){
                    countsum+=map.get(target);
                }
            }
        }
        return countsum;
    }
}


383.赎金信

题目链接:https://leetcode.cn/problems/ransom-note/

第一想法:看到题目后就想到之前做的一道“判读是否是异位词”的题目,然后按照那个思路发现是可行的。

学习代码随想录后:和我自己开始想到的方向思路是一致的,这道题和判断异位词是一样的。

思路:这道题要注意题目说明的一点:在杂志词里面每个字母都只能出现一次,且都是小写字母;首先创建一个长度为26的整型数组,先遍历赎信词然后按照规律方法将字母放到它对应数组位置,并且统计频数,所以这里需要++,目的是统计每个字母的频数;之后遍历杂志词,方法都是一样的,只是对应字母出现的话需要在那个位置--,与原来统计赎信词的各字母统计频数进行加减,最后若数组都是小于或者等于0,说明符合要求。

class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        int [] result=new int[26];
        for(int i=0;i<ransomNote.length();i++){
            result[ransomNote.charAt(i)-'a']++;
        }

        for(int j=0;j<magazine.length();j++){
            result[magazine.charAt(j)-'a']--;
        }

        for(int i=0;i<result.length;i++){
            if(!(result[i]<=0)){
                return false;
            }
        }
        return true;
    }
}


以下是三数之和和四数之和,这两题的思路是完全相同的;如果在碰到需要求一个数组中的n数之和都是采取此方法,只是需要根据n等于几来增加for循环的次数,还要一些判断条件。

学习代码随想录后:“双指针法”,因为使用双指针法,所以先要对数组进行排序;

应用这道题需要:

1.首先设置一个for循环用于遍历数组也就是三数之和的第一个数,然后设置一个左指针指第二个数,最后是在数组末尾的右指针指向第三个数;所求三数之和为0,所以判断在当前位置时的三数之和,当大于0时,说明偏大,因为数组是排序好的,因此右指针需要往前移动;所求三数之和小于0,说明偏小,所以左指针需要往右移;若刚好为0就将这几个数的数组转化成链表添加进入大链表中;

2.在同一个数组中所有的三数之和的可能会出现重复的,所以去重是一大关键也是难点,首先是第一个数称为a,a的判断条件是(i>0&&nums[i]==nums[i-1]),这个表示当a遇到相同的就跳过,但是要按照这种方法来跳过;接着是left和right指针,这两个指针是判断当left的下一个和right的上一个相同的话就再过一个位置表示跳过;这个左右指针接着1中的最后一种情况:在加入满足要求的链表后需要继续遍历数组找寻是否还有满足要求的,这里要对左右指针进行判断,判断左指针下一个和右指针上一个是否重复,若是首先就到这个重复的位置,然后接下来位置继续移动达到跳过的效果;若不同左指针就继续往右移动,右指针也如此。

3.在刚开始进行循环时,需要判断第一个数,若大于0,那么就说明根本不可能成立,因为后面的数都比第一个数大。

关于四数之和:四数之和和以上三数之和的流程和理解都是一样的,只是需要再多一些判断,比如说求四个数之和,那么需要再多一层for循环来表示第二个数,那么左指针就在这第二个数之后;然后还有四数甚至其他题目出现的n数之和,并不一定所求值为0,也可能为其他target值,target值是不确定的,无法得知是正或负,所以还要留意对此进行多一个判断---例如:数组是[-4,-1,-2,-3],target是-10,那么如果直接判断nums[i]>target就不成立了,因为target是负数,这个情况可能说清楚有点困难,所以还是看四数之和的文章来帮助理解会比较好。

15.三数之和

题目链接:https://leetcode.cn/problems/3sum/

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
       List<List<Integer>> list = new ArrayList<>();
       Arrays.sort(nums);
       for(int i=0;i<nums.length;i++){
           if(nums[i]>0){
               return list;
           }
           if(i>0&&nums[i-1]==nums[i]){
               continue;
           }
            
            int left=i+1;
            int right=nums.length-1;
            while(right>left){
                int sum=nums[i]+nums[left]+nums[right];
                if(sum>0){
                    right--;
                }else if(sum<0){
                    left++;
                }else{
                    list.add(Arrays.asList(nums[i],nums[left],nums[right]));
                    while(right>left&&nums[left]==nums[left+1])left++;
                    while(right>left&&nums[right]==nums[right-1])right--;
                    left++;
                    right--;
                }
            }
       }
       return list;
}
}

18.四数之和

题目链接:https://leetcode.cn/problems/4sum/submissions/

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> list=new ArrayList<List<Integer>>();
        Arrays.sort(nums);
        for(int i=0;i<nums.length;i++){
            if(nums[i]>0&&nums[i]>target){
                return list;
            }

            if(i>0&&nums[i]==nums[i-1]){
                continue;
            }

            for(int j=i+1;j<nums.length;j++){
                if(j>i+1&&nums[j]==nums[j-1]){
                    continue;
                }
                int left=j+1;
                int right=nums.length-1;
                while(right>left){
                    int sum=nums[i]+nums[j]+nums[left]+nums[right];
                    if(sum>target){
                        right--;
                    }else if(sum<target){
                        left++;
                    }else{
                        list.add(Arrays.asList(nums[i],nums[j],nums[left],nums[right]));
                        while(right>left&&nums[left]==nums[left+1])left++;
                        while(right>left&&nums[right]==nums[right-1])right--;
                        left++;
                        right--;
                    }
                }
            }
        }
        return list;
    }
}

总结:

今日的题目对于三数之和是最大的难点,里面要考虑到的去重问题,还要一些判断都是比较复杂的,所以要加强对这题的印象,理解完三数之和后,之后的n数之和都可以运用此法,只是需要添加for循环还有一些判断。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值