力扣15题 三数之和 双指针算法

15. 三数之和

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

算法思路

这个题和两数之和十分相似, 不同的是, 题目要找的是"不重复"的三元组(元素不同), 那么我们可以在两数之和的双指针思想上进行解题:

  1. 先排序
  2. 先固定一个数, 加入这个数从左到右枚举到了i位置
  3. 然后定义两个指针, 指向i位置右边区间的两端, left = i + 1, right = nums.length - 1, 在[left, right]区间内找到两数之和为-nums[i]的二元组.
    • 这里要注意的是, 当我们固定的数是正数a时, 我们需要在右侧区间寻找两数之和为-a的二元组, 但是右侧区间的数都大于等于a, 都是正数, 所以根本不可能找到两数之和为负数的二元组, 所以当枚举到正数时, 就可以直接break.
  4. 找到了就和nums[i]组成符合题目要求的三元组

但是要注意的是, 这道题有去重操作

假设nums是这样一个数组[-4, -4, -1, 0, 0, 0, 1, 1, 4, 4, 5, 6]

如果现在到了这种情况:[-4, 0, 4]已经计入了返回的结果集里面.

在这里插入图片描述

left++, right--后, 虽然形成的三元组依然符合题意, 但是这和上一个结果就重复了, 而题目要求不能重复. 所以, 指针移动的操作中, 要"跳过重复"的元素.

跳过符合两数之和为-num[i]的重复元素. 而那些不符合却重复的数不用管, 因为它本身也进入不到结果集.

不仅如此, 我们再看, 假如第一个-4右边的区间已经遍历完成, i++, 但是新的固定值和前一个固定值相同, 如果我们不做处理, 依然在它右边找两数之和是4的元素, 也会产生重复. 所以这里也要"跳过重复"的元素

因此

  • 找到⼀个结果之后, left right 指针要「跳过重复」的元素;
  • 当使⽤完⼀次双指针算法之后,固定的 a 也要「跳过重复」的元素。

Java代码

class Solution {public List<List<Integer>> threeSum(int[] nums) {Arrays.sort(nums);List<List<Integer>> lists = new LinkedList<>();int i = 0;//为什么是i < nums.length - 2, 因为我们要找的是三元组//最后判断的一个三元组是nums[nums.length -3], nums[nums.length - 2], nums[nums.length - 1]while(i < nums.length - 2) {//如果固定的数字是正数, 那么右侧绝对不会出现两数之和为负数的二元组, 所以可以直接终止循环if(nums[i] > 0) {break;}int left = i + 1;int right = nums.length - 1;while(left < right) {int sum = nums[left] + nums[right];if(sum > -nums[i]) {right--;} else if(sum < -nums[i]) {left++;} else {lists.add(new LinkedList<Integer>(Arrays.asList(nums[i], nums[left], nums[right])));right--;left++;//跳过重复元素, 注意left < rightwhile(left < right && nums[left] == nums[left - 1]) {left++;}while(left < right && nums[right] == nums[right + 1]) {right--;}}}i++;//跳过重复的数字while (i < nums.length && nums[i] == nums[i - 1]) {i++;}}return lists;}
}

时间复杂度: O(N2) 空间复杂度:O(log2N)

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

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

相关文章

Flask 构建高效的 Python Web 应用详解

概要 Flask 是一个用 Python 编写的轻量级 Web 应用框架。它的设计哲学是“简单优雅”&#xff0c;但它的灵活性和可扩展性使其成为构建复杂应用的理想选择。本文旨在深入探讨 Flask 的架构和核心组件&#xff0c;通过详细的示例和实践指南&#xff0c;为开发者提供构建高效、…

rust持续学习 COW

COW我第一次看见还以为是奶牛 很奇怪是个啥 后来了解到是clone on write 缩写的&#xff0c;大乌龙啊 这个有两种enum,一种是borrow&#xff0c;一种是own rust中&#xff0c;数据读写经常涉及到所有权 这个borrow&#xff0c;很显然&#xff0c;就是不可变借用了 own就是可以写…

【渗透】记录阿里云CentOS被渗透攻击

文章目录 发现排查安装Nethogs查询情况 最终方案 发现 流量异常&#xff0c;出现大流量&#xff0c;网络贷带宽占满情况 排查 安装Nethogs 1.1 Nethogs介绍 NetHogs是一个开源的命令行工具&#xff08;类似于Linux的top命令&#xff09;&#xff0c;用来按进程或程序实时统…

MySQL 基础、进阶、运维的学习笔记

1. MySQL 基础篇 1.1 MySQL 概述 1.1.1 数据库相关概念 数据库(Database, 简称 DB): 存储数据的仓库&#xff0c;数据是有组织的进行存储。 数据库管理系统(Database Management System, 简称 DBMS): 操作和管理数据库的大型软件。 SQL(Structured Query Language, 简称 S…

linux 内核工作队列技术原理

首先介绍一下工作队列使用的术语。 work&#xff1a;工作&#xff0c;也称为工作项。work queue&#xff1a;工作队列&#xff0c;就是工作的集合&#xff0c; work queue 和 work 是一对多的关系。worker&#xff1a; 工人&#xff0c; 一个工人对应一个内核线程&#xff0c;…

在re:Invent上IBM宣布与亚马逊云科技携手,Amazon RDS for DB2正式亮相

11月29日&#xff0c;IBM在亚马逊云科技re:Invent 2023上宣布&#xff0c;与亚马逊云科技合作推出Amazon Relational Database Service&#xff08;Amazon RDS&#xff09;for Db2。这项全新的完全托管云服务旨在简化客户在混合云环境中管理人工智能&#xff08;AI&#xff09;…

AH8691是一款80V转3.3V降压芯片

80V转3.3V降压芯片AH8691&#xff1a;宽电压输入范围&#xff0c;高效稳定&#xff0c;多领域应用 在当今电源管理领域&#xff0c;高效、稳定的降压芯片已成为各类设备的关键需求。本文将为您介绍一款80V转3.3V降压芯片AH8691&#xff0c;其具备宽电压输入范围、迟滞控制、高…

wpf devexpress 使用IDataErrorInfo实现input验证

此处下载源码 当form初始化显示&#xff0c;Register按钮应该启动和没有输入错误应该显示。如果用户点击注册按钮在特定的输入无效数据&#xff0c;form将显示输入错误和禁用的注册按钮。实现逻辑在标准的IDataErrorInfo接口。请查阅IDataErrorInfo接口&#xff08;System.Com…

如何在C/C++中测量一个函数或者功能的运行时间(串行和并行,以及三种方法的实际情况对比)

本文算是一个比较完整的关于在 C/C 中测量一个函数或者功能的总结&#xff0c;最后会演示三种方法的对比。 最常用的clock() 最常用的测量方法是使用clock()来记录两个 CPU 时间点clock_t&#xff0c;然后做差。这个方法的好处在于非常简单易写&#xff0c;如下&#xff08;第…

基于相关性的四种机器学习聚类方法

在这篇文章中&#xff0c;基于20家公司的股票价格时间序列数据。根据股票价格之间的相关性&#xff0c;看一下对这些公司进行分类的四种不同方式。 苹果&#xff08;AAPL&#xff09;&#xff0c;亚马逊&#xff08;AMZN&#xff09;&#xff0c;Facebook&#xff08;META&…

【技术分享】RK356X Android11 以太网共享4G网络

本文基于IDO-SBC3566-V1B Android11系统实现开机后以太网自动共享4G网络功能。 IDO-SBC3566基于瑞芯微RK3566研发的一款高性能低功耗的智能主板&#xff0c;采用四核A55,主频高达1.8GHz&#xff0c;专为个人移动互联网设备和AIOT设备而设计&#xff0c;内置了多种功能强大的嵌…

TZOJ 1379 C语言合法标识符

答案&#xff1a; #include <stdio.h> #include <string.h> int main() {char arr[60];int n 0, i 0, num 0, flag;scanf("%d", &n);getchar(); //读取回车键while (n--) //循环N次{gets(arr);num strlen(arr); //num为字符串长度flag 1; …