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

LeetCode Hot100刷题——三数之和

15. 三数之和

1. 题目描述

给你一个整数数组 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
  • -10^5 <= nums[i] <= 10^5

2. 思路分析

  1. 暴力法:三重循环,时间复杂度为O(n^3),会超时,且去重麻烦
  2. 双指针法:先排序,然后固定一个数,再用双指针在固定数之后的区间寻找两个数,使得三数之和为0

排序的好处:

  • 方便去重:相同的元素相邻,可以跳过重复元素避免重复解
  • 双指针可以高效地寻找两数之和

具体步骤:

  • 排序数组:首先对数组进行排序。排序后,相同的元素会相邻,这有助于后续跳过重复元素,避免重复的三元组。同时,排序使得我们可以使用双指针技巧高效地搜索三元组。
  • 固定一个元素,使用双指针搜索:遍历数组,对于每个元素nums[i],使用双指针在 i+1 到数组末尾的区间内搜索两个元素 nums[left] 和 nums[right],使得三数之和为0。
    • 双指针移动策略:
      • 如果三数之和等于0,记录三元组,并移动左右指针跳过重复元素。
      • 如果和小于0,左指针右移(增加和)
      • 如果和大于0,右指针左移(减少和)
    • 跳过重复元素:在移动指针时,跳过重复值,确保不会生成重复的三元组。
  • 跳过重复的固定元素:在遍历数组时,如果当前元素与前一个元素相同,则跳过,避免重复处理相同的三元组。

3. 解题过程

  1. 排序数组:使用Arrays.sort()对数组进行升序排序
  2. 初始化结果列表:用于存储所有满足条件的三元组
  3. 遍历数组:外层循环遍历每个元素nums[i]
  4. 跳过重复的nums[i]:如果当前元素与前一个元素相同,则跳过
  5. 双指针搜索:初始化左指针 left = i + 1 和右指针 right = nums.length - 1
    1. 计算三数之和 sum = nums[i] + nums[left] + nums[right]
    2. 根据sum的值移动指针:
      1. 如果sum == 0,记录三元组,移动左右指针并跳过重复元素。
      2. 如果sum < 0,左指针右移并跳过重复元素。
      3. 如果sum > 0,右指针左移并跳过重复元素。
  6. 返回结果:所有满足条件的三元组

程序代码

class Solution {public List<List<Integer>> threeSum(int[] nums) {// 排序数组Arrays.sort(nums);// 结果列表List<List<Integer>> result = new ArrayList<>();for (int i = 0; i < nums.length; i++) {// 跳过重复的固定元素if (i > 0 && nums[i] == nums[i - 1]) {continue;}// 初始化左右指针int left = i + 1;int right = nums.length - 1;while(left < right){int sum = nums[i] + nums[left] + nums[right];if(sum == 0){// 找到有效三元组result.add(Arrays.asList(nums[i], nums[left], nums[right]));left++;right--;// 跳过重复的左指针元素while(left < right && nums[left] == nums[left - 1]){left++;}// 跳过重复的右指针元素while(left < right && nums[right] == nums[right + 1]){right--;}} else if(sum < 0){// 左指针右移left++;// 跳过重复的左指针元素while(left < right && nums[left] == nums[left - 1]){left++;}} else if(sum > 0){// 右指针左移right--;// 跳过重复的右指针元素while(left < right && nums[right] == nums[right + 1]){right--;}}} }return result;}
}
  • 排序:通过排序,相同元素相邻,便于后续跳过重复元素。

  • 外层循环:遍历每个元素作为固定元素,跳过重复值以避免重复三元组。

  • 双指针:左指针从 i+1 开始,右指针从数组末尾开始,根据三数之和调整指针位置。

  • 跳过重复元素

    • 在找到有效三元组后,移动左右指针并跳过重复值。

    • 在移动左指针(和小于0时)或右指针(和大于0时)时,同样跳过重复值。

  • 时间复杂度:排序 O(n log n),双指针搜索 O(n^2),总体 O(n^2)

  • 空间复杂度O(1)(不考虑存储结果的空间)。


补充

Arrays.asList() 是 Java 标准库中 java.util.Arrays 类的一个静态方法,用于将一组元素转换为固定大小的列表(List

基本用法

import java.util.Arrays;
import java.util.List;public class Main {public static void main(String[] args) {// 创建包含多个元素的列表List<String> fruits = Arrays.asList("Apple", "Banana", "Cherry");// 输出列表内容System.out.println(fruits); // [Apple, Banana, Cherry]}
}

相关文章:

  • 直曲联合!【连续测量】让CAD多线段长度测量精准与效率双升级
  • C/C++ 面试复习笔记(5)
  • Vite 插件使用全攻略(含自动导入)
  • Codeforces Round 1029 (Div. 3)
  • QT 仿网易云项目
  • SQL-labs通关(23-38)
  • 自动化过程中,如何定位一闪而过的toast?
  • 精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
  • 什么是VR全景展示?VR全景展示的用途
  • SOC-ESP32S3部分:QA-关于唤醒词更改及配置操作步骤
  • IIC(I2C)通信隔离电路分享
  • SQL Server 手动收缩ldf文件
  • 记录:RK3588 PWM调试
  • 算法:模拟
  • 12.找到字符串中所有字母异位词
  • 镜像里切换为普通用户
  • JDK 17 序列化是怎么回事
  • 【c语言】安全完整性等级
  • 「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案
  • Qt Http Server模块功能及架构
  • 做网站济宁/衡阳seo优化推荐
  • 迪士尼网站是谁做的/广告营销策划
  • 网站建设华科技公司/中国关键词网站
  • 网站开发培训机构/关键词优化排名软件
  • 南沙定制型网站建设/如何软件网站优化公司
  • 刷钻做网站/快手seo