【KOKO-代码随想录算法训练营Day 8 |454 |383 |15|18 】

KOKO-代码随想录算法训练营Day 8 |454 |383 |15|18



一、454.四数相加II

1.题目

https://leetcode.cn/problems/4sum-ii/

2.代码

public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        Map<Integer,Integer> map = new HashMap<>();
        int n=nums1.length;
        int res=0;
        for (int i = 0; i <n ; i++) {
            for (int j = 0; j <n ; j++) {
                int target1=nums1[i]+nums2[j];
                    map.put(target1,map.getOrDefault(target1,0)+1);
            }
        }
        for (int i = 0; i < n; i++) {
            for (int j = 0; j <n ; j++) {
               int targer2=nums3[i]+nums4[j];
               if(map.containsKey(0-targer2)&&map.get(0-targer2)>0){
                  res+=map.get(0-targer2);
               }
            }
        }
        return res;
    }

3.总结

四数相加取遍每个下标,下标不重复则值不重复,用map存储key<(nums1[i]+nums2[j]),次数>,找两数相加等只需用map获取target-当前值,判断key是否存在即可。用map中的key是否存在判断两个数的和。
map中的value存的是次数,因为取的是每个下标中符合target的元素。

二、 383. 赎金信

1.题目

https://leetcode.cn/problems/ransom-note/

2.代码

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

3.总结

和字母异位词类似,用标记数组的值>0或<0判断是否有被用完。

三. 15. 三数之和

1.题目:

https://leetcode.cn/problems/3sum/

2.代码:

    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(nums);//-4,-1,-1,0,1,2
        if (nums[0] > 0 || nums[nums.length - 1] < 0) {
            return res;
        }
        int i = 0;
        while (i < nums.length) {
            if (nums[i] > 0) {
                return res;
            }
            int j = i + 1;
            int k = nums.length - 1;
            if (i > 0 && nums[i - 1] == nums[i]) {
                i++;
                continue; //i==i-1时跳过
            }
            while (j < k) {
                int num = nums[i] + nums[j] + nums[k];
                if (num < 0) {
                    j++;
                    while (j < k && nums[j - 1] == nums[j]) {
                        j++;
                    }
                } else if (num > 0) {
                    k--;
                     while (j < k && nums[k +1] == nums[k]) {
                        k--;
                    }
                } else {
                    List<Integer> temp = new ArrayList<>();
                    temp.add(nums[i]);
                    temp.add(nums[j]);
                    temp.add(nums[k]);
                    res.add(temp);
                    while (j < k && nums[k - 1] == nums[k]) {
                        k--;
                    }
                    while (j < k && nums[j + 1] == nums[j]) {
                        j++;
                    }
                    j++; //2,1
                    k--;
                }
            }
            i++; //1
        }
        return res;
    }

3.总结:

重点是去重,对left,对right的去重。
我在做该题时用了while,实际上for较简单,只需让i到nums.length即可,不用取到nums.length-2。
另外,不必对j和k在没取到目标值时进行剪枝,因为剪枝和得到的结果不为0时做的操作是相同的,相当于加了一次操作,所以不该在此处剪枝,应当在nums[i]+nums[j]+nums[k]=target时剪枝。

四. 18. 四数之和

1.题目:

https://leetcode.cn/problems/4sum/

2.代码:

 public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> res=new ArrayList<>();
        Arrays.sort(nums);
        for (int i = 0; i <nums.length ; i++) {
            if(nums[i]>target&&nums[i]>=0){
                return res;
            }
            if(i>0&&nums[i-1]==nums[i]){
                continue;
            }
            int j=i+1;
            for (;j<nums.length; j++) {
                int left=j+1;
                int right=nums.length-1;
                if(j>i+1&&nums[j-1]==nums[j]){
                    continue;
                }
                while (left<right){
                    int num=nums[i]+nums[j]+nums[left]+nums[right];
                    if(num<target){
                        left++;
                    }else if(num>target){
                        right--;
                    }else{
                        List<Integer> temp=new ArrayList<>();
                        temp.add(nums[i]);
                        temp.add(nums[j]);
                        temp.add(nums[left]);
                        temp.add(nums[right]);
                        res.add(temp);
                        while (left<right&&nums[right-1]==nums[right]){
                            right--;
                        }
                        while (left<right&&nums[left+1]==nums[left]){
                            left++;
                        }
                        right--;
                        left++;
                    }
                }
            }
        }
        return res;
    }

3.总结:

四数之和,固定i,固定j,用j作为三数之和的i,继续用left,right.
剪枝时要对i剪,也要对j剪,对j剪应该是从j>i+1开始。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值