LeetCode算法题:15. 三数之和(Java)

题目描述

给你一个整数数组 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 。

提示:

  • 3 <= nums.length <= 3000
  • -10^5 <= nums[i] <= 10^5

解题思路一:

将原始数组进行从小到大进行排序,然后定义三个指针a,b,c,初始时分别指向数组的第一个元素、第二个元素、第三个元素,并且b所指位置永远在a之后,c所指元素永远在b之后,表示正在尝试的三元组,然后定义三层循环,分别表示遍历移动这三个元素,如果三个值相加为0,则添加进结果列表。如果向后移动的元素与前一个元素值相同,则直接跳过,因为已经试过了,减少遍历次数的同时也避免了重复三元组的出现。直到a遍历到了数组的倒数第二个位置,结束。

实现的代码

class Solution {public List<List<Integer>> threeSum(int[] nums) {Arrays.sort(nums);List<List<Integer>> result = new ArrayList<>();int i,j,k,len=nums.length,a,b,c;for(i=0;i<len-2;i++){if(i==0||nums[i]!=nums[i-1]){// 当前遍历的值前面没有遍历过,则进入第二层循环a = nums[i];for(j=i+1;j<len-1;j++){if(j==i+1||nums[j]!=nums[j-1]){// 当前遍历的值前面没有遍历过,则进入第三层循环b = nums[j];for(k=j+1;k<len;k++){if(k==j+1||nums[k]!=nums[k-1]){// 当前遍历的值前面没有遍历过,则进行计算是否符合条件c = nums[k];if(a+b+c==0){//符合三元组条件List<Integer> l = new ArrayList<>();l.add(a);l.add(b);l.add(c);result.add(l);}}}}}}}return result;}
}

结果:过了308个测例,但还是超出时间限制,时间复杂度过高,分析代码逻辑可知,时间复杂度为O(n^3)
在这里插入图片描述

解题思路二:

由前面的思路以及之前做的题可知,HashMap的检索时间复杂度为O(1),所以当确定了前两个元素值之后,第三个元素值只能等于0-(a+b),因此可以利用HashMap直接检索是否存在0-(a+b),时间复杂度将为O(n^2)。所以先遍历一次数组,构建HashMap,其中的键是数组元素值,值为该数组元素在数组中的次数。每次遍历某个元素后将map中对应的值-1,表示已经使用了一个该元素。

代码:

class Solution {public List<List<Integer>> threeSum(int[] nums) {Arrays.sort(nums);List<List<Integer>> result = new ArrayList<>();Map<Integer,Integer> mapValues = new HashMap<>();Map<Integer,Integer> mapIndex = new HashMap<>();// 用于存储每个元素第一次出现在数组中的位置,int i,j,k,len=nums.length,a,b,c;for(i=0;i<len;i++){if(i==0||nums[i]!=nums[i-1]){// 该元素之前没出现过,则将其新加入map,mapValues.put(nums[i],1);}else{// 该元素已经出现过,将对应键值对的值+1mapValues.put(nums[i],mapValues.get(nums[i])+1);}mapIndex.put(nums[i],i);//更新位置map添加位置信息}for(i=0;i<len-2;i++){if(i==0||nums[i]!=nums[i-1]){// 当前遍历的值前面没有遍历过,则进入第二层循环a = nums[i];mapValues.put(a,mapValues.get(a)-1); //表示该元素已经使用一个for(j=i+1;j<len-1;j++){if(j==i+1||nums[j]!=nums[j-1]){// 当前遍历的值前面没有遍历过,则进行三元组计算b = nums[j];mapValues.put(b,mapValues.get(b)-1); //表示该元素已经使用一个c = 0-a-b;if(mapValues.containsKey(c) && mapIndex.get(c)>j && mapValues.get(c)>0){// 还存在三元组所需要的c,且c的位置是在b之后List<Integer> l = new ArrayList<>();l.add(a);l.add(b);l.add(c);result.add(l);}mapValues.put(b,mapValues.get(b)+1); //表示该元素已经使用一个}}mapValues.put(a,mapValues.get(a)+1); //恢复成原个数}}return result;}
}

结果:
在这里插入图片描述
不过时间消耗和空间消耗都非常大,还有很大改进空间。

解题思路3:

通过分析内层循环可知,当固定了a之后,那么b和c只能从a之后的位置去找,同时如果一开始固定b为a的后一个元素,c是最后一个元素,那么当a+b+c<0时,说明b+c的值不够,又因为c已经是最大的值了,只可能移动b来增大b+c的值。同理,当a+b+c>0时,说明b+c的值超过了,又因为b已经是最小的值了,只可能移动c来减小b+c的值。因此内层的b和c循环实际上是并列的关系,可以通过一次遍历来判断。

改进之后代码:

class Solution {public List<List<Integer>> threeSum(int[] nums) {Arrays.sort(nums);List<List<Integer>> result = new ArrayList<>();int i,j,k;for(i=0;i<nums.length-2;i++){if(i>0&&nums[i]==nums[i-1]){continue;}j = i+1;// 初始化j为i的后一位k = nums.length-1;// 初始化k为数组最后一个数while(j<k){// 当j处于k的左边则进一步判断int sum = nums[i]+nums[j]+nums[k];if(sum>0){k--;}else if(sum<0){j++;}else{// 满足三元组要求List<Integer> l = new ArrayList<>();l.add(nums[i]);l.add(nums[j]);l.add(nums[k]);result.add(l);// j继续向右移动,k继续向左移,寻找是否j++;k--;while(j<k&&nums[j]==nums[j-1])j++ ;// 向后移动的b与当前三元组的b值一样,不需要重复计算while(j<k&&nums[k]==nums[k+1])k--; // 向前移动的c与当前三元组的c值一样,不需要重复计算}}}return result;}
}

结果:
在这里插入图片描述
总结:
需要通过两个数去寻找他们和的固定值,可以通过排序+双指针问题去解决。不断通过判断离固定值的差距去调整双指针的位置。

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

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

相关文章

文档分类DPCNN简介(pytorch实现)

文档分类DPCNN简介 DPCNN简介 模型结构区域嵌入等长卷积1/2池化DPCNN模型代码实现 DPCNN简介 论文中提出了一种基于 word-level 级别的网络-DPCNN&#xff0c;由于 TextCNN 不能通过卷积获得文本的长距离依赖关系&#xff0c;而论文中 DPCNN 通过不断加深网络&#xff0c;可以…

RTMP低延迟推流

人总是需要压力才能进步, 最近有个项目, 需要我在RK3568上, 推流到公网, 最大程度的降低延迟. 废话不多说, 先直接看效果: 数据经过WiFi发送到Inenter的SRS服务器, 再通过网页拉流的. 因为是打金任务, 所以逼了自己一把, 把RTMP推流好好捋一遍. 先说说任务目标, 首先是MPP编码…

按照官网引擎问题重新设置监控目录,仍然存在空三等待的问题怎么办?

答&#xff1a;任务目录和引擎目录设置一样&#xff0c;然后取消任务重新写入. 重建大师是一款专为超大规模实景三维数据生产而设计的集群并行处理软件&#xff0c;输入倾斜照片&#xff0c;激光点云&#xff0c;POS信息及像控点&#xff0c;输出高精度彩色网格模型&#xff0…

Iphone更换后摄像头蓝光珠

拆蓝光珠 风枪加热240℃&#xff0c;风速70&#xff0c;直接融化掉蓝光珠 清除残胶 风枪加热140℃&#xff0c;风速50 更换新的蓝光珠 点UV胶紫外灯加固&#xff0c;防止晃动 安装完毕&#xff01;

RT-Thread的 FAL 组件_使用笔记

RT-Thread的FAL分区表组件 1、FAL介绍 FAL (Flash Abstraction Layer) Flash 抽象层&#xff0c;是对 Flash 及基于 Flash 的分区进行管理、操作的抽象层&#xff0c;对上层统一了 Flash 及 分区操作的 API (框架图如下所示)&#xff0c;并具有以下特性&#xff1a; 1.1 FAL目…

【EI稳定检索|主题广泛】2024年航空航天、遥感与计算机国际会议(ARSC 2024)

2024年航空航天、遥感与计算机国际会议&#xff08;ARSC 2024&#xff09; 2024 International Conference on Aerospace, Remote Sensing, and Computing 【会议简介】 2024年航空航天、遥感与计算机国际会议将在古都西安召开。本次会议是航空航天、遥感与计算机领域的一次…

[牛客网]——C语言刷题day3

答案&#xff1a;A 解析&#xff1a; A.表示将数组a的首地址赋值给指针变量p B.将一个int型变量直接赋值给一个int型的指针是不行的 C.道理同B D.j2是一个右值&#xff0c;右值是不能进行取地址操作的 #include <iostream> using namespace std;#define N 7 int fun…

Ubuntu16 扩展磁盘空间

一、扩展容量 关闭虚拟机->硬盘->扩展->输入要扩展的空间大小 二、重新磁盘分区 打开虚拟机&#xff0c;在终端安装gparted&#xff1a; sudo apt-get install gparted 打开gparted&#xff1a; sudo gparted 磁盘分区如下图所示 选择/dev/sda5分区&#xff0c;选择…

web3 ETF软件开发难点

开发一个涉及到 Web3 ETF&#xff08;Exchange-Traded Fund&#xff0c;交易所交易基金&#xff09;的软件可能会面临一些挑战和难点&#xff0c;特别是在整合 Web3 技术和金融服务方面。以下是一些可能的难点。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&am…

微信在线预约系统怎么做_让您的业务更高效!

在这个数字化飞速发展的时代&#xff0c;传统的业务预约方式已经逐渐无法满足现代人的需求。随着智能手机的普及和微信用户数量的不断攀升&#xff0c;微信在线预约系统已成为许多企业和个人提升服务效率、优化客户体验的不二之选。今天&#xff0c;就让我们一起探讨微信在线预…

【Linux玩物志】Linux环境开发基本工具使用(1)——vim

W...Y的主页 &#x1f60a; 代码仓库分享&#x1f495; Linux开发工具 首先我们要知道vim是什么&#xff1f; vi&#xff08;Visual Editor&#xff09;是由美国程序员比尔乌尔曼&#xff08;Bill Joy&#xff09;于1976年开发的&#xff0c;最初是为了在Unix系统上进行文本编…

npm install [Error]

npm install 依赖的时候报错 依赖版本问题的冲突&#xff0c;忽视即可 使用 npm install --legacy-peer-deps