代码随想录算法训练营day07|四数相加Ⅱ、赎金信、三数之和、四数之和

2023.3.21 四数相加Ⅱ

454. 四数相加 II - 力扣(LeetCode)

由于题目只需要求出有多少个数组能够满足要求即可,所以我们可以直接使用哈希表,先储存前两个数组的元素和的信息,令元素和为key,值value存放元素和出现的次数。随后在根据后两个数组中的元素和来判断哈希表中是否有对应的数,如果有,将value计入结果中即可。

关键点,要想到把多个组别拆分为两组,一组计入哈希表,另一组根据要求结果计算出需要的值再哈希表中进行查找。

之前都是遇到的两个组的情况,现在有四个组,突然不知道咋做了。。。没想到分段处理。

class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        Map<Integer,Integer> hashMap = new HashMap<>();
        int res = 0;
        //双重循环记录两个数组相加的结果
        for(int x : nums1){
            for(int y : nums2){
                int add = x+y;
                hashMap.put(add,hashMap.getOrDefault(add,0)+1);
            }
        }
        for(int x : nums3){
            for(int y : nums4){
                int target = 0-(x+y);
                if(hashMap.containsKey(target)){
                    res += hashMap.get(target);
                }
            }
        }
        return res;
    }
}

2023.3.21 赎金信

383. 赎金信 - 力扣(LeetCode)

由于magazinez中的每个字符只能在ransomNote中使用一次

所以我们的magazine长度至少要等于ransomNote。

随后我们将magazine中出现的英文字母记录进数组中,

方法一:利用数组记录信息

class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        if(magazine.length() < ransomNote.length()){
            return false;
        }
        int[] res = new int[26];
        for(int i = 0;i<magazine.length();i++){
            res[magazine.charAt(i)-'a']++;
        }
        for(int i = 0;i<ransomNote.length();i++){
            res[ransomNote.charAt(i)-'a']--;
        }
        for(int x : res){
            if(x<0){
                return false;
            }
        }
        return true;
    }
}

方法二:哈希表

class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        if(magazine.length() < ransomNote.length()){
            return false;
        }
        Map<Character,Integer> hashMap = new HashMap<>();
        for(int i = 0;i<magazine.length();i++){
            char c = magazine.charAt(i);
            hashMap.put(c,hashMap.getOrDefault(c,0) + 1);
        }
        for(int i = 0;i<ransomNote.length();i++){
             char c = ransomNote.charAt(i);
            hashMap.put(c,hashMap.getOrDefault(c,0) - 1);
            if(hashMap.get(c) < 0){
                return false;
            }
        }
        return true;
    }
}

2023.3.21 三数之和

15. 三数之和 - 力扣(LeetCode)

由于题目要求我们求出三个元素满足其和为0,它并不需要我们求出元素的下标,因此我们可以对数组元素进行排序处理,随后使用指针对其进行循环判断即可。

如当我们对数组排序后,令i为数组第一个元素,j为i的右侧元素,k为数组最后一个元素,

如果nums[i]+nums[j]+nums[k]>0,说明我们需要k元素大了,需要向左移动k的位置

同理,如果nums[i]+nums[j]+nums[k]

当满足nums[i]+nums[j]+nums[k] = 0时,记录List中即可。

同时,题目要求我们结果中不能出现重复的三元组,这意味着我们的结果中数组元素不能用相同值。

首先考虑i的去重,由于i是向右移动的,当其值与左侧值相同时,由于左侧的元素已经做过一次判断,所以这次的元素不需要在做判断了,直接continue。

j的去重,j也是向右移动的,当j与j的左侧值相同时,直接令j继续右移即可。

k的去重,k是向左移动的,当k的值与k右侧的值相同时说明,k的值已经做过一次判断,继续左移。

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        //新建结果List
        List<List<Integer>> res = new ArrayList<>();
        //对数组排序
        Arrays.sort(nums);
        //开始循环遍历
        for(int i = 0;i<nums.length-2;i++){
            //由于数组已经进行过一次排序,因此当nums[i]>0时,此时已经无法满足三个数相加为0的要求了,直接返回结果
            if(nums[i] > 0){
                return res;
            }
            //对i去重
            if(i > 0 &&  nums[i] == nums[i-1]){
                continue;
            }
            int j = i + 1;
            int k = nums.length-1;
            while(j < k){
                int sum = nums[i] + nums[j] + nums[k];
                if(sum > 0){//k需要向左移动
                k--;
                }
                else if(sum < 0){//j需要向右移动
                    j++;
                }
                else{//得到结果
                res.add(Arrays.asList(nums[i],nums[j],nums[k]));
                //得到结果后需要继续移动指针,此时有可能存在重复结果,即k的左侧值与k相同,j的右侧值与j相同,因此我们在这里需要做去重处理,否则可能会有重复的结果。
                while(j < k && nums[k-1] == nums[k]) k--;
                while(j < k && nums[j+1] == nums[j]) j++;
                //不存在重复元素也需要对j和k移动,将k左移,j右移,不能只移动一个,因为如果不是重复元素,必然不会有等于0的结果
                k--;
                j++;
            }
        }
        }
        return res;
    }
}

2023.3.21 四数之和

18. 四数之和 - 力扣(LeetCode)

多了一个元素要如何遍历?,使用双重循环?借鉴三数之和的思路?

错误代码:

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> res = new ArrayList<>();
        //对数组排序
        Arrays.sort(nums);
        for(int a = 0;a < nums.length - 3;a++){
            if(nums[a] > target){
                return res;
            }
            if(a > 0 && nums[a] == nums[a-1]){
                continue;
            }
            for(int b = a + 1;b < nums.length - 2;b++){
                //nums[b]的去重条件
                if(b> a+1 && nums[b] == nums[b-1]){
                    continue;
                }
                int c = b+1;
                int d = nums.length-1;
                while(c < d){
                    int sum = nums[a] + nums[b] + nums[c] + nums[d];
                    if(sum > target){
                        d--;
                    }
                    else if(sum<target){
                        c++;
                    }
                    else{
                        res.add(Arrays.asList(nums[a],nums[b],nums[c],nums[d]));
                        while(c < d && nums[d-1] == nums[d]) d--;
                        while(c < d && nums[c+1] == nums[c]) c++;
                        d--;
                        c++;
                    }
                }
            }
        }
        return res;
    }
}

这里的nums[a] > target判断条件有问题,因为不是三数之和为0的条件了,如果target为负数,即使nums[a]>target,也是可能有结果的。所以我们的条件应该是nums[a]>0 并且nums[a] > target时,就可以退出了。

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> res = new ArrayList<>();
        //对数组排序
        Arrays.sort(nums);
        for(int a = 0;a < nums.length - 3;a++){
            if(nums[a] > 0  && nums[a] > target){
                return res;
            }
            if(a > 0 && nums[a] == nums[a-1]){
                continue;
            }
            for(int b = a + 1;b < nums.length - 2;b++){
                //nums[b]的去重条件
                if(b> a+1 && nums[b] == nums[b-1]){
                    continue;
                }
                int c = b+1;
                int d = nums.length-1;
                while(c < d){
                    int sum = nums[a] + nums[b] + nums[c] + nums[d];
                    if(sum > target){
                        d--;
                    }
                    else if(sum<target){
                        c++;
                    }
                    else{
                        res.add(Arrays.asList(nums[a],nums[b],nums[c],nums[d]));
                        while(c < d && nums[d-1] == nums[d]) d--;
                        while(c < d && nums[c+1] == nums[c]) c++;
                        d--;
                        c++;
                    }
                }
            }
        }
        return res;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值