重刷leetcode-day4-[15. 三数之和]

117 阅读1分钟

【题目】15. 三数之和

【题目考察】:双指针

【目标复杂度】: O(n^2)

【解法】:

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function(nums) {
    // 定义res存储结果数组
    const res = [];
    // 升序排序
    nums.sort((a, b) => a - b);
    if (
        // 空
        !nums ||
        // 数组长度小于3
        nums.length < 3 ||
        // 升序排序后第一个数字大于0
        nums[0] > 0
    ) {
        // 直接返回空数组
        return res;
    }
    // nums从第一个数字遍历,接着第二第三个从后面取
    for (let i = 0; i < nums.length; i++) {
        // nums是升序排序过的,如果第一个数字都为0,比如0, 0, 1, 肯定和大于0,直接不断continue结束就好了
        if (nums[i] > 0) {
            continue;
        }
        // 比如-1,-1,0,1,其实两个-1是重复的,跳过重复的去重
        if (nums[i] === nums[i - 1]) {
            continue;
        }
        // 定义左边指针
        let left = i + 1;
        // 定义右指针
        let right = nums.length - 1;
        // 进行while循环判断left和right 条件是left 小于 right 由两边向中间夹,left肯定是比right小的,相等或者大了的就结束
        while (left < right) {
            // 取三个数之和
            const sum = nums[i] + nums[left] + nums[right];
            if (sum === 0) {
                // 如果等于0,那么就把对应的数字放到结果数组中
                res.push([nums[i], nums[left], nums[right]]);
                // 接着对左边去重
                while(nums[left] === nums[left + 1]) {
                    left++;
                }
                // 对右边去重
                while(nums[right] === nums[right - 1]) {
                    right--;
                }
                // 去重后其实上面哪个数字还是之前那个一样的,所以需要左边右边都移动一位
                left++;
                right--;
            } else if (sum > 0) {
                // 如果和大于0,因为是升序排序的,那么表示右边太大了,需要往左移动一点,和就会小一点
                right--;
            } else if (sum < 0) {
                // 如果和小于0,因为是升序排序的,那么表示左边太小了,需要往右移动一点,和就会大一点
                left++;
            }
        }
    }
    // 返回结果
    return res;
};