【前端er每日算法】hash之几数之和--454/383/15/18

70 阅读1分钟

题目一 454. 四数相加 II

思路

用hash法,hash存储前两个数字可能的和的次数,再循环遍历后两个数,看hash里相加符合0的次数,整体相加即为所求。

var fourSumCount = function(nums1, nums2, nums3, nums4) {
    const hash = {};
    for (let i = 0; i < nums1.length; i++) {
        for (let j = 0; j < nums2.length; j++) {
            let sum = nums1[i] + nums2[j];
            if (!hash[sum]) {
                hash[sum] = 1;
            } else {
                hash[sum]++;
            }
        }
    }
    let count = 0;
    for (let i = 0; i < nums3.length; i++) {
        for (let j = 0; j < nums4.length; j++) {
            let sum = nums3[i] + nums4[j];
            if (hash[0 - sum]) {
                count += hash[0 - sum];
            }
        }
    }
    return count;
};

题目二 383. 赎金信

思路

比较简单,对magazine做hash,然后遍历ransomNote看hash的值,如果不存在,直接返回false,遍历完成则返回true

var canConstruct = function(ransomNote, magazine) {
    const hash = {};
    for (let i = 0; i < magazine.length; i++) {
        const char = magazine[i];
        if (!hash[char]) {
            hash[char] = 1;
        } else {
            hash[char]++;
        }
    }
    for (let i = 0; i < ransomNote.length; i++) {
        const char = ransomNote[i];
        if (hash[char]) {
            hash[char]--;
        } else {
            return false;
        }
    }
    return true;
};

题目三 15. 三数之和

思路

一层循环+快慢指针,难点在于去重,还想了好大会,但需要举例子才理解。

  • a去重:比较i与i-1的大小,并且i大于0,这样前面遍历过的数字不需要再去循环,因为前面的值是包含后面的所有结果的。
  • b、c去重:在找到之后,判断是否有相同元素,有的话,left++或者right--,跳过这个元素,不用再做收集。
var threeSum = function(nums) {
    nums.sort((a, b) => a - b);
    const len = nums.length;
    if (nums[0] > 0) {
        return [];
    }
    let result = [];
    for (let i = 0; i < len; i++) {
        if (i > 0 && nums[i - 1] === nums[i]) {
            continue;
        }
        let left = i + 1;
        let right = len - 1;
        while (left < right) {
            if (nums[i] + nums[left] + nums[right] < 0) {
                left++;
            } else if (nums[i] + nums[left] + nums[right] > 0) {
                right--;
            } else {
                result.push([nums[i], nums[left], nums[right]]);
                while (left < right && nums[left] === nums[left + 1]) {
                    left++;
                }
                while (left < right && nums[right] === nums[right - 1]) {
                    right--;
                }
                left++;
                right--;
            }
        }
    }
    return result;
};

题目四 18. 四数之和

思路

和三数之和类似,但是是两层for循环,加上快慢指针。

var fourSum = function(nums, target) {
    nums.sort((a, b) => a - b);
    const len = nums.length;
    let result = [];
    for (let i = 0; i < len - 3; i++) {
        if (nums[i] > target && nums[i] > 0) {
            break;
        }
        if (i > 0 && nums[i] === nums[i - 1]) {
            continue;
        }
        for (let j = i + 1; j < len - 2; j++) {
            if (nums[i] + nums[j] > target && nums[i] + nums[j] >= 0) {
                break;
            }
            if (j > i + 1 && nums[j] === nums[j - 1]) {
                continue;
            }
            let left = j + 1;
            let right = len - 1;
            while (left < right) {
                const sum = nums[i] + nums[j] + nums[left] + nums[right]
                if (sum > target) {
                    right--;
                } else if (sum < target) {
                    left++;
                } else {
                    result.push([nums[i], nums[j], nums[left], nums[right]]);
                    while(left < right && nums[left] === nums[left + 1]) {
                        left++;
                    }
                    while(left < right && nums[right] === nums[right - 1]) {
                        right--;
                    }
                    left++;
                    right--;
                }
            }
        }
    }
    return result;
};

总结

脑图总结一波几数之和相关的题目。

WechatIMG217.jpeg