【LeetCode 题解】算法:15.三数之和

一、问题描述

在 LeetCode 上有这样一道经典的算法题,题目要求给定一个整数数组 nums,找出所有不重复的三元组 [nums[i], nums[j], nums[k]],需要满足以下两个条件:

  1. 三个元素的索引互不相同,即 i != ji != kj != k

  2. 这三个元素的和为 0,也就是 nums[i] + nums[j] + nums[k] == 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[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。

二、思路分析

暴力法(不可取)

暴力法的思路是尝试数组中所有可能的三元组组合。对于一个长度为 n 的数组,需要三层嵌套循环来遍历所有组合,其时间复杂度为 O(n3)。当数组规模较大时,这种方法的效率极低,会导致程序运行时间过长,因此在实际应用中不可行。

哈希表法(有优化空间但较复杂)

此方法的思路是先遍历数组中的每个元素 nums[i],将问题转化为在剩余元素中寻找两数之和为 -nums[i] 的问题。可以使用哈希表来记录元素及其出现的位置,这样在查找互补元素时可以将时间复杂度从 O(n) 降低到 O(1)。整体时间复杂度为 O(n2)。不过,使用哈希表法需要处理重复元素的问题,实现起来相对复杂。

排序 + 双指针法(最优解)

这是解决该问题的最优方案,步骤如下:

  1. 排序数组:对数组进行排序,排序后相同的元素会相邻排列,这便于后续跳过重复元素,减少不必要的计算。

  2. 固定第一个数:依次选取数组中的每个元素作为三元组的第一个数。

  3. 双指针查找:在剩余的元素中使用双指针,一个指针从第一个数的下一个元素开始向右移动,另一个指针从数组的最后一个元素开始向左移动,通过移动指针来寻找满足和为 0 的另外两个数。

  4. 时间复杂度:排序的时间复杂度为 O(nlogn),双指针查找的时间复杂度为 O(n2),因此总的时间复杂度为 O(n2),该方法适合处理较大规模的数据。

三、详细解题代码

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;public class ThreeSum {public static List<List<Integer>> threeSum(int[] nums) {// 用于存储最终结果的列表List<List<Integer>> result = new ArrayList<>();// 首先检查数组长度,如果小于 3,直接返回空列表if (nums == null || nums.length < 3) {return result;}// 对数组进行排序,方便后续去重和双指针操作Arrays.sort(nums);int n = nums.length;// 遍历数组,固定第一个数for (int i = 0; i < n; i++) {// 如果当前数大于 0,由于数组已排序,后面的数都大于 0,不可能找到和为 0 的三元组,直接跳出循环if (nums[i] > 0) {break;}// 跳过重复的第一个数if (i > 0 && nums[i] == nums[i - 1]) {continue;}// 初始化双指针,j 指向 i 的下一个元素,k 指向数组末尾int j = i + 1;int k = n - 1;// 双指针查找满足条件的另外两个数while (j < k) {int total = nums[i] + nums[j] + nums[k];if (total == 0) {// 找到满足条件的三元组,添加到结果列表中result.add(Arrays.asList(nums[i], nums[j], nums[k]));// 跳过重复的第二个数while (j < k && nums[j] == nums[j + 1]) {j++;}// 跳过重复的第三个数while (j < k && nums[k] == nums[k - 1]) {k--;}// 移动指针继续寻找j++;k--;} else if (total < 0) {// 总和小于 0,说明需要增大和,将左指针右移j++;} else {// 总和大于 0,说明需要减小和,将右指针左移k--;}}}return result;}public static void main(String[] args) {int[] nums = {-1, 0, 1, 2, -1, -4};List<List<Integer>> result = threeSum(nums);for (List<Integer> triplet : result) {System.out.println(triplet);}}
}

代码解释

1、输入检查:首先检查数组是否为空或者长度是否小于 3,如果是则直接返回空列表。

2、数组排序:使用 Arrays.sort(nums) 对数组进行排序,为后续的双指针操作和去重做准备。

3、遍历第一个数:使用 for 循环遍历数组,固定第一个数 nums[i]。如果 nums[i] 大于 0,由于数组已排序,后面的数都大于 0,不可能找到和为 0 的三元组,直接跳出循环。同时,跳过重复的第一个数。

4、双指针查找:初始化双指针 j 和 k,分别指向 i 的下一个元素和数组末尾。计算三个数的和 total,根据 total 的值进行不同的操作:

  • 如果 total 等于 0,说明找到了一个满足条件的三元组,将其添加到结果列表中,并跳过重复的第二个数和第三个数,然后移动指针继续寻找。

  • 如果 total 小于 0,说明需要增大和,将左指针 j 右移。

  • 如果 total 大于 0,说明需要减小和,将右指针 k 左移。

5、返回结果:遍历结束后,返回存储结果的列表。 

四、复杂度分析

  • 时间复杂度:排序操作的时间复杂度为 O(nlogn),双指针查找的时间复杂度为 O(n2),因此总的时间复杂度为 O(n2)。

  • 空间复杂度:排序所需的栈空间为 O(logn),因此空间复杂度为 O(logn)。

五、常见问题解答

1. 为什么排序后可以去重?

排序后相同的元素会相邻排列,通过比较相邻元素是否相等,可以很方便地判断是否为重复元素。例如,在遍历第一个数时,如果当前数和前一个数相同,就跳过当前数,避免重复计算。

2. 如何处理全零数组?

当数组为 [0, 0, 0] 时,排序后第一个数为 0,双指针 j = 1 和 k = 2,计算 nums[i] + nums[j] + nums[k] 的和为 0,满足条件,将 [0, 0, 0] 添加到结果集中。

3. 能否用哈希表优化?

可以使用哈希表来优化,但需要处理大量的边界条件,例如重复元素的处理、元素自身为零的情况等。使用哈希表实现的代码复杂度较高,不如排序 + 双指针法简洁高效。

六、总结

  • 核心思想:先对数组进行排序,然后通过双指针法在剩余元素中寻找满足条件的三元组,同时利用排序后相邻元素相同的特性进行去重。

  • 关键点:正确处理指针的移动和重复元素的跳过逻辑,确保结果集中不包含重复的三元组。

  • 适用场景:该算法适用于需要高效处理大规模数据,并且要求结果唯一的场景。

感谢各位的阅读,后续将持续给大家讲解力扣中的算法题,如果觉得这篇内容对你有帮助,别忘了点赞和关注,后续还有更多精彩的算法解析与你分享!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/39991.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

多路转接Poll

在之前我们讲过select是最古老的多路转接方案&#xff0c;古老就意味着他不是很方便使用&#xff0c;他需要用户手动保存fd_set这个位图结构&#xff0c;来表示读写事件的关注与否或者就绪性。 而且由于fd_set的大小是固定的&#xff0c;这就意味着他能管理的套接字文件描述符是…

C语言贪吃蛇实现

When the night gets dark,remember that the Sun is also a star. 当夜幕降临时&#xff0c;请记住太阳也是一颗星星。 ————《去月球海滩篇》 目录 文章目录 一、《贪吃蛇》游戏介绍 二、WIN32部分接口简单介绍 2.1 控制台窗口大小设置 2.2 命令行窗口的名称的变更 2…

基于深度学习的图片识别系统(下)

文章目录 前言1.任务描述2.模型搭建3.代码解释3.1模型加载3.2加载数据3.3模型权重的保存3.4学习率3.5过拟合3.6训练模型3.7调试检查 4.结果分析5. 完整代码结语 前言 书接上回&#xff0c;我们已经完成数据预处理部分的内容&#xff0c;后续仍需要对表格进行裁剪&#xff0c;此…

再学:区块链基础与合约初探 EVM与GAS机制

目录 1.区块链是什么 2.remix ​3.账户​ ​4.以太坊三种交易​ 5.EVM 6.以太坊客户端节点 ​7.Gas费用 8.区块链浏览器 1.区块链是什么 只需要检验根节点 Merkel根是否有更改&#xff0c;就不用检查每个交易是否有更改。方便很多。 2.remix 3.账户 如果交易失败的话&…

Java 中装饰者模式与策略模式在埋点系统中的应用

前言 在软件开发中&#xff0c;装饰者模式和策略模式是两种常用的设计模式&#xff0c;它们在特定的业务场景下能够发挥巨大的作用。本文将通过一个实际的埋点系统案例&#xff0c;探讨如何在 Java 中运用装饰者模式和策略模式&#xff0c;以及如何结合工厂方法模式来优化代码…

HCIP_NOTE03_网络组成

网络组成 LAN MAN WAN 园区网 企业或机构内部的网络,分大中小型 行业园:企业园网 校园网 政务园 商业园 三层交换机 数据大量交换的局域网内部,转发效率高,有简单的路由功能 路由器 进出口网络,适用于复杂的网络环境,选路需求 无线网 信号传输稳定性差---- 电磁波易受干…

简记_单片机硬件最小系统设计

以STM32为例&#xff1a; 一、电源 1.1、数字电源 IO电源&#xff1a;VDD、VSS&#xff1a;1.8~3.6V&#xff0c;常用3.3V&#xff0c;去耦电容1 x 10u N x 100n &#xff1b; 内核电源&#xff1a;内嵌的稳压器输出&#xff1a;1.2V&#xff0c;给内核、存储器、数字外设…

32.[前端开发-JavaScript基础]Day09-元素操作-window滚动-事件处理-事件委托

JavasScript事件处理 1 认识事件处理 认识事件(Event) 常见的事件列表 认识事件流 2 事件冒泡捕获 事件冒泡和事件捕获 事件捕获和冒泡的过程 3 事件对象event 事件对象 event常见的属性和方法 事件处理中的this 4 EventTarget使用 EventTarget类 5 事件委托模式 事件委托&am…

LeetCode hot 100 每日一题(15)——48.旋转图像

这是一道难度为中等的题目&#xff0c;让我们来看看题目描述&#xff1a; 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 提示…

图灵300题-21~40-笔记002

图灵300题 图灵面试题视频&#xff1a;https://www.bilibili.com/video/BV17z421B7rB?spm_id_from333.788.videopod.episodes&vd_sourcebe7914db0accdc2315623a7ad0709b85&p20。 本文是学习笔记&#xff0c;如果需要面试没有时间阅读原博文&#xff0c;可以快速浏览笔…

09_从经典论文入手Seq2Seq架构

Sequence to Sequence 架构 Paper链接 Sequence to Sequence Learning with Neural Networks B站课程ShusenWang 核心思想 关键的改进点 In this paper, we show that a straightforward application of the Long Short-Term Memory (LSTM) architecture [16] can solve …

大疆上云api介绍

概述 目前对于 DJI 无人机接入第三方云平台,主要是基于 MSDK 开发定制 App,然后自己定义私有上云通信协议连接到云平台中。这样对于核心业务是开发云平台,无人机只是其中一个接入硬件设备的开发者来说,重新基于 MSDK 开发 App 工作量大、成本高,同时还需要花很多精力在无人…

3、孪生网络/连体网络(Siamese Network)

目的&#xff1a; 用Siamese Network (孪生网络) 解决Few-shot learning (小样本学习)。 Siamese Network并不是Meta Learning最好的方法&#xff0c; 但是通过学习Siamese Network&#xff0c;非常有助于理解其他Meta Learning算法。 这里介绍了两种方法&#xff1a;Siame…

OpenCV图像拼接(7)根据权重图对源图像进行归一化处理函数normalizeUsingWeightMap()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::detail::normalizeUsingWeightMap 是 OpenCV 中用于图像拼接细节处理的一个函数。它根据权重图对源图像进行归一化处理&#xff0c;通常用于…

卷积神经网络 - AlexNet各层详解

AlexNet的层次化设计&#xff0c;使得 AlexNet 能够逐层提取从简单边缘到复杂图形的特征&#xff0c;同时结合归一化、池化和 Dropout 技术&#xff0c;有效提升了训练速度和泛化能力&#xff0c;成为推动深度学习发展的重要里程碑。本文我们来理解AlexNet各层的参数设置以及对…

【设计模式】工厂模式

首先了解一下什么是工厂方法模式&#xff1f; 工厂方法模式&#xff08;Factory Method Pattern&#xff09;是一种创建型设计模式&#xff0c;它提供了一种方法来封装对象的创建逻辑。具体来说&#xff0c;它通过定义一个创建对象的接口&#xff08;即工厂方法&#xff09;&a…

centos 7 部署FTP 服务用shell 脚本搭建

#!/bin/bash# 检查是否以root身份运行脚本 if [ "$EUID" -ne 0 ]; thenecho "请以root身份运行此脚本。"exit 1 fi# 安装vsftpd yum install -y vsftpd# 启动vsftpd服务并设置开机自启 systemctl start vsftpd systemctl enable vsftpd# 配置防火墙以允许F…

基于Spring Boot的个性化商铺系统的设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

AI(DeepSeek、ChatGPT)、Python、ArcGIS Pro多技术融合下的空间数据分析、建模与科研绘图及论文写作

人工智能&#xff08;AI&#xff09;与ArcGIS Pro的结合&#xff0c;为空间数据处理和分析开辟了前所未有的创新路径。AI通过强大的数据挖掘、深度学习及自动化能力&#xff0c;可高效处理海量、多源、异构的空间数据&#xff0c;极大提升了分析效率与决策支持能力。而ArcGIS P…

2025最新3个wordpress好用的主题

红色大气的wordpress企业主题&#xff0c;适合服务行业的公司搭建企业官方网站使用。是一款专为中小企业和个人开发者设计的WordPress主题&#xff0c;旨在提供专业的网站构建解决方案。 通过此WordPress主题&#xff0c;用户可以轻松创建和维护一个专业的企业网站&#xff0c…