LeetCode【0015】三数之和

本文目录

  • 1 中文题目
  • 2 求解思路
    • 2.1 基础解法:暴力枚举法
    • 2.2 优化解法:哈希表法
    • 2.3 最优解法:双指针法
  • 3 题目总结

1 中文题目

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请返回所有和为 0 且不重复的三元组。

注意答案中不可以包含重复的三元组,输出三元组的顺序并不重要。

**示例 **

输入: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]
输入:nums = [0,1,1]
输出:[]
解释:三数之和不为 0 
输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:有且只有一个三元组

提示:

  • 3 ≤ n u m s . l e n g t h ≤ 3000 3 \leq nums.length \leq 3000 3nums.length3000
  • − 1 0 5 ≤ n u m s [ i ] ≤ 1 0 5 -10^5 \leq nums[i] \leq 10^5 105nums[i]105

2 求解思路

2.1 基础解法:暴力枚举法

思路
使用三重循环遍历所有可能的三元组组合,找出满足和为0的组合。首先对数组进行排序,前面的数比后面的数字小,当前面的数大于0时,就可以提前跳出循环。最后对结果进行去重处理。

Python代码

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        """
        暴力枚举法
        - 提前退出条件
        - 优化循环范围
        - 增加剪枝策略
        """
        if len(nums) < 3:
            return []
        
        # 对数组排序,便于剪枝
        nums.sort()
        n = len(nums)
        result_set = set()
        
        # 第一层循环
        for i in range(n-2):
            # 优化1:如果第一个数大于0,后面不可能和为0
            if nums[i] > 0:
                break
                
            # 第二层循环
            for j in range(i+1, n-1):
                # 优化2:如果前两个数之和大于0,第三个数更大,和一定大于0
                if nums[i] + nums[j] > 0:
                    break
                    
                # 第三层循环
                for k in range(j+1, n):
                    curr_sum = nums[i] + nums[j] + nums[k]
                    
                    # 优化3:根据和的大小提前退出
                    if curr_sum > 0:
                        break
                        
                    if curr_sum == 0:
                        result_set.add((nums[i], nums[j], nums[k]))
        
        return [list(x) for x in result_set]

时空复杂度分析

  • 时间复杂度分析:O(n³)
    • 三重循环:O(n³)
  • 空间复杂度分析:O(n)

上面的代码,因为时间复杂度不能通过LeetCode的全部测试用例


2.2 优化解法:哈希表法

思路

将三数之和转化为两数之和加一个数,使用哈希表存储遍历过的数字,实现O(1)的查找。通过两层循环枚举两个数,然后在哈希表中查找第三个数,从而降低时间复杂度。

详细算法步骤:

  • 预处理:
    • 数组排序,便于去重和剪枝
    • 处理特殊情况(长度小于3等)
  • 外层循环(第一个数):
    • 遍历数组,固定第一个数
    • 利用排序后的特性进行剪枝
    • 处理重复元素
  • 内层循环(第二个数):
    • 遍历第一个数之后的元素
    • 使用哈希表存储已遍历的数
    • 查找满足条件的第三个数
  • 结果处理:
    • 找到符合条件的组合后加入结果集,处理重复元素,确保结果不重复

python代码

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        """
        哈希表解法
        1. 提前计算边界情况
        2. 更多的剪枝条件
        3. 优化哈希表使用方式
        """
        # 特判
        if len(nums) < 3:
            return []
            
        nums.sort()
        n = len(nums)
        res = []
        
        # 优化1:提前判断边界情况
        # 最小的三个数和大于0,或最大的三个数和小于0,直接返回
        if nums[0] + nums[1] + nums[2] > 0 or nums[-1] + nums[-2] + nums[-3] < 0:
            return []
            
        # 第一层循环,固定第一个数
        for i in range(n-2):
            # 第一个数大于0,后面不可能有解
            if nums[i] > 0:
                break
                
            # 去重
            if i > 0 and nums[i] == nums[i-1]:
                continue
                
            # 优化2:当前数字和可能的最小两个数和大于0,后面不可能有解
            if nums[i] + nums[i+1] + nums[i+2] > 0:
                break
                
            # 优化3:当前数字和可能的最大两个数和小于0,跳过当前数
            if nums[i] + nums[-1] + nums[-2] < 0:
                continue
                
            # 第二层循环,固定第二个数
            j = i + 1
            # 用set存储已经遍历过的数
            seen = set()
            
            while j < n:
                # 计算需要的第三个数
                target = -(nums[i] + nums[j])
                
                # 如果target在seen中,说明找到了答案
                if target in seen:
                    res.append([nums[i], nums[j], target])
                    # 去重:跳过重复的第二个数
                    while j + 1 < n and nums[j] == nums[j+1]:
                        j += 1
                        
                # 将当前数加入seen        
                seen.add(nums[j])
                j += 1
                
        return res

时空复杂度分析

  • 时间复杂度:O(n²)
    • 排序: O(nlogn)
    • 两层循环: O(n²)
    • 哈希表查找: O(1)
  • 空间复杂度:O(n)
    • 排序: O(logn)或O(n),取决于具体实现
    • 哈希表: O(n)

2.3 最优解法:双指针法

思路
先对数组排序,固定一个数,然后用双指针在剩余部分寻找两个数,使三数之和为0。通过指针的移动来降低时间复杂度,同时利用排序后的特性进行剪枝和去重。核心思想是将问题转化为"一个固定数 + 两数之和"的形式,通过排序实现去重和双指针移动的条件,利用双指针减少一层循环,降低时间复杂度。

详细思路解析:

  • 预处理阶段
    • 对数组进行排序,使数组有序,排序后的数组便于去重和指针移动,排序后可以利用数组特性进行剪枝。
  • 固定第一个数
    • 从左到右枚举第一个数,固定一个数后,问题转化为两数之和。利用有序特性进行剪枝(第一个数大于0则结束)
  • 双指针查找
    • left指针从固定数右侧开始
    • right指针从数组末尾开始
    • 根据三数之和与0的关系移动指针:
      • 和大于0:右指针左移
      • 和小于0:左指针右移
      • 和等于0:记录结果并同时移动两个指针
  • 去重处理
    • 固定数去重:跳过相同的第一个数
    • 左指针去重:跳过相同的左侧数
    • 右指针去重:跳过相同的右侧数

python代码

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        """
        使用双指针法求解三数之和问题
        
        参数:
            nums: 输入数组
        返回:
            满足和为0的三元组列表
        """
        # 处理特殊情况
        if len(nums) < 3:
            return []
            
        # 对数组进行排序,便于去重和使用双指针
        nums.sort()
        n = len(nums)
        result = []
        
        # 固定第一个数,遍历到倒数第三个数即可
        for i in range(n-2):
            # 优化1:如果第一个数大于0,后面的数都比它大,和不可能为0
            if nums[i] > 0:
                break
                
            # 优化2:跳过重复的第一个数,避免重复结果
            if i > 0 and nums[i] == nums[i-1]:
                continue
                
            # 双指针分别指向当前数后的两端
            left = i + 1
            right = n - 1
            
            # 双指针移动寻找满足条件的组合
            while left < right:
                curr_sum = nums[i] + nums[left] + nums[right]
                
                if curr_sum == 0:
                    # 找到满足条件的三元组
                    result.append([nums[i], nums[left], nums[right]])
                    
                    # 跳过重复的left值
                    while left < right and nums[left] == nums[left+1]:
                        left += 1
                    # 跳过重复的right值
                    while left < right and nums[right] == nums[right-1]:
                        right -= 1
                        
                    # 继续移动指针寻找其他组合
                    left += 1
                    right -= 1
                    
                elif curr_sum < 0:
                    # 和小于0,需要增加和,左指针右移
                    left += 1
                else:
                    # 和大于0,需要减少和,右指针左移
                    right -= 1
                    
        return result

时空复杂度分析

  • 时间复杂度分析:O(n²)
    • 排序:O(nlogn)
    • 外层循环:O(n)
    • 双指针操作:O(n)
  • 空间复杂度分析:O(logn)或O(n)
    • 排序空间:O(logn)或O(n),取决于排序算法

3 题目总结

题目难度:中等
数据结构:数组、哈希表
应用算法:双指针

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大数据新视界 -- 大数据大厂之 Impala 性能优化:基于数据特征的存储格式选择(上)(19/30)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

【C++】用红黑树封装set和map

在C标准库中&#xff0c;set容器和map容器的底层都是红黑树&#xff0c;它们的各种接口都是基于红黑树来实现的&#xff0c;我们在这篇文章中已经模拟实现了红黑树 ->【C】红黑树&#xff0c;接下来我们在此红黑树的基础上来看看如何封装set和map。 一、共用一颗红黑树 我…

Leetcode3345. 最小可整除数位乘积 I

Every day a Leetcode 题目来源&#xff1a;3345. 最小可整除数位乘积 I 解法1&#xff1a;枚举 至多循环 10 次&#xff0c;一定会遇到个位数为 0 的数字&#xff0c;数位乘积是 0&#xff0c;一定是 t 的倍数。 所以暴力枚举即可。 代码&#xff1a; /** lc appleetcod…

通过scrapy和Django登录、爬取和持久化数据

使用 Scrapy 和 Django 实现登录、爬取和持久化数据的完整流程&#xff0c;可以通过以下步骤完成&#xff1a; 创建 Django 项目和数据库模型&#xff1a;定义一个存储爬取数据的数据库模型。创建 Scrapy 项目&#xff1a;实现登录并抓取目标页面的数据。整合 Scrapy 和 Djang…

SpringMVC全面复习

Javaweb SpringMVC Spring MVC是Spring框架的一个模块&#xff0c;专门用于构建Web应用程序的模型-视图-控制器&#xff08;MVC&#xff09;架构。它通过清晰的分离关注点&#xff0c;简化了Web应用各部分的开发。Spring MVC提供了强大的绑定机制&#xff0c;能够将请求参数绑定…

【再谈设计模式】抽象工厂模式~对象创建的统筹者

一、引言 在软件开发的世界里&#xff0c;高效、灵活且易于维护的代码结构是每个开发者追求的目标。设计模式就像是建筑蓝图中的经典方案&#xff0c;为我们提供了应对各种常见问题的有效策略。其中&#xff0c;抽象工厂模式在对象创建方面扮演着重要的角色&#xff0c;它如同一…

【Linux】ELF可执行程序和动态库加载

&#x1f525; 个人主页&#xff1a;大耳朵土土垚 &#x1f525; 所属专栏&#xff1a;Linux系统编程 这里将会不定期更新有关Linux的内容&#xff0c;欢迎大家点赞&#xff0c;收藏&#xff0c;评论&#x1f973;&#x1f973;&#x1f389;&#x1f389;&#x1f389; 文章目…

SpringBootCloud 服务注册中心Nacos对服务进行管理

介绍 Nacos&#xff08;Naming and Configuration Service&#xff09;是一个开源的、动态的服务发现、配置管理和服务管理平台&#xff0c;特别适用于云原生应用和微服务架构。它可以作为服务注册中心&#xff0c;用于微服务的注册、发现、配置管理等。在微服务架构中&#x…

八款局域网监控软件优选|2024最新排行榜(企业老板收藏篇)

在当今数字化办公的时代&#xff0c;企业和组织对于局域网电脑监控的需求日益增长。无论是为了保障信息安全、提高员工工作效率&#xff0c;还是为了规范网络行为&#xff0c;一款优秀的局域网电脑监控软件都能发挥重要作用。市面上的监控软件种类繁多&#xff0c;功能各异&…

限价订单簿中的高频交易

数量技术宅团队在CSDN学院推出了量化投资系列课程 欢迎有兴趣系统学习量化投资的同学&#xff0c;点击下方链接报名&#xff1a; 量化投资速成营&#xff08;入门课程&#xff09; Python股票量化投资 Python期货量化投资 Python数字货币量化投资 C语言CTP期货交易系统开…

丹摩征文活动|CogVideoX-2b:从0到1,轻松完成安装与部署!

丹摩征文活动 | CogVideoX-2b&#xff1a;从0到1&#xff0c;轻松完成安装与部署&#xff01; CogVideoX 介绍 CogVideoX的问世&#xff0c;标志着视频制作技术迈入了一个全新的时代。它不仅打破了传统视频制作在效率与质量之间的平衡难题&#xff0c;还通过其先进的3D变分自…

Creo 9.0 中文版软件下载安装教程

[软件名称]&#xff1a;Creo 9.0 [软件语言]&#xff1a;简体中文 [软件大小]&#xff1a;5.2G [安装环境]&#xff1a;Win11/Win10/ [硬件要求]&#xff1a;内存8G及以上 下载方法&#xff1a;电脑打开浏览器&#xff0c;复制下载链接&#xff0c;粘贴至浏览器网址栏&…

RT-DETR融合CVPR[2024]无膨胀多尺度卷积PKI模块及相关改进思路

RT-DETR使用教程&#xff1a; RT-DETR使用教程 RT-DETR改进汇总贴&#xff1a;RT-DETR更新汇总贴 《Poly Kernel Inception Network for Remote Sensing Detection》 一、 模块介绍 论文链接&#xff1a;https://arxiv.org/abs/2403.06258 代码链接&#xff1a;https://github…

ubuntu-desktop-24.04上手指南(更新阿里源、安装ssh、安装chrome、设置固定IP、安装搜狗输入法)

ubuntu-desktop-24.04上手指南(更新阿里源、安装ssh、安装chrome、设置固定IP、安装搜狗输入法) 一、更新并安装基础软件 #切换root用户 sudo su -#更新 apt update #升级 apt upgrade#install vim apt install vim#install net-tools apt install net-tools二、安装ssh并设置…

[CKS] K8S ServiceAccount Set Up

最近准备花一周的时间准备CKS考试&#xff0c;在准备考试中发现有一个题目关于Rolebinding的题目。 ​ 专栏其他文章: [CKS] Create/Read/Mount a Secret in K8S-CSDN博客[CKS] Audit Log Policy-CSDN博客 -[CKS] 利用falco进行容器日志捕捉和安全监控-CSDN博客[CKS] K8S Netwo…

介绍和安装及数据类型

1、介绍和安装 1.1、简介 ClickHouse是俄罗斯的Yandex于2016年开源的列式存储数据库&#xff08;DBMS&#xff09;&#xff0c;使用C语言编写&#xff0c;主要用于在线分析处理查询&#xff08;OLAP&#xff09;&#xff0c;能够使用SQL查询实时生成分析数据报告。 OLAP&…

算法魅力-二分查找实战

目录 前言 算法定义 朴素二分模版 二分查找 二分的边界查找 在排序数组中查找元素的第一个和最后一个位置&#xff08;medium&#xff09; 暴力算法 二分查找 边界查找分析 山峰数组的峰顶 暴力枚举 二分查找 搜索旋转排序数组中的最小值&#xff08;medium&#xf…

Linux第四讲:Git gdb

Linux第四讲&#xff1a;Git && gdb 1.版本控制器Git1.1理解版本控制1.2理解协作开发1.3Git的历史1.4Git的操作1.4.1仓库创建解释、仓库克隆操作1.4.2本地文件操作三板斧1.4.3文件推送详细问题 2.调试器 -- gdb/cgdb使用2.1调试的本质是什么2.2watch命令2.3set var命令…

海底捞点单

单点锅底推荐&#xff1a; 番茄锅底通31 牛油麻辣通44 清汤麻辣备44 菌汤锅底通31 小吃&主食&#xff1a; 捞派捞面一黄金小馒头一茴香小油条 红糖枇杷一小酥肉 DIY锅底推荐&#xff1a; 1.寿喜锅&#xff1a;海鲜味酱4勺陈醋1勺蚝油2勺盐适量白糖7勺 芹菜1勺 2.麻辣锅底…

PNG图片批量压缩exe工具+功能纯净+不改变原始尺寸

小编最近有一篇png图片要批量压缩&#xff0c;大小都在5MB之上&#xff0c;在网上找了半天要么就是有广告&#xff0c;要么就是有毒&#xff0c;要么就是功能复杂&#xff0c;整的我心烦意乱。 于是我自己用python写了一个纯净工具&#xff0c;只能压缩png图片&#xff0c;没任…