【力扣】15. 三数之和

153 阅读1分钟

题目

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

image.png

image.png

一、题目分析

  • 【长度】包含n个整数的数组nums
  • 【累加】不重复的三个元素的和为0

二、开始解题

1、【双指针法】这次一开始就先上双指针试试,和为0的不同三个元素我们用一个数组存储起来。

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function(nums) {
    let arr = nums;
    arr.sort((a, b) => a - b); // 一样的一开始先排个序
    let countZeroArray = [];
    for (let i=0;i<arr.length;i++) {
        let [start, end] = [i+1, arr.length - 1];
        while (start < end) {
            if (i !== start && i !== end) {
                let item = [arr[i], arr[start], arr[end]];
                let count = arr[i] + arr[start] + arr[end];
                // 因为之前排序过,所以去判断三位数的累加和于目标值的关系来判断移动
                // 数字累加之和小于目标值,则开始后移
                if (count <= 0) {
                    start++;
                    if (count === 0) {
                        item = item.toString();
                        if (!countZeroArray.find(li => li === item)) {
                            countZeroArray.push(item);
                        }
                    }
                }
                // 数字累加之和大于目标值,则结束前移
                else{
                    end--;
                }
            } else {
                start++;
            }
        }
    }
    countZeroArray = countZeroArray.map(item => item.split(','));
    return countZeroArray;
};

有了上一篇16【最接近的三数之和】的解题经验,不出意外,还挺顺利,一次就过了👏👏👏~~~~

image.png

2、但执行时间跑的有点久,因该是在和为0的三个元素存储进数组的时候进行的转换操作和避免重复插入的排序操作影响到了~我们调整一下代码试试~~

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function(nums) {
    if (nums.length < 3) return [];
    let arr = nums;
    arr.sort((a, b) => a - b);
    let countZeroDict = {};
    for (let i=0;i<arr.length;i++) {
        let [left, right] = [i + 1, arr.length - 1];
        while (left < right) {
            if (i === left || left === right || i === right) continue;
            let key = `${arr[i]},${arr[left]},${arr[right]}`;
            let keyValue = [arr[i], arr[left], arr[right]];
            let count = arr[i] + arr[left] + arr[right];
            if (count < 0) {
                left++;
            } else if (count > 0) {
                right--;
            } else{
                if (!countZeroDict[key]) {
                    countZeroDict[key] = keyValue;
                }
                left++;
                right--;
            }
        }
    }
    return Object.values(countZeroDict);
};

速度有提升了一点点👏👏~~~

image.png

3、但还是要很久~~~猜测是多跑了一些多余的循环次数,导致代码执行时间超时,优化一下代码结构🤮~~

  1. 首先,因为我们一开始就对代码进行了从小到大排序,那么在遍历中,当nums[i]的值大于0的时候,那三个数的和一定就是大于0,所以可以直接去结束遍历,不用再跑下去了!!!
// 例如:[-3, -2, -1, 0, 1, 2, 3]
// 0之后任何数相加 1000% 会大于 0 ~~🤮直接结束遍历就行
if(nums[i] > 0) break; // add

image.png

加这一句~~快了100ms~~~~👏

  1. 其次就是在计算三个数之和的时候,去重需要重新调整,这样可以减少一些不必要的循环次数,优化代码运行速度。
/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function(nums) {
    if (nums.length < 3) return [];
    nums.sort((a, b) => a - b);
    let countZeroDict = [];
    for (let i=0;i<nums.length;i++) {
        if(nums[i] > 0) break;
        if(i > 0 && nums[i] == nums[i-1]) continue; // 去重
        let [left, right] = [i + 1, nums.length - 1];
        while (left < right) {
            // let key = `${nums[i]},${nums[left]},${nums[right]}`;
            let keyValue = [nums[i], nums[left], nums[right]];
            let count = nums[i] + nums[left] + nums[right];
            if (count < 0) {
                left++;
            } else if (count > 0) {
                right--;
            } else {
                // if (!countZeroDict[key]) {
                //     countZeroDict[key] = keyValue;
                // }
                countZeroDict.push(keyValue)
                while (left < right && nums[left] == nums[left+1]) left++; // 去重
                while (left < right && nums[right] == nums[right-1]) right--; // 去重
                left++;
                right--;
            }
        }
    }
    return countZeroDict;
    // return Object.values(countZeroDict);
};

image.png

三、最后

原题地址:15. 三数之和

未完待续😄~