LeetCode - 15 三数之和

news2024/11/25 15:58:24

目录

题目来源

题目描述

示例

提示

题目解析

算法源码


题目来源

15. 三数之和 - 力扣(LeetCode)

题目描述

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

题目解析

本题需要从nums数组中找出所有和为0的三元组,且找出的三元组不能重复。

本题可以分解为两部分逻辑:

  1. 找到和为0的三元组
  2. 三元组去重

找和为0的三元组,最简单的方法就是三重for暴力枚举,时间复杂度O(n^3),n = nums.length(),结合备注的nums长度,可以得出暴力法会超时。

因此,我们需要一种更优的算法。

当前最优算法思路为:

首先,将nums数组进行升序,

然后,利用三个指针 i, l, r 来选择三个数,如果i, l,r指针指向的三数之和为0,则找到一个符合要求的三元组。

三指针指向的元素值的大小关系:nums[i] <= nums[l] <= nums[r]

上面三指针的运动逻辑其实可以概括,

首先确定三元组的最小值nums[i],然后找到一个与之匹配的nums[l],nums[r]

这样的话,就将三指针运动 转为了 双指针运动。

我们通过下面 示例1 图示来理解运动过程:

nums = [-1,0,1,2,-1,-4] 经过升序后,变为nums = [-4,-1,-1,0,1,2]

如上图,我们分别找了:

  • 三元组中最小值为-4,即 i 固定指向 0
  • 三元组中最小值为-1,即 i 固定指向 1
  • 三元组中最小值为-1,即 i 固定指向 2
  • 三元组中最小值为0,即 i 固定指向 3

的三元组情况。而针对上面情况,初始时l,r指针固定为:

  • l = i + 1
  • r = nums.length - 1

由于nums已经升序,因此,如果i, l, r三元组之和sum

  • sum > 0,则说明三元组之和大了,我们应该减小它,此时
  1. i 指针是固定的,因此不能移动 i 指针
  2. l 指针只能向右移动,因为 l 不能比 i 小,但是 l 指针右移只会增大三元组之和,因此不能移动 l 指针
  3. r 指针只有向左移动,而 r 指针向左移动的话,会导致nums[r]减少,因此三元组之和也会减少,所以我们左移 r 指针,即r--,可以减少三元组之和
  • sum < 0,则说明三元组之和小了,我们应该增大它,此时我们应该右移 l 指针,即 l++,来增大三元组之和
  • sum == 0,则说明当前i, l, r指向的三个数就是一个和为0的三元组

上面就是找和为0的三元组的逻辑。


下面就是去重逻辑的实现了

我们通过示例一可以发现,三指针运动过程中,产生了重复的三元组,如下图所示

那么如何才能去重呢?

最简单的方法,其实就是将所有和为0的三元组求出后,对比去重,但是效率非常低,不推荐。

更高效的去重策略是,发现规律,通过上面图示,我们可以发现:

重复的两个三元组,如果基于后面一个来看的话,那么变化的只有 i 指针,且nums[i] == nums[i-1],而l,r位置未发生改变。

如果我们把nums[i]和nums[i-1]看出一个整体的话,那么这两个重复二元组就是同一个。

且他们对于的l,r指针的运动逻辑也是一致的。因此后续会产生重复的二元组。

因此,我们可得去重结论,如果 num[i] == nums[i-1],则后续的l,r指针运动就可以不做了,因为会产生重复的二元组。


如果上面的 i 指针会产生重复二元组外,对于 l, r 指针同样会产生重复二元组。

比如下面例子:

上面例子中,产生了多个重复的三元组

但是实际上,

如果 nums[l] == nums[l+1],则可以直接 l++ 

如果 nums[r] == nums[r-1],则可以直接 r--

即运动过程如下:

即 nums[l] == nums[l+1] 的话,则 i, l, r 其实和 i, l+1,r 三元组是重复的,因此,我们可以直接跳过l+1的三元组,选择l++

    nums[r] == nums[r-1] 的话,则i ,l , r其实和i, l, r-1 三元组是重复的,因此,我们可以直接跳过r-1的三元组,选择r-- 


另外本题还有一个剪枝优化,

如果 nums[i] > 0的话,由于nums[i]是三元组中最小值,因此nums[i] > 0的话,则nums[l],nums[r]必然也大于0,三元组之和也大于0。

并且nums已经升序,因此nums[i+1]>0也是必然的,即nums[i+1]对应的三元组也是大于0的。

因此如果nums[i] > 0了,则可以直接break掉整个三指针运动。

JS算法源码

/**
 * @param {number[]} nums
 * @return {number[][]}
 */
var threeSum = function (nums) {
  const ans = [];

  nums.sort((a, b) => a - b);

  for (let i = 0; i < nums.length - 2; i++) {
    // 剪枝
    if (nums[i] > 0) break;

    // 去重
    if (i > 0 && nums[i] == nums[i - 1]) continue;

    let l = i + 1;
    let r = nums.length - 1;

    while (l < r) {
      const sum = nums[i] + nums[l] + nums[r];

      if (sum > 0) {
        r--;
      } else if (sum < 0) {
        l++;
      } else {
        ans.push([nums[i], nums[l], nums[r]]);

        // 去重
        while (l + 1 < r && nums[l] == nums[l + 1]) l++;
        // 去重
        while (r - 1 > l && nums[r] == nums[r - 1]) r--;
        l++;
        r--;
      }
    }
  }

  return ans;
};

三数之和 - 提交记录 - 力扣(LeetCode)

Java算法源码

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

class Solution {
  public List<List<Integer>> threeSum(int[] nums) {
    List<List<Integer>> ans = new ArrayList<>();

    Arrays.sort(nums);

    for (int i = 0; i < nums.length - 2; i++) {
      // 剪枝优化
      if (nums[i] > 0) break;

      // 去重
      if (i > 0 && nums[i] == nums[i - 1]) continue;

      int l = i + 1;
      int r = nums.length - 1;

      while (l < r) {
        int sum = nums[i] + nums[l] + nums[r];

        if (sum > 0) {
          r--;
        } else if (sum < 0) {
          l++;
        } else {
          ArrayList<Integer> tmp = new ArrayList<>();
          Collections.addAll(tmp, nums[i], nums[l], nums[r]);
          ans.add(tmp);

          // 去重
          while (l + 1 < r && nums[l] == nums[l + 1]) l++;
          // 去重
          while (r - 1 > l && nums[r] == nums[r - 1]) r--;

          l++;
          r--;
        }
      }
    }

    return ans;
  }
}

三数之和 - 提交记录 - 力扣(LeetCode)

Python算法源码

class Solution(object):
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        ans = []

        nums.sort()

        for i in range(len(nums) - 2):
            # 剪枝
            if nums[i] > 0:
                break

            # 去重            
            if i > 0 and nums[i] == nums[i - 1]:
                continue

            l = i + 1
            r = len(nums) - 1

            while l < r:
                total = nums[i] + nums[l] + nums[r]

                if total > 0:
                    r -= 1
                elif total < 0:
                    l += 1
                else:
                    ans.append([nums[i], nums[l], nums[r]])

                    # 去重
                    while l + 1 < r and nums[l] == nums[l + 1]:
                        l += 1

                    # 去重
                    while r - 1 > l and nums[r] == nums[r - 1]:
                        r -= 1

                    l += 1
                    r -= 1

        return ans

三数之和 - 提交记录 - 力扣(LeetCode)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Android】WMS(四)WMS职责

WMS职责 WMS&#xff08;Window Manager Service&#xff09;是 Android 系统中的一个系统服务&#xff0c;它是WindowManager的管理者&#xff0c;负责对窗口进行管理、分配资源&#xff0c;以及处理用户的输入事件等问题。WMS是整个系统中非常重要的一个组成部分&#xff0c;…

昨晚技术交流群“炸了”,论搞技术的网络工程师究竟能有多严谨?

昨日在IELAB网络实验室学习交流群中发生了一场“激烈”的争论&#xff0c;原本是同往常一样的答题领红包活动&#xff0c;同学对答案产生了异议&#xff0c;从而和Summer赵老师在群里进行了沟通交流&#xff0c;具体是什么情况呢&#xff1f; IELAB每日答题活动 于是乎&#xf…

JMeter 测试笔记(一):认识JMeter

引言&#xff1a; 在现代互联网时代&#xff0c;应用程序的性能已经成为了一个非常重要的问题&#xff0c;并且对于许多公司的生存和发展都起着至关重要的作用。 而JMeter作为一个免费且开源的性能测试工具&#xff0c;可以帮助我们进行各种类型的性能测试&#xff0c;如接口…

阿里巴巴最新开源:Java工程师面试笔记(30万字精华总结 + 面试1300问)吊打面试官绰绰有余

前言 作为一个 Java 程序员&#xff0c;你平时总是陷在业务开发里&#xff0c;每天噼里啪啦忙敲着代码&#xff0c;上到系统开发&#xff0c;下到 Bug 修改&#xff0c;你感觉自己无所不能。然而偶尔的一次聚会&#xff0c;你听说和自己一起出道的同学早已经年薪 50 万&#x…

网卡中的Ring buffer -- 解决 rx_resource_errors 丢包

1、软硬件环境 硬件&#xff1a; 飞腾E2000Q 平台 软件&#xff1a; linux 4.19.246 2、问题现象 网卡在高速收包的过程中&#xff0c;出现 rx error , 细查是 rx_resource_errors 如下&#xff1a; rootE2000-Ubuntu:~# ifconfig eth1 eth1: flags4163<UP,BROADCAST,RU…

Amazon SageMaker:探索AI绘画云端部署新方案

目录 1 从艺术实验到AI绘画2 什么是Amazon SageMaker&#xff1f;3 云端部署AI绘画应用3.1 模型构建与部署3.2 AI绘画测试(文生图) 4 亚马逊云科技中国峰会 1 从艺术实验到AI绘画 在过去&#xff0c;人们只希望基于已有的给定数据做一些预测和拟合&#xff0c;因此判别式模型得…

RFID资产盘点在企业的应用

随着新技术的发展&#xff0c;企业在不断地进行转型&#xff0c;企业为了更好地发展&#xff0c;对企业内部的管理工作越来越重视。在管理中&#xff0c;如何利用先进的科学技术来提高管理效率&#xff0c;成为了企业发展的关键。在资产管理上&#xff0c; RFID技术在资产盘点和…

TCP三次握手建立连接和四次挥手断开连接

TCP的连接与断开 TCP 通过三次握手建立连接&#xff0c;以建立确保数据传输的参数&#xff0c;连接的双方都将初始化与 TCP 连接相关的许多 TCP 状态变量。该连接是一条逻辑连接&#xff0c;其共同状态仅保留在二个通信端系统的TCP程序中。 TCP连接的组成包括&#xff1a;一台…

上门服务app开发|上门服务系统定制打开家政服务的大门

上门服务app可以为用户带来更加便捷的服务体验&#xff0c;不需要用户出门寻找服务商&#xff0c;只需要通过小程序下单即可享受到上门服务&#xff0c;省去了用户的时间和精力。同时上门服务app也为服务商提供了一个更广阔的市场&#xff0c;他们可以通过上门服务系统向更多的…

走进科学之sudo rm -rf,为什么如此危险

关注微信公众号“网络安全学习圈”&#xff0c;回复暗号【网络安全】&#xff0c;立即领取最新网安教程全家桶。 什么是 sudo rm -rf&#xff1f; sudo rm -rf 是一个linux的命令行命令&#xff0c;用于在系统中删除文件和目录。sudo表示以管理员权限运行该命令。rm是remove…

OPEN AI 全新版本来了2.0.0永久免费在线体验构建AI开放生态

V2.0.0 更新内容 后台整体功能重构完善后台增加订阅接口服务后台会陆续扩展订阅更多AI接口服务后台增加分销推广功能OPEN AI注册增加邮箱验证绑定OPEN AI开发者插件生态构建后台分销推广额度累计支持提现现金后台支持查询官方账号key使用量和余量开放接口提供账号绑定和订阅接…

【ChatGLM】记录一次Windows部署ChatGLM-6B流程及遇到的问题

文章目录 部署环境文件下载项目文件模型配置文件模型文件 运行demo遇到的问题 部署环境 系统版本&#xff1a;Windows 10 企业版 版本号&#xff1a;20H2 系统类型&#xff1a;64 位操作系统, 基于 x64 的处理器 处理器&#xff1a;Intel Core™ i7-8700 CPU 3.20GHz 3.19 GH…

软考A计划-电子商务设计师-模拟试题卷四

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&am…

NX/UG二次开发—Parasolid—PK_EDGE_ask_convexity

判断实体边的凸凹性 Convexity Value Example convex PK_EDGE_convexity_convex_c concave PK_EDGE_convexity_concave_c variable the convexity varies along the edge PK_EDGE_convexity_variable_c smooth flat parallel surface normals, both faces have zero f…

cli3 非父子组件传值

这里&#xff0c;App.vue中&#xff0c;引入了parent组件&#xff1b;parent组件中引入了child组件。现在要从app.vue&#xff0c;向child组件传值。 主要文件&#xff1a; 1. 通过事件总线传值 1. src ->util->bus.js // 通过util中的bus&#xff0c;完成两个组件之间…

你的Postman为什么连不了数据库?

postman本身没有数据库连接功能&#xff0c;所以用到了node.js中的xmysql实现Rest API的生成&#xff0c;利用postman进行请求&#xff0c;获取需要的数据&#xff0c;来做数据准备或断言 1.安装 安装node.js&#xff1a;要求版本大于等于7.6 首先保证你的环境上有node.js&a…

打工人,别着急摆烂,看看你到底值多少钱?

2023求职现状&#xff1a; HR&#xff1a;看简历&#xff0c;以为能造飞机&#xff0c;招进来以后发现螺丝都不会拧。 普通求职者&#xff1a;看公司招聘要求&#xff0c;以为这个岗位是造飞机的&#xff0c;没想到进去以后是拧螺丝的。 大龄求职者&#xff1a;以前我都是造飞…

1.平台介绍:FISCO-BCOS 区块链

&#xff08;1&#xff09;概念: FISCO BCOS是由国内企业主导研发、对外开源、安全可控的企业级金融联盟链底层平台。它以联盟链的实际需求为出发点&#xff0c;兼顾性能、安全、可运维性、易用性、可扩展性&#xff0c;支持多种SDK&#xff0c;并提供了可视化的中间件工具&am…

Python3+Selenium2完整的自动化测试实现之旅(六):Python单元测试模块Unittest运用

目录 引言 一、Unittest单元测试框架简介 二、首次使用Unittest模块 三、Unittest模块批量加载和管理用例 写在最后 引言 这篇文章讲述的是Python3Selenium2自动化测试实现之旅的第六篇&#xff0c;主要是介绍如何运用Python单元测试模块Unittest进行测试。 我个人觉得这篇…

【新版】系统架构设计师 - 数学与经济管理

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 文章目录 架构 - 数学与经济管理考点摘要最小生成树最短路径网络与最大流量线性规划动态规划预测 - 博弈论预测 - 状态转移矩阵决策 - 不确定型决策决策 - 决策树排队论数学建模数学建模 - 模型分析数学建模 - 模型…