LeetCode三数之和

题目描述:

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。

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

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:

nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0

不同的三元组是 [-1,0,1][-1,-1,2]
注意,输出的顺序和三元组的顺序并不重要。

示例 2:

输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。

示例 3:
输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。

代码

/**
 * 函数threeSum,接受一个数字数组nums作为参数,返回所有和为0的三元组数组。
 * 
 * @param {number[]} nums 数字数组
 * @return {number[][]} 所有和为0的三元组数组
 */
var threeSum = function (nums) {
    // 首先对数组进行排序,使用升序
    let arr = nums.sort((a, b) => a - b);
    // 初始化结果数组
    let result = [];
    // 临时变量,用于存储中间结果
    let tmp, left, right;

    // 循环遍历数组中的所有数
    for (let i = 0; i < arr.length; i++) {
        // 如果当前元素大于0,由于数组是升序排列的,后面的元素都会更大,不可能找到和为0的三元组
        if (arr[i] > 0) break;
        
        // 如果当前元素与前一个元素相同,跳过当前循环,避免找到重复的三元组
        while (arr[i] == arr[i - 1]) i++;
        
        // 计算当前元素的补数,即需要找到两个数,使得它们与当前元素相加等于0
        tmp = 0 - arr[i];
        // 初始化左指针,从当前元素的下一个位置开始
        left = i + 1;
        // 初始化右指针,从数组的最后一个元素开始
        right = arr.length - 1;
        
        // 使用左右指针寻找和为0的三元组
        while (left < right) {
            // 如果左右指针所指的元素之和等于补数,说明找到了一个三元组
            if (arr[left] + arr[right] == tmp) {
                let tmparr = [];
                // 将当前的三元组添加到临时数组中
                tmparr.push(arr[i], arr[left], arr[right]);
                // 将临时数组添加到结果数组中
                result.push(tmparr);
                
                // 跳过重复的left指针元素
                while (left < right && arr[left] == arr[left + 1]) left++;
                // 跳过重复的right指针元素
                while (left < right && arr[right] == arr[right - 1]) right--;
                
                // 移动指针,继续寻找下一个可能的三元组
                left++;
                right--;
            } 
            // 如果左右指针所指的元素之和大于补数,说明需要减小和,移动right指针向左
            else if (arr[left] + arr[right] > tmp) {
                right--;
            }
            // 如果左右指针所指的元素之和小于补数,说明需要增大和,移动left指针向右
            else if (arr[left] + arr[right] < tmp) {
                left++;
            }
        }
    }
    // 返回结果数组
    return result;
};

代码主要逻辑

  1. 排序:首先对输入数组nums进行排序,这样可以通过比较当前元素与0的关系来确定是否需要继续搜索。

  2. 初始化:定义一个空数组result来存储找到的三元组。

  3. 遍历数组:使用一个for循环遍历数组,其中i是当前考虑的元素的索引。

  4. 终止条件:如果当前元素nums[i]大于0,由于数组已排序,后面的元素也会大于0,因此不可能找到和为0的三元组,直接返回结果。

  5. 跳过重复元素:如果当前元素与前一个元素相同,跳过当前循环,避免找到重复的三元组。

  6. 左右指针:使用两个指针leftright,分别指向当前元素的下一个位置和数组的最后一个元素。

  7. 寻找三元组:在while循环中,通过移动leftright指针来寻找和为0的三元组。

  8. 添加三元组:如果找到和为0的三元组,将其添加到结果数组中,并更新指针位置,同时跳过重复的元素。

  9. 移动指针:如果三数之和不等于0,根据三数之和与0的比较结果来决定是移动left指针还是right指针。

  10. 返回结果:最后返回包含所有和为0的三元组的数组。

这个算法的时间复杂度是O(n^2),其中n是数组的长度,因为对于每个元素,我们最多进行一次O(n)的双指针搜索。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值