首页 > 其他分享 >四数相加II & 赎金信 & 三数之和 & 四数之和

四数相加II & 赎金信 & 三数之和 & 四数之和

时间:2023-02-13 23:45:23浏览次数:54  
标签:map 四数 nums int 三数 II right 数组 left

一、四数相加Ⅱ

454. 四数相加 II

1.方法概述

  • 首先定义一个map,key放a和b两数之和,value 放a和b两数之和出现的次数。遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中。定义int变量count,用来统计 a+b+c+d = 0 出现的次数。在遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就用count把map中key对应的value也就是出现次数统计出来。最后返回统计值 count 就可以了。

2、具体实现

Java实现

点击查看代码
class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        Map<Integer,Integer> map = new HashMap<>();
        int tmp;
        int ret = 0;
        for(int i:nums1){
            for(int j:nums2){
                tmp = i+j;
                if(map.containsKey(tmp)){
                    map.put(tmp,map.get(tmp)+1);
                }else{
                    map.put(tmp,1);
                }
            }
        }
        for(int i:nums3){
            for(int j:nums4){
                tmp = i+j;
                if(map.containsKey(0-tmp)){
                    ret += map.get(0-tmp);
                }
            }
        }
        return ret;
    }
}

3.要点总结

  • 因为本题即涉及到目标值又涉及到次数的统计,可以考虑使用map来解决。map的key来存放值,value来存放出现的次数。
  • 本题是四个独立的数组,只要找到A[i] + B[j] + C[k] + D[l] = 0就可以,不用考虑有重复的四个元素相加等于0的情况。
  • 两两数组匹配寻找在时间效率上更优。

二、救赎金

383. 赎金信

1.方法概述

  • 本题判断第一个字符串ransom能不能由第二个字符串magazines里面的字符构成,首先创建一个大小为26的数组来记录,字母出现的位置和次数。使用增强for和toCharArray()来遍历字符串,第一个字符串字母-'a'存入数组所对应的下标对应值+1用来记录出现次数.第二个字符串字母-'a'对应的下标对应值-1。最后遍历数组中是否含有<0的情况即可。

2.具体实现

Java实现

点击查看代码
class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        int[] arr = new int[26];
        for(char c : magazine.toCharArray()){
            arr[c-'a'] +=1;
        }

        for(char c:ransomNote.toCharArray()){
            arr[c-'a'] -=1;
        }

        for(int i:arr){
            if(i<0){
                return false;
            }
        }
        return true;
    }
}

3.要点总结

  • 因为题目所只有小写字母,那可以采用空间换取时间的哈希策略,用一个长度为26的数组还记录magazine里字母出现的次数。然后再用ransomNote去验证这个数组是否包含了ransomNote所需要的所有字母。
  • toCharArray() 方法将字符串转换为字符数组。

三、三数之和

1.方法概述

  • 引用解法。首先将给定整数数组进行排序,使其从小到大依次排列。然后最外层使用for循环,i从下标0开始,同时定义一个位置在i+1上的left下标,定义一个在数组末尾位置上的right下标。在数组中查找a(nums[i])+b(nums[left])+c(nums[right])=0。当a+b+c>0,说明三数之和大了,需要right下标向左移动,如果a+b+c<0则需要left向右移动。当a+b+c=0时将元素值存放到二维数组ret中。因为该题需要不重复的三元组(组里面的元素可以重复),接下来就是a,b,c的去重操作。首先是a的去重,因为首先是在第一个元素确定的情况下查找的剩下两个元素,如果当第一个元素重复时就说明这样的情况已近存在,需要去重。同理接下来就是b,c的去重。最后返回ret。

2.具体实现

Java实现

点击查看代码
class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> ret = new ArrayList<>();
        Arrays.sort(nums);
        for(int i = 0;i<nums.length;i++){
            if(nums[i] > 0){
                return ret;
            }
            if(i>0 && nums[i] == nums[i-1]){
                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{
                    ret.add(Arrays.asList(nums[i],nums[left],nums[right]));
                    while(right>left && nums[right] == nums[right-1]){
                        right--;
                    }
                    while(right > left && nums[left] == nums[left+1]){
                        left++;
                    }
                    right--;
                    left++;
                }
            }
        }
        return ret;
    }
}

3.要点总结

  • 首先将数组进行排序,本题原数组元素和下标对本题的解决无影响,可以先进行排序,方便后面的查找遍历以及去重操作。
  • 本题的难点在于三元组不重复,在查找目标元素时需要去重操作。去重操作的核心就是判断三元组的第一个元素是否在它之前出现过,如果出现过,则证明该元素已近遍历过,在遍历同样的元素,必定导致重复三元组的出现。
  • 在for循环这层遍历中,left和right需要不停的遍历寻找匹配元素,同时也需要去重操作,去重的思想和a的去重思想是一致。判断下一个元素是否和上一个出现元素相同,不同点是一个是从i+1下标开始遍历,另一个是从数组末端下标开始遍历。如果大了,说明right需要左移,如果小了,说明left需要右移,否则存入到二维数组中去,直到相遇,停止while层循环(因为题设要求满足i != left != right),进入下一次for循环。
  • 还有一个关键点是b,c的去重要建立在存在一个三元组之后,否则就都会被去掉。
  • 当b,c去重以后指针实际指向与第二位b(与第三位c)相同的数,因此指针需要移动指向不同的数,因此还需要left++,right--;

四、四数之和

18. 四数之和

1.方法概述

  • 总体思想和三数之和一样,只是需要在最外层再套一个for循环来确定一个元素。

2.具体实现

Java实现

点击查看代码
class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> ret = new ArrayList<>();
        Arrays.sort(nums);

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

3.要点总结

  • 不要判断nums[k] > target 就返回了,三数之和 可以通过 nums[i] > 0 就返回了,因为 0 已经是确定的数了,四数之和这道题目 target是任意值。比如:数组是[-4, -3, -2, -1],target是-10,不能因为-4 > -10而跳过。但是我们依旧可以去做剪枝,逻辑变成nums[i] > target && (nums[i] >=0 || target >= 0)就可以了。
  • 因为只要 nums[k] + nums[i] > target,那么 nums[i] 后面的数都是正数的话,就一定不符合条件了。

标签:map,四数,nums,int,三数,II,right,数组,left
From: https://www.cnblogs.com/neverlate/p/17118315.html

相关文章