云计算百科
云计算领域专业知识百科平台

LeetCode 15. 三数之和:排序 + 双指针解法详解

一、 题目描述(题目链接)

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

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

二、 算法思路:排序 + 双指针

本题的核心难点在于降低时间复杂度以及结果去重。暴力三重循环的时间复杂度为 O(N^3),在数据量较大时会超时。采用排序 + 双指针的策略,可以将时间复杂度优化至 O(N^2)。

核心步骤

  • 数组排序: 首先对数组进行升序排序。排序有两个关键作用:

    • 便于后续使用双指针进行线性扫描。

    • 便于跳过重复元素,实现结果去重。

  • 固定第一个数(外层循环): 遍历排序后的数组,设当前索引为 i,将 nums[i] 作为三元组的第一个数。

    • 剪枝优化:若 nums[i] > 0,由于数组已升序,后续数字必然大于 0,三数之和不可能为 0,直接终止循环。

    • 去重:若 i > 0 且 nums[i] == nums[i-1],说明该数值已作为第一个数处理过,跳过当前循环,避免重复解。

  • 双指针寻找另外两个数(内层循环): 在 i 之后的区间 [i+1, n-1] 中,设置左指针 left = i + 1,右指针 right = n – 1。

    • 计算 sum = nums[i] + nums[left] + nums[right]。

    • 若 sum == 0:找到一组解,记录结果。随后必须进行去重:左指针跳过所有重复值,右指针跳过所有重复值,最后 left++、right– 继续寻找。

    • 若 sum < 0:说明和偏小,需要增大,左指针右移(left++)。

    • 若 sum > 0:说明和偏大,需要减小,右指针左移(right–)。

  • 三、 代码实现 (C++)

    class Solution {
    public:
    vector<vector<int>> threeSum(vector<int>& nums) {
    vector<vector<int>> result;
    int n = nums.size();

    // 特判:元素少于3个直接返回
    if (n < 3) return result;

    // 1. 排序
    sort(nums.begin(), nums.end());

    // 2. 遍历第一个数
    for (int i = 0; i < n – 2; ++i) {
    // 剪枝:第一个数大于0,后续不可能凑成和为0
    if (nums[i] > 0) break;

    // 去重:跳过重复的第一个数
    if (i > 0 && nums[i] == nums[i-1]) continue;

    // 3. 双指针寻找另外两个数
    int left = i + 1;
    int right = n – 1;

    while (left < right) {
    int sum = nums[i] + nums[left] + nums[right];

    if (sum == 0) {
    result.push_back({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–;
    }
    else if (sum < 0) {
    left++; // 和太小,左指针右移
    }
    else {
    right–; // 和太大,右指针左移
    }
    }
    }

    return result;
    }
    };

    四、 复杂度分析

    时间复杂度:O(N2)

    数组排序的时间复杂度为 O(Nlog⁡N)。

    外层循环遍历数组 O(N),内层双指针遍历 O(N),嵌套后为 O(N^2)。

    综合来看,主导项为 O(N^2)。

    空间复杂度:O(log⁡N)

    主要取决于排序算法的空间消耗。C++ 的 std::sort 通常采用内省排序(Introsort),空间复杂度为 O(log⁡N)。除返回值外,未使用额外的线性空间。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » LeetCode 15. 三数之和:排序 + 双指针解法详解
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!