题目:15. 三数之和

问题描述

给你一个整数数组 nums,判断是否存在三元组 [nums[i], nums[j], nums[k]],满足:

  • i != j != k

  • nums[i] + nums[j] + nums[k] == 0

返回 所有和为 0 且不重复的三元组

示例 1:

复制代码
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]

示例 2:

复制代码
输入:nums = [0,1,1]
输出:[]

示例 3:

复制代码
输入:nums = [0,0,0]
输出:[[0,0,0]]

提示:

  • 3 <= nums.length <= 3000

  • -10^5 <= numsi <= 10^5


解题思路

  1. 排序 + 双指针

    • 先对数组进行升序排序,这样方便去重,同时可以用双指针快速找到两数之和。
  2. 固定第一个数

    • 遍历数组,固定 nums[i],剩下部分用双指针寻找两个数,使三数之和为 0。
  3. 双指针

    • 左指针 left = i + 1,右指针 right = n - 1

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

      • sum == 0 → 找到答案,记录并去重

      • sum < 0 → 左指针右移

      • sum > 0 → 右指针左移

  4. 去重技巧

    • 遍历 i 时跳过重复元素

    • 左右指针移动时跳过重复元素

  5. 动态扩容结果数组

    • 因为满足条件的三元组数量不确定,需要动态扩容结果数组,防止越界。

C语言代码实现

复制代码
#include <stdlib.h>
#include <stdio.h>

// 数组排序函数
int cmp(const void* a, const void* b) {
    return (*(int*)a - *(int*)b);
}

int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
    *returnSize = 0;
    if (numsSize < 3) {
        *returnColumnSizes = NULL;
        return NULL;
    }

    qsort(nums, numsSize, sizeof(int), cmp);  // 排序

    int capacity = 16;  // 初始容量
    int** result = malloc(sizeof(int*) * capacity);
    *returnColumnSizes = malloc(sizeof(int) * capacity);

    for (int i = 0; i < numsSize - 2; i++) {
        if (i > 0 && nums[i] == nums[i - 1]) continue;  // 去重

        int left = i + 1;
        int right = numsSize - 1;

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

            if (sum == 0) {
                if (*returnSize == capacity) {  // 扩容
                    capacity *= 2;
                    result = realloc(result, sizeof(int*) * capacity);
                    *returnColumnSizes = realloc(*returnColumnSizes, sizeof(int) * capacity);
                }

                result[*returnSize] = malloc(sizeof(int) * 3);
                result[*returnSize][0] = nums[i];
                result[*returnSize][1] = nums[left];
                result[*returnSize][2] = nums[right];
                (*returnColumnSizes)[*returnSize] = 3;
                (*returnSize)++;

                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(n log n)
双指针遍历 O(n²)
总时间复杂度 O(n²)
空间复杂度 O(1)(不算返回结果数组)

核心总结

  1. 排序 → 便于去重和双指针搜索

  2. 双指针 → 高效寻找两数之和

  3. 去重 → 防止重复三元组

  4. 动态扩容 → 处理不确定的返回数组大小


相关推荐
wuyk5551 小时前
104.C 语言字节对齐:从底层原理到工程实践的完整指南
c语言·开发语言·stm32·单片机·嵌入式硬件
北域码匠8 小时前
高通滤波算法深度解析(High-Pass Filter)
stm32·算法·c#·数字信号处理·嵌入式开发·滤波算法·高通滤波
南棱笑笑生8 小时前
20260904实测给飞凌OK3576-C开发板刷入Rockchip原厂的IMG固件【使用飞凌的DTS】切换串口波特率为1.5Mbps
c语言·开发语言·rockchip
指掀涛澜天下惊8 小时前
强化学习进阶篇八 策略梯度算法
深度学习·学习·算法·强化学习
乌萨奇也要立志学C++8 小时前
【洛谷】kmp算法
开发语言·算法
禹凕8 小时前
Dijkstra算法详解与应用
python·算法
YaraMemo9 小时前
元启发式算法框架
人工智能·算法·5g·信息与通信·启发式算法·信号处理
weixin_3077791310 小时前
一维无粘 Burgers 方程的激波形成问题:MacCormack 格式求解
c++·算法·matlab
HugoStudio_SWAN10 小时前
洛谷 B4500 / B4449 / B3843 凯撒密码、密码强度与密码合规——加密与安全的三道门
c++·学习·程序人生·算法·安全
枫叶林FYL11 小时前
【群体智能集群控制工程实践】第3章 一致性协同算法
算法