(双指针 ) 15. 三数之和 ——【Leetcode每日一题】

news2024/11/16 8:59:30

❓15. 三数之和

难度:中等

给你一个整数数组 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 < = n u m s . l e n g t h < = 3000 3 <= nums.length <= 3000 3<=nums.length<=3000
  • − 1 0 5 < = n u m s [ i ] < = 1 0 5 -10^5 <= nums[i] <= 10^5 105<=nums[i]<=105

💡思路:双指针

其实这道题目使用哈希法并不十分合适,因为在去重的操作中有很多细节需要注意,在面试中很难直接写出没有 bug 的代码。
而且使用哈希法 在使用两层 for 循环的时候,能做的剪枝操作很有限,虽然时间复杂度是 O ( n 2 ) O(n^2) O(n2),也是可以在leetcode上通过,但是程序的执行时间依然比较长 。

这里使用双指针法

在这里插入图片描述
拿这个 nums 数组来举例,首先将数组排序,然后有一层 for 循环,i 从下标 0 的地方开始,同时定一个下标 left 定义在 i +1的位置上,定义下标 right 在数组结尾的位置上。
依然还是在数组中找到 a b c 使得 a + b +c = 0,我们这里相当于 a = nums[i]b = nums[left]c = nums[right]:

  • 如果 nums[i] + nums[left] + nums[right] > 0 就说明 此时三数之和大了,因为数组是排序后了,所以 right 下标就应该向左移动,这样才能让三数之和小一些
  • 如果 nums[i] + nums[left] + nums[right] < 0 说明 此时 三数之和小了,left 就向右移动,才能让三数之和大一些,直到 leftright 相遇为止。

答案中不可以包含重复的三元组,所以要考虑去重

  • 由于和为 0 ,所以只有三个数都为 0 时,才可能三个数同时相等,如果有这种情况,则加入结果,退出循环,因为后面的任意三个数都大于等于0;
  • 每次循环三个数中的第一个数 num[i] 都不同,避免重复
  • 如果后两个相等,则只加这一种情况,退出循环;

🍁代码:(Java、C++)

Java

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> ans = new ArrayList<>();
        Arrays.sort(nums);
        int n = nums.length - 1;
        for(int i = 0; i < n - 1; i++){//遍历到数组倒数第三个数即可
            if(nums[i] == 0){
                if(nums[i + 2] == 0){
                    ans.add(Arrays.asList(0, 0, 0));
                }
                break;
            }
            if(i > 0 && nums[i] == nums[i - 1]) continue; //去重,每次循环第一个数都不同

            int left = i + 1, right = n;
            
            while(left < right){
                if(nums[left] + nums[right] < -nums[i]) left++;
                else if(nums[left] + nums[right] > -nums[i]) right--;
                else{
                    ans.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    if(nums[left] == nums[right]) break;//去重,后两个相同则结束循环
                    while(left < right && nums[left + 1] == nums[left]) left++; //找到下一个比left大的数
                    left++;
                    while(left < right && nums[right - 1] == nums[right]) right--; //找到下一个比right小的数
                    right--;
                }
            }
        }
        return ans;
    }
}

C++

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> ans;
        sort(nums.begin(), nums.end());
        int n = nums.size() - 1;
        for(int i = 0; i < n - 1; i++){
            if(nums[i] == 0) {
                if(nums[i + 2] == 0){
                    ans.push_back({0,0,0});
                }
                break;
            }
            if(i > 0 && nums[i] == nums[i - 1]) continue;//去重,每次循环第一个数都不同

            int left = i + 1, right = n;
            
            while(left < right){
                if(nums[left] + nums[right] < -nums[i]) left++;
                else if(nums[left] + nums[right] > -nums[i]) right--;
                else{
                    ans.push_back({nums[i], nums[left], nums[right]});
                    if(nums[left] == nums[right]) break;//去重,后两个相同则结束循环
                    while(left < right && nums[left + 1] == nums[left]) left++;//找到下一个比left大的数
                    left++;
                    while(left < right && nums[right - 1] == nums[right]) right--;//找到下一个比right小的数
                    right--;
                }
            }
        }
        return ans;
    }
};

🚀 运行结果:

在这里插入图片描述

🕔 复杂度分析:

  • 时间复杂度 O ( n 2 ) O(n^2) O(n2),其中 n 为数组 nums 的长度。
  • 空间复杂度 O ( 1 ) O(1) O(1),忽略存储答案的空间。

题目来源:力扣。

放弃一件事很容易,每天能坚持一件事一定很酷,一起每日一题吧!
关注我LeetCode主页 / CSDN—力扣专栏,每日更新!

注: 如有不足,欢迎指正!

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

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

相关文章

pip安装python库速度慢、失败及超时报错解决办法

背景&#xff1a; 随着人工智能的不断兴起&#xff0c;python作为最接近人工智能的语言&#xff0c;变得越来越流行&#xff0c;人生苦短&#xff0c;python要学起来。之所以越来用的人喜欢学习python和研究Python&#xff0c;除了python本身便于学些、语法简短、面向对象等特点…

静态库与动态库的区别

静态库与动态库的区别 静态库动态库 首先用OpenCV的开源库来举个例子了解一下库文件的分类&#xff1a; bin文件夹里面放的都是dll文件&#xff1b; lib文件夹里面放的都是伴随dll文件的动态lib文件&#xff1b; staticlib文件夹里面放的才是真正的静态lib文件&#xff0c;和…

专利费减备案操作流程——让你申请专利时的官费大大打折

【系列专栏】&#xff1a;博主结合工作实践输出的&#xff0c;解决实际问题的专栏&#xff0c;朋友们看过来&#xff01; 《项目案例分享》 《极客DIY开源分享》 《嵌入式通用开发实战》 《C语言开发基础总结》 《从0到1学习嵌入式Linux开发》 《QT开发实战》 《Android开发实…

【为什么控件的引用和控件的代理要用weak Objective-C语言】

一、还记得我们给大家说过,UI控件,当用一个属性,引用UI控件的时候,那个标记要用weak, 1.为什么,但是用strong,是不是也行, 但是,如果是控件的代理对象,是不是一定得用weak, 我现在就告诉你,为什么, 注意听,现在,比如说,这个是控制器, 我先解释,为什么UI控…

Java实战-基于JDK的LRU算法实现、优雅的实现代码耗时统计(Spring AOP、AutoCloseable方式)

场景 Java中基于JDK的LRU算法实现 LRU算法-缓存淘汰算法-Least recently used,最近最少使用算法 根据数据的历史访问记录来进行淘汰数据&#xff0c;其核心思想是&#xff1a;如果有数据最近被访问过&#xff0c;那么将来被访问的几率也更高 在Java中可以利用LinkedHashMap…

34. Linux系统下打包qt应用程序

1. 说明 对程序进行打包前需要在Release模式对程序代码进行编译,然后得到编译后的可执行文件,正常情况下这个可执行文件是可以双击打开运行的,如果无法双击运行,可在**.pro**文件内加入下面的代码: QMAKE_LFLAGS += -no-pie TEMPLATE = app同时将main.qml文件中的Window…

【总结】对接达梦数据库DM8详细教程

目录 1.达梦数据库-技术文档2.软件安装包下载2.1 iso 安装版2.2 docker 安装版 3.DM8单机安装部署规范4.安装操作步骤4.1 安装docker4.2 docker安装dameng&#xff08;推荐&#xff09; 5. 启动/停止数据库6.客户端连接使用7.DDL SQL实践7.1 创建表空间7.2 建表语句 8.DML SQL实…

「2023大学生就业报告 」出炉,应届生都去了哪些行业?

2023年的应届毕业生人数再创新高&#xff0c;达到1158万人&#xff0c;是不是开始担忧他们的就业了&#xff1f;别急&#xff0c;最近Boss直聘发布的一组数据&#xff0c;会让这样的担忧有所缓解。 期望薪资有所下降 和增长明显的毕业人数相反的是&#xff0c;这一届大专、本…

网络流量监控及流量异常检测

当今的企业面临着许多挑战&#xff0c;尤其是在监控其网络基础设施方面&#xff0c;需要确保随着网络规模和复杂性的增长&#xff0c;能够全面了解网络的运行状况和安全性。为了消除对网络性能的任何压力&#xff0c;组织应该采取的一项重要行动是使用随组织一起扩展的工具监控…

探究工业设备状态监测的典型对象和常用方法

工业设备状态监测的目的是实时掌握设备的健康状况&#xff0c;及时发现潜在故障迹象&#xff0c;并采取相应的维修和维护措施。通过有效的状态监测&#xff0c;企业可以降低设备故障风险&#xff0c;减少计划外停机时间&#xff0c;提高生产效率&#xff0c;节约维护成本&#…

深兰科技亮相2023数博会:硅基知识大模型推动个人数字化产业

近日&#xff0c;2023中国国际大数据产业博览会 “数字经济与实体经济深度融合”论坛在贵阳举行。腾讯云、京东集团、网易、深兰科技等8家企业负责人进行了行业演讲。 作为2023数博会的专业论坛之一&#xff0c;本次论坛以“数融百业 创变赋新”为主题&#xff0c;从数实融合视…

项目冲突管理机制的4大关键环节

1、冲突预防功能 预先采取一些措施防止冲突的产生&#xff0c;如建立有效的沟通机制。在项目开始前&#xff0c;制定沟通计划、沟通频率和方式&#xff0c;以确保项目成员充分了解自我职责和任务&#xff0c;并自愿分享和讨论。通过有效的沟通机制&#xff0c;最大限度避免不必…

QoS实现之限速

基于流分类&#xff08;MQC&#xff09;的流量监管 前面我们已经介绍过&#xff0c;流量监管一般用于入方向。下面举个例子&#xff0c;详细介绍如何在入方向配置基于MQC的流量监管。如图2所示&#xff0c;企业的语音业务对应的VLAN ID为120&#xff0c;视频业务对应的VLAN ID…

自学网安该怎么做以及怎么找工作?

趁着今天下班&#xff0c;我花了几个小时整理了下&#xff0c;非常不易&#xff0c;希望大家可以点赞收藏支持一波&#xff0c;谢谢。 我的经历&#xff1a; 我 19 年毕业&#xff0c;大学专业是物联网工程&#xff0c;我相信很多人在象牙塔里都很迷茫&#xff0c;到了大三大…

图解LeetCode——146. LRU 缓存

一、题目 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类&#xff1a; LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存中&#xff0c;则返回关键字的值&#xff0c;…

什么才是自动化测试框架?最流行的自动化测试框架整理,你的进阶之路...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 Python自动化测试&…

Smartbi助力航天百亿级遥测数据实现秒级查询

“Smartbi全程参与了火星探测任务、中国载人空间站建设任务&#xff0c;为航天任务参战单位提供专业、易用、高性能的实时数据查询分析监控平台&#xff0c;实现航天器飞行状态监测和预警&#xff0c;让咱们的科研人员专注聚焦科研工作&#xff0c;保障航天任务顺利进行。Smart…

Benewake(北醒) 快速实现 TF02-i-RS485 与电脑通信操作说明

目录 一、前言二、工具准备1. USB-RS485 转接器2. TF02-i-RS4853. 兆信直流电源4.连接线、绝缘胶带、螺丝刀5. PC&#xff1a;Windows 系统6. 串口助手软件 三、连接方式1. USB-RS485 转接板接口说明2. TF02-i-RS485 引脚定义3. 连接图 四、TF02-i-RS485 与电脑通信操作说明1. …

js中+new Date()

在学习js过程中遇到了这样的写法&#xff1a; var nownew Date(); 在这段代码中有一个号&#xff0c;上网查阅得知在前面加一个号是涉及到了隐式转换&#xff0c;也就是触发对象执行valueof进行求值。 valueof可以用来得到现在时间距离1970.1.1总的毫秒数&#xff1a; var …

Android12之源码手动生成aidl对应java/cpp/ndk/rust服务(一百五十三)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…