【LeetCode Hot 100】15. 三数之和

news/2024/9/22 11:42:20/文章来源:https://www.cnblogs.com/louistang0524/p/18425102

题目描述

回忆一下之前做过的两数之和,用的是哈希表存储已经遍历过的元素。但是本题要求返回值中不能有重复元素,因此需要去重,强行用哈希表的话,去重操作会很复杂。

我们可以通过哪些方法来保证返回的数组中不包含重复的三元组?

  1. 先将整个数组进行排序,可以保证答案数组中有\((a,b,c)\)(其中\(a \le b \le c\))且\((b,a,c)\)\((c,a,b)\)这样的三元组不会同时出现在答案数组中。
  2. 跳过相同的元素(排序之后这样的元素是相邻的),比如如果数组的排列是\(\dots, a, b, c, c. \dots\),将\((a,b,c)\)加入答案后下一个三元组仍然是\((a,b,c)\),仍然满足要求,如果我们跳过相同的元素,这样的重复情形就不会出现在答案中。

看到这个题,最简单粗暴的想法依旧是使用三重循环进行逐个遍历,但是这种方法的时间复杂度为\(O(N^3)\),很容易超时。那么我们就需要对其进行优化。要找到满足nums[i] + nums[j] + nums[k] = 0的所有三数组合,对于每个固定的元素nums[k]k可以作为最外层循环从头到尾进行遍历),相当于找到和确定为0 - nums[k]的两个数。要在循环内部找到这两个数,能否通过双重循环以外的方式呢?我们可以使用双指针,将两个指针分别设置在k+1位置和数组的最后一个位置,当三数之和sum == 0时,说明我们找到了一个正确的三元组,加入答案数组中;当sum < 0时,说明nums[i] + nums[j] < -nums[k],需要把这两数之和增大,由于数组已经排好序,我们就应该把左边的指针向右移动一格(当然此过程需要跳过重复元素);当sum > 0时,情况类似,需要把右边的指针向左移动。

这种方法的正确性是如何得来的呢?考虑这种情况,某一时刻的三元组\((k,i,j)\)表示此时正在检查的三个数的下标,\(k\)在外层循环,对于内层来说是固定的,如果三数之和\(S \gt 0\),我们把\(j\)减小直到\(j\prime\)停下来,说明\(n_k + n_i + n_{j\prime} \le 0\)而当\(j\prime \lt j \lt len\)时,都有\(S \gt 0\),如果我们再把\(i\)向右移动,那么\(n_i\)只会更大,加上\(j\prime \lt j \lt len\)\(n_j\),三数之和\(S\)也会更大,自然也大于\(0\),所以我们可以说\(j\prime \lt j \lt len\)这段区间的\(j\)已经被我们排除了,所以我们才可以放心地同时移动双指针。

// Java
class Solution {public List<List<Integer>> threeSum(int[] nums) {Arrays.sort(nums);List<List<Integer>> res = new ArrayList<>();for (int k = 0; k < nums.length - 2; k++) {if (nums[k] > 0) break;if (k > 0 && nums[k] == nums[k - 1]) continue;int i = k + 1, j = nums.length - 1;while (i < j) {int sum = nums[k] + nums[i] + nums[j];if (sum < 0) {while (i < j && nums[i] == nums[++i]) ;} else if (sum > 0) {while (i < j && nums[j] == nums[--j]) ;} else {res.add(new ArrayList<Integer>(Arrays.asList(nums[k], nums[i], nums[j])));while (i < j && nums[i] == nums[++i]) ;while (i < j && nums[j] == nums[--j]) ;}}}return res;}
}

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

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

相关文章

FFmpeg开发笔记(五十四)使用EasyPusher实现移动端的RTSP直播

​之前的文章《利用RTMP协议构建电脑与手机的直播Demo》介绍了如何使用RTMP Streamer实现完整的RTMP直播流程,另一篇文章《利用SRT协议构建手机APP的直播Demo》介绍了如何使用SRT Streamer实现完整的SRT直播流程,接下来介绍如何使用EasyPusher-Android实现完整的RTSP直播流程…

小飞机配置

小飞机配置把两个文件的文件复制到小飞机的安装路径中小飞机路径:打开文件所在的位置将MSI Afterburner中的文件复制找到RTSS安装路径RTSS设置中文小飞机监控设置选择自己需要显示内容进行OSD显示

Spring原理基础

Spring 高级 1 容器与Bean 1.1 接口容器 1.1.1 BeanFactory是什么 @SpringBootApplication public class ShowApplication {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(ShowApplication.class, args);/*** 1、…

springboot+vite 商品管理

SpringBoot + Vue3 +MySql5.7 +JDK8 一、 SpringBoot项目搭建 1 SpringBoot概述 1.1 SpringBoot 概念 SpringBoot提供了一种快速使用Spring的方式,基于约定优于配置的思想,可以让开发人员不必在配置与逻 辑业务之间进行思维的切换,全身心的投入到逻辑业务的代码编写中,从而…

SaaS业务架构:业务能力分析

大家好,我是汤师爷~ 今天聊聊SaaS业务架构的业务能力分析。 业务能力概述 简单来说,业务能力是企业“做某事的能力”。 业务能力描述了企业当前和未来应对挑战的能力,即企业能做什么或需要做什么。业务能力建模的关键在于定义了企业做什么,而不是如何做(由业务流程描述)。…

Redis常见使用场景

Redis常见使用场景

学习vue——ref和$refs

一、获取dom 二、获取子组件的方法

正方形计数 题解

题意简述 给出一个 \(n \times n\) 的格点平面,有 \(q\) 次询问,求有多少正方形以 \((x, y)\) 为某一顶点,满足这个正方形顶点均在格点上,且边长为有理数。 \(l \leq 10^5\),\(q \leq 5 \times 10^5\)。 题目分析 看到边长为有理数,想到「毕达哥拉斯三元组」("Pyth…

《AI系统:原理与架构》于华为HC大会2024正式发布

2024年9月21日,《AI系统:原理与架构》新书发布会在上海世博馆华为HC大会顺利举办。本书由华为昇腾技术专家、B站AI科普博主ZOMI酱和哈工大软件学院副院长苏统华教授联合编写,是领域内AI系统方面填补空白的重磅之作 发布会上,《AI系统:原理与架构》的作者、编辑代表分别介绍…

南沙C++信奥老师解一本通题:1372:小明的账单

​【题目描述】小明在一次聚会中,不慎遗失了自己的钱包,在接下来的日子,面对小明的将是一系列的补卡手续和堆积的账单… 在小明的百般恳求下,老板最终同意延缓账单的支付时间。可老板又提出,必须从目前还没有支付的所有账单中选出面额最大和最小的两张,并把他们付清。还没…