当前位置: 首页 > news >正文

力扣第十五题——三数之和

内容介绍

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != 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 。

提示:

  • 3 <= nums.length <= 3000
  • -105 <= nums[i] <= 105

完整代码

class Solution {public List<List<Integer>> threeSum(int[] nums) {int n = nums.length;Arrays.sort(nums);List<List<Integer>> ans = new ArrayList<List<Integer>>();for (int first = 0; first < n; ++first) {if (first > 0 && nums[first] == nums[first - 1]) {continue;}int third = n - 1;int target = -nums[first];for (int second = first + 1; second < n; ++second) {if (second > first + 1 && nums[second] == nums[second - 1]) {continue;}while (second < third && nums[second] + nums[third] > target) {--third;}if (second == third) {break;}if (nums[second] + nums[third] == target) {List<Integer> list = new ArrayList<Integer>();list.add(nums[first]);list.add(nums[second]);list.add(nums[third]);ans.add(list);}}}return ans;}
}

思路详解

整体思路

  1. 排序:首先对数组进行排序,这样可以在后续的遍历中避免重复解,并且方便使用双指针技巧。

  2. 枚举:通过固定一个元素,然后使用双指针在剩余部分寻找另外两个元素,使得这三个元素的和为零。

  3. 去重:在枚举过程中,需要跳过相同的元素,以避免出现重复解。

详细步骤

  1. 初始化

    • n:数组长度。
    • ans:用于存储最终结果的列表。
  2. 枚举第一个元素(a)

    • 使用一个循环从数组的第一个元素枚举到倒数第三个元素(因为需要留出空间给另外两个元素)。
    • 在每次循环开始时,检查当前元素是否与前一个元素相同,如果相同则跳过,以避免重复解。
  3. 双指针寻找另外两个元素(b 和 c)

    • 初始化指针third指向数组的最后一个元素。
    • 计算目标值target,即-nums[first]
    • 使用一个内层循环枚举第二个元素(b),从first + 1开始到n - 1
    • 在内层循环中,同样检查当前元素是否与前一个元素相同,如果相同则跳过。
  4. 调整双指针

    • nums[second] + nums[third] > target时,说明当前和过大,需要将third指针左移,以减小和的值。
    • second == third时,说明已经没有满足条件的c了,可以退出内层循环。
  5. 检查并添加解

    • nums[second] + nums[third] == target时,说明找到了一组解,将其添加到结果列表ans中。
  6. 返回结果

    • 循环结束后,返回结果列表ans

代码优点

  • 时间复杂度:排序的时间复杂度为O(nlogn),双指针遍历的时间复杂度为O(n^2),总体时间复杂度为O(n^2),在可接受范围内。
  • 空间复杂度:只使用了常数级别的额外空间,空间复杂度为O(1)。
  • 去重逻辑:通过简单的条件判断,有效地避免了重复解的出现。

知识点精炼

  1. 排序:首先对数组进行排序,便于后续去重和双指针操作。
  2. 枚举:固定一个元素,使用双指针在剩余数组中寻找另外两个元素。
  3. 双指针:一前一后两个指针,根据和的大小调整指针位置,提高查找效率。
  4. 去重:在枚举过程中,跳过相同的元素,避免重复解。
  5. 时间复杂度:O(n^2),排序O(nlogn),双指针遍历O(n^2)。
  6. 空间复杂度:O(1),仅使用常数级别额外空间。

 

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 基于秒杀系统的企业开发设计思考
  • LFU算法实现笔记
  • 【postgresql】pg_dump备份数据库
  • 六爻排盘 api数据接口
  • mmc-utils 的 MMC 测试工具
  • nng协议nni_posix_resolv_sysinit()系统初始化
  • iOS ------ ARC的工作原理
  • Android获取当前屏幕显示的是哪个activity
  • 访问控制系列
  • 【RPC注册发现框架实战】一个简易的RPC注册发现框架
  • Vue.js:如何区分页面关闭和刷新?深入解析与实战
  • mysql命令练习
  • 测试开发面经总结(三)
  • Qt篇——QSqlQueryModel内容居中显示
  • Stable Diffusion:质量高画风清新细节丰富的二次元大模型二次元插图
  • [nginx文档翻译系列] 控制nginx
  • 【391天】每日项目总结系列128(2018.03.03)
  • 【Linux系统编程】快速查找errno错误码信息
  • 345-反转字符串中的元音字母
  • android 一些 utils
  • CSS3 变换
  • Docker 笔记(2):Dockerfile
  • FineReport中如何实现自动滚屏效果
  • JavaScript-Array类型
  • jquery cookie
  • JS数组方法汇总
  • Perseus-BERT——业内性能极致优化的BERT训练方案
  • python学习笔记 - ThreadLocal
  • React-Native - 收藏集 - 掘金
  • ReactNative开发常用的三方模块
  • redis学习笔记(三):列表、集合、有序集合
  • Zepto.js源码学习之二
  • 阿里云爬虫风险管理产品商业化,为云端流量保驾护航
  • 基于Volley网络库实现加载多种网络图片(包括GIF动态图片、圆形图片、普通图片)...
  • 前端路由实现-history
  • 微信开放平台全网发布【失败】的几点排查方法
  • 你对linux中grep命令知道多少?
  • 宾利慕尚创始人典藏版国内首秀,2025年前实现全系车型电动化 | 2019上海车展 ...
  • 国内开源镜像站点
  • ​猴子吃桃问题:每天都吃了前一天剩下的一半多一个。
  • #QT(TCP网络编程-服务端)
  • (13)Hive调优——动态分区导致的小文件问题
  • (20)目标检测算法之YOLOv5计算预选框、详解anchor计算
  • (7) cmake 编译C++程序(二)
  • (Redis使用系列) Springboot 使用Redis+Session实现Session共享 ,简单的单点登录 五
  • (二)测试工具
  • (简单有案例)前端实现主题切换、动态换肤的两种简单方式
  • (十) 初识 Docker file
  • (学习日记)2024.02.29:UCOSIII第二节
  • (学习日记)2024.03.12:UCOSIII第十四节:时基列表
  • (一)u-boot-nand.bin的下载
  • (转)ORM
  • .desktop 桌面快捷_Linux桌面环境那么多,这几款优秀的任你选
  • .NET 4 并行(多核)“.NET研究”编程系列之二 从Task开始
  • .NET 动态调用WebService + WSE + UsernameToken