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

90 阅读2分钟

454.四数相加II

题目链接:454.四数相加II

解题思路🤔

1、首先将四个数组两两分开,求数组元素之和,和出现的次数,放到map中。
2、将求和问题转化为求差问题。 在map中寻找 0-(c+d),把map中key对应的value,即出现次数统计出来。

代码⌨️

var fourSumCount = function(nums1, nums2, nums3, nums4) {
    const twoSumMap = new Map();
    let count = 0;
    // 统计nums1和nums2数组元素之和,和出现的次数,放到map中
    for(const n1 of nums1) {
        for(const n2 of nums2) {
            const sum = n1 + n2;
            twoSumMap.set(sum, (twoSumMap.get(sum) || 0) + 1)
        }
    }
    // 找到如果 0-(c+d) 在map中出现过的话,就把map中key对应的value也就是出现次数统计出来
    for(const n3 of nums3) {
        for(const n4 of nums4) {
            const sum = n3 + n4;
            count += (twoSumMap.get(0 - sum) || 0)
        }
    }

    return count;
};

总结👀


383. 赎金信

题目链接:383. 赎金信

解题思路🤔

1、数组在哈希表中的应用。
2、用一个长度为26的数组来记录magazine里字母出现的次数。
3、然后再用ransomNote去验证这个数组是否包含了ransomNote所需要的所有字母。

代码⌨️

var canConstruct = function(ransomNote, magazine) {
    const strArr = new Array(26).fill(0), 
        base = "a".charCodeAt();
    for(const s of magazine) {  // 记录 magazine里各个字符出现次数
        strArr[s.charCodeAt() - base]++;
    }
    for(const s of ransomNote) { // 对应的字符个数做--操作
        const index = s.charCodeAt() - base;
        if(!strArr[index]) return false;  // 如果没记录过直接返回false
        strArr[index]--;
    }
    return true;
};

总结👀

为什么没有用map?
在本题的情况下,使用map的空间消耗要比数组大一些。因为map要维护红黑树或者哈希表,且还要做哈希函数,是费时的!当数据量大时 就能体现出来差别了。所以数组更加简单直接有效!


15. 三数之和🔥🔥🔥🔥

题目链接:15. 三数之和

解题思路🤔

1、通过双指针方法,查找所有的组合
2、第一步要先将数组排序
3、怎样进行剪枝和去重。
4、因为要求返回的是数值,满足要求的集合。所以可以用双指针法,而两数之和中要求返回索引下标,双指针法一定要排序,导致索引改变,无法使用双指针法。

代码⌨️

var threeSum = function(nums) {
    const res = [], len = nums.length
    // 将数组排序
    nums.sort((a, b) => a - b)
    for (let i = 0; i < len; i++) {
        let l = i + 1, r = len - 1, iNum = nums[i]
        // 数组排过序,如果第一个数大于0直接返回res
        if (iNum > 0) return res
        // 去重
        if (iNum == nums[i - 1]) continue
        while(l < r) {
            let lNum = nums[l], rNum = nums[r], threeSum = iNum + lNum + rNum
            // 三数之和小于0,则左指针向右移动
            if (threeSum < 0) l++ 
            else if (threeSum > 0) r--
            else {
                res.push([iNum, lNum, rNum])
                // 去重
                while(l < r && nums[l] == nums[l + 1]){
                    l++
                }
                while(l < r && nums[r] == nums[r - 1]) {
                    r--
                }
                l++
                r--
            }
        }
    }
    return res
};

18. 四数之和🔥🔥🔥🔥

题目链接:18. 四数之和

解题思路🤔

1、双指针法

代码⌨️

var fourSum = function(nums, target) {
    const len = nums.length;
    if(len < 4) return [];
    nums.sort((a, b) => a - b);
    const res = [];
    for(let i = 0; i < len - 3; i++) {
        // 去重i
        if(i > 0 && nums[i] === nums[i - 1]) continue;
        for(let j = i + 1; j < len - 2; j++) {
            // 去重j
            if(j > i + 1 && nums[j] === nums[j - 1]) continue;
            let l = j + 1, r = len - 1;
            while(l < r) {
                const sum = nums[i] + nums[j] + nums[l] + nums[r];
                if(sum < target) { l++; continue}
                if(sum > target) { r--; continue}
                res.push([nums[i], nums[j], nums[l], nums[r]]);
		
		// 对nums[left]和nums[right]去重
                while(l < r && nums[l] === nums[++l]);
                while(l < r && nums[r] === nums[--r]);
            }
        } 
    }
    return res;
};