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

33 阅读3分钟

454.四数相加II

相关链接: 题目链接 文章讲解 视频讲解

解题思路

分别先求两个数组的和,然后剩下的两个数组的和。 最后加起来就是四个数组的和;

可以看成两个数组的和

代码

var fourSumCount = function(nums1, nums2, nums3, nums4) {
    var map = new Map(),
        count = 0;
    for(let i = 0; i < nums1.length; i++){
        for(let j = 0; j < nums2.length; j++){
            let val = nums1[i] + nums2[j]
            if(!map.has(val)){
                map.set(val, 1)
            }else{
                var value = map.get(nums1[i] + nums2[j])
                 map.set(nums1[i] + nums2[j], value + 1)
            }
        }
    }

    for(let l = 0; l < nums3.length; l++){
        for(let r = 0; r < nums4.length; r++){
            let target = 0 - (nums3[l] + nums4[r]);
            if(map.has(target)){
                count += map.get(target);
            }
        }
    }
    return count;
};

383. 赎金信

相关链接: 题目链接 文章讲解 

解题思路

代码

var canConstruct = function(ransomNote, magazine) {
    var map = new Map();
    for(let i = 0; i< magazine.length; i++){
        if(!map.has(magazine[i])){
            map.set(magazine[i],1)
        }else{
            let val = map.get(magazine[i]);
            map.set(magazine[i], val + 1);
        }
    }

    for(let j = 0; j <ransomNote.length; j++){
        let res = map.get(ransomNote[j]);
        if(res > 0){
            map.set(ransomNote[j], res - 1);
        }else{
            return false;
        }
    }
    return true;
};

15. 三数之和

相关链接: 题目链接 文章讲解 视频讲解

解题思路

双指针

  • 先排序,后查找

  • 重点:nums[i] === nums[i-1]; 去重并避免把重复结果的结果集漏掉

代码

var threeSum = function(nums) {
    var res = [];
    nums.sort(function(a,b){
       return  a-b;
    });

    for(let i = 0;i<nums.length; i++){
        if(nums[i] > 0 ) return res;
        if(i > 0 && nums[i] === nums[i - 1]) continue;
        let left= i + 1, right = nums.length - 1;
        while(right > left){
            if((nums[i] + nums[left] + nums[right]) > 0){
                right--;
            }else if ((nums[i] + nums[left] + nums[right]) < 0){
                left++;
            }else{
                res.push([nums[i], nums[left], nums[right]]);
                // // right 去重
                // while(left < right && (nums[right] === nums[right - 1])){
                //     right--;

                // }
                // //left 去重
                // while(left < right && (nums[left] === nums[left + 1])){
                //     left++;
                    
                // }
                // left++;
                // right--;
               
                while(left < right){
                    if(nums[right] === nums[right - 1]){
                        right--;
                    }else if(nums[left] === nums[left + 1]){
                        left++;
                    }else{ 
                        break;
                    }
                }
            //   如果没有找到重复的则直接相加
                left++;
                right--;
            }
        }
    }
    return res;
};

18. 四数之和

相关链接: 题目链接 文章讲解 视频讲解

解题思路

在三数之和的基础上,多加一层循环

剪枝:主要是 target 有可能是负值,-6 = -5 + -1,所以需要过滤 target 负数 去重: i> 0 && nums[i] === nums[i - 1] 注意这样写

代码

var fourSum = function(nums, target) {

    // target 有可能是负数
    var result = [];
    const len = nums.length;
    if(len < 4) return result;
    nums.sort(function(a, b){
        return a - b;
    })
    for(let i = 0; i < len; i++){
        //剪枝 target 负数的话, -6 = -5 + -1,所以需要过滤 target 负数
        if(nums[i] > target && target > 0){
            return result;
        }
        // 去重
        if(i> 0 && nums[i] === nums[i - 1]){
            continue;
        }
        for(let j = i + 1; j < len; j++){
            let res = nums[i] + nums[j];
            //剪枝 target 负数的话, -6 = -5 + -1,所以需要过滤 target 负数
            //并且需要保证 j 紧跟着 i
            // eg: 比如这个例子,排序后是 [-10, -9, -8, -8, -8, -7, -2, 0, 0, 1, 3, 5, 6, 7, 7, 8, 8] 在i = -2,j = 7的时候直接return了,就漏掉了0,0,1,3
            if(res > target && target > 0 && i+1 == j){
                 return result;
            }
            //去重
            if(j > i + 1 && nums[j] === nums[j-1]){
                continue;
            }
            let l = j + 1, r = len - 1;
            while(r > l){
                let sum = nums[i] + nums[j] + nums[l] + nums[r];
                if(sum > target){
                    r--;
                }else if(sum < target){
                    l++;
                }else{
                    result.push([nums[i],nums[j],nums[l],nums[r]]);
                   while(r > l && nums[l] === nums[l + 1]){
                        l++;
                    }
                    while(r > l && nums[r] === nums[r - 1]){
                        r--;
                    }
                    l++;
                    r--;
                }
            }
        }
    }
    return result;
};