BM54-三数之和

news2024/9/25 21:22:00

题目

给出一个有n个元素的数组S,S中是否有元素a,b,c满足a+b+c=0?找出数组S中所有满足条件的三元组。

数据范围:0≤n≤1000,数组中各个元素值满足 ∣val∣≤100。

空间复杂度:O(n^2),时间复杂度 O(n^2)。

注意:

  1. 三元组(a、b、c)中的元素必须按非降序排列。(即a≤b≤c)
  2. 解集中不能包含重复的三元组。

例如,给定的数组 S = {-10 0 10 20 -10 -40},解集为(-10, -10, 20),(-10, 0, 10)。

示例1

输入:[0]

返回值:[]

示例2

输入:[-2,0,1,1,2]

返回值:[[-2,0,2],[-2,1,1]]

示例3

输入:[-10,0,10,20,-10,-40]

返回值:[[-10,-10,20],[-10,0,10]]


思路1:双指针

实现版本1:

直接找三个数字之和为某个数,太麻烦了,我们是不是可以拆分一下:如果找到了某个数a,要找到与之对应的另外两个数,三数之和为0,那岂不是只要找到另外两个数之和为−a?这就方便很多了。

因为三元组内部必须是有序的,因此可以优先对原数组排序,这样每次取到一个最小的数为a,只需要在后续数组中找到两个之和为−a就可以了,我们可以用双指针缩小区间,因为太后面的数字太大了,就不可能为−a,可以舍弃。

具体做法:

  • step 1:排除边界特殊情况。
  • step 2:既然三元组内部要求非降序排列,那我们先得把这个无序的数组搞有序了,使用sort函数优先对其排序。
  • step 3:得到有序数组后,遍历该数组,对于每个遍历到的元素假设它是三元组中最小的一个,那么另外两个一定在后面。
  • step 4:需要三个数相加为0,则另外两个数相加应该为上述第一个数的相反数,我们可以利用双指针在剩余的子数组中找有没有这样的数对。双指针指向剩余子数组的首尾,如果二者相加为目标值,那么可以记录,而且二者中间的数字相加可能还会有。
  • step 5:如果二者相加大于目标值,说明右指针太大了,那就将其左移缩小,相反如果二者相加小于目标值,说明左指针太小了,将其右移扩大,直到两指针相遇,剩余子数组找完了。

注:对于三个数字都要判断是否相邻有重复的情况,要去重。


代码1.1

import java.util.ArrayList;
import java.util.Arrays;

public class Solution {
    public ArrayList<ArrayList<Integer>> threeSum(int[] num) {
        ArrayList<ArrayList<Integer> > res = new ArrayList<ArrayList<Integer>>();
        int n = num.length;

        //不够三元组
        if(n < 3) {
            return res;
        }

        //排序
        Arrays.sort(num);

        for(int i = 0; i < n - 2; i++) {
            if(i != 0 && num[i] == num[i - 1]) {
                continue;
            }
            //后续的收尾双指针
            int left = i + 1;
            int right = n - 1;
            //设置当前数的负值为目标
            int target = -num[i];

            while(left < right) {
                //双指针指向的二值相加为目标,则可以与num[i]组成0
                if(num[left] + num[right] == target) {
                    ArrayList<Integer> temp = new ArrayList<Integer>();
                    temp.add(num[i]);
                    temp.add(num[left]);
                    temp.add(num[right]);
                    res.add(temp);
                    while(left + 1 < right && num[left] == num[left + 1]) {
                        //去重
                        left++;
                    }
                    while(right - 1 > left && num[right] == num[right - 1]) {
                        //去重
                        right--;
                    }
                    //双指针向中间收缩
                    left++;
                    right--;
                } else if(num[left] + num[right] > target) {  //双指针指向的二值相加大于目标,右指针向左
                    right--;
                } else {  //双指针指向的二值相加小于目标,左指针向右
                    left++;
                }
            }
        }
        return res;
    }
}
  • 时间复杂度:O(n^2),排序的复杂度为O(nlog2n),查找三元组的复杂度为O(n2)。
  • 空间复杂度:O(1),res属于必要空间,不属于额外空间,无其他辅助空间。

实现版本2:

  1. 对数组长度进行特判。
  2. 排序。
  • num[i] > 0说明后面的三数和不可能等于0。
  • 对于重复元素跳过。
  • 左指针left = i + 1,右指针right = len - 1
  • nums[i] + nums[left] + nums[right] == 0执行循环,判断左界和右界是否和下一位置重复,去除重复解。并同时将 left,right 移到下一位置,寻找新的解。
  • 如果和<0,left++;
  • 如果和>0,right--;


代码1.2

import java.util.*;

public class Solution {
    public ArrayList<ArrayList<Integer>> threeSum(int[] num) {
        //存放最终答案的二维数组
        ArrayList<ArrayList<Integer>> ans = new ArrayList<>();
        int len = num.length;

        //特判:长度<3的数组不满足条件
        if (len < 3) {
            return ans;
        }

        //排序O(nlogn)
        Arrays.sort(num);

        for (int i = 0; i < len; i++) {
            //如果nums[i]已经大于0,就没必要继续往后了,因为和就是0啊
            if (num[i] > 0) {
                return ans;
            }
            //注意考虑越界i>0,主要功能是排除重复值
            if (i > 0 && num[i] == num[i - 1]) {
                continue;
            }
            //声明指针
            int cur = num[i];
            int left = i + 1;
            //从尾部开始
            int right = len - 1;
            
            while (left < right) {
                //满足条件的三数和
                int tp_ans = cur + num[left] + num[right];
                //如果已经找到和为0
                if (tp_ans == 0) {
                    //创建一个数组,并将满足条件的三元素放进去
                    ArrayList<Integer> list = new ArrayList<>();
                    list.add(cur);
                    list.add(num[left]);
                    list.add(num[right]);
                    //将最终的结果存入答案数组ans中
                    ans.add(list);
                    //判断是left指针指向是否重复
                    while (left < right && num[left] == num[left + 1]) {
                        left++;
                    }
                    //判断是right指针指向是否重复
                    while (left < right && num[right] == num[right - 1]) {
                        right--;
                    }
                    //移动指针
                    left++;
                    right--;
                } else if (tp_ans < 0) {
                    left++;
                } else {
                    right--;
                }
            }
        }
        return ans;
    }
}
  • 时间复杂度:O(n^2)。
  • 空间复杂度:O(1)。

思路2:哈希表

利用哈希表特性,对符合条件的三元组进行去重处理。


代码2

import java.util.*;

public class Solution {
    public ArrayList<ArrayList<Integer>> threeSum(int[] num) {
        //存放答案的集合
        ArrayList<ArrayList<Integer>> ans = new ArrayList<>();
        int len =  num.length;

        //排序O(nlogn)
        Arrays.sort(num);

        //哈希表去重
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < len; i++) {
            map.put(num[i], i);
        }

        //若干变量声明
        int L, M, R;
        for (int i = 0; i < len; i = map.get(L) + 1) {
            //指定L的值
            L = num[i];
            //注意里层循环从i+1开始
            for (int j = i + 1; j < len; j = map.get(M) + 1) {
                M = num[j];
                //注意一下,这里是个容易错的细节..
                R = -L - M;
                if (R < M) {
                    break;
                }
                if (map.get(R) != null && map.get(R) > j) {
                    //创建一个数组,并将满足条件的三元素放进去
                    ArrayList<Integer> list = new ArrayList<Integer>();
                    list.add(L);
                    list.add(M);
                    list.add(R);
                    //将最终的结果存入答案数组ans中
                    ans.add(list);
                    //ans.add(Arrays.asList(L,M,R)); 不知道为什么这种写法在牛客平台编译过不了
                }
            }
        }
        return ans;
    }
}

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

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

相关文章

React 第三方插件 —— Cron 表达式生成器(qnn-react-cron)

qnn-react-cron 可以看做 react-cron-antd 的升级版&#xff08;具体“渊源”可见文档&#xff09;&#xff0c;现有功能如下&#xff1a; &#x1f389; 全面支持 cron&#xff1a;秒、分、时、日、月、周、年 &#x1f389; 日及周条件互斥&#xff0c;自动改变响应值 &…

8年测试开发,写给1-3年功能测试的几点建议,满满硬货指导

从15年毕业到现在也从业八年了&#xff0c;普通本科毕业&#xff0c;现在一家互联网公司担任测试部门总监&#xff0c;摸爬打滚&#xff0c;坑坑洼洼也经历了不少。思绪很久决定还是写下这篇&#xff0c;希望对后进的小伙子少走一点弯路。 很多人把职场想得太美好&#xff0c;其…

学node写接口!!!

fs 可以读取文档 fs.readFild() 用于读取文件 第一个参数 路径 第二个参数 "utf8"(默认值) 第三个参数 函数 function(err , dataStr ){ 第一个参数是错误&#xff0c; 第二个参数是正确的可以拿到读取文件里面的值 } fs.writeFile() 用于创建文件添加内容 …

【LeetCode中等】1419.数青蛙

给你一个字符串 croakOfFrogs&#xff0c;它表示不同青蛙发出的蛙鸣声&#xff08;字符串 “croak” &#xff09;的组合。由于同一时间可以有多只青蛙呱呱作响&#xff0c;所以 croakOfFrogs 中会混合多个 “croak” 。 请你返回模拟字符串中所有蛙鸣所需不同青蛙的最少数目。…

如何根据参考文献查找原文及详细的文献信息

当我们已知参考文献想要查看下载原文以及相关信息时可以用下面的方法&#xff1a; 例如这篇参考文献&#xff1a;Alsamhi S H, Almalki F, Ma O, et al. Predictive estimation of optimal signal strength from drones over IoT frameworks in smart cities[J]. IEEE Transac…

FPGA实现SDI视频解码PCIE传输 提供工程源码和QT上位机源码加技术支持

目录 1、前言2、我已有的SDI编解码方案3、我已有的PCIE方案4、总体设计思路和方案SDI摄像头Gv8601a单端转差GTX解串SDI解码VGA时序恢复YUV转RGB图像缓存PCIE发送通路SDI同步输出通路 5、vivado工程详解6、驱动安装7、QT上位机软件8、上板调试验证SDI同步HDMI输出验证PCIE输出验…

neo4j结合gds实现最短路径算法

背景&#xff1a;Neo4j自带的cypher语句中的 shortestpath allShortestPaths 返回值内容非常有限&#xff0c;不易处理, 在实际生产环境中可用性极低&#xff0c; 且若带where条件查询时&#xff0c;查询效率极低 因此&#xff0c;使用Neo4j自带的插件如apoc来进行最短路径查询…

使用@Autowired、@Qualifier、@Primary注解自动装配组件

1.Autowired、Qualifier、Primary注解 1.1.Autowired注解 Autowired注解可以对类成员变量、方法和构造函数进行标注&#xff0c;完成自动装配的工作。 package org.springframework.beans.factory.annotation;import java.lang.annotation.Documented; import java.lang.ann…

hexo stellar主题添加运行时间-利用不蒜子

在网站的页脚想添加博客运行的时间以及&#xff0c;查了一下资料&#xff0c;根据下面的这个博主的代码进行了修改。 打造一个舒服的写作环境&#xff08;Hexo&#xff09; 下面我们开始修改&#xff1a; stellar/layout/_partial/main/footer.ejs 找到//footer的 这一段 // …

基于logback 实现springboot的日志配置

目录 一、前言 二、使用详解 2.1、打印到文件中 2.2、打印级别控制 2.3、logback 详细配置 2.4、logback 配置文件的组成 2.4.1、<root>标签 2.4.2、<contextName>标签 2.4.3、<property>标签 2.4.4、<appender>标签 2.4.5、<logger&g…

Mysql索引(2):索引结构

1 概述 MySQL的索引是在存储引擎层实现的&#xff0c;不同的存储引擎有不同的索引结构&#xff0c;主要包含以下几种&#xff1a; 索引结构描述BTree索最常见的索引类型&#xff0c;大部分引擎都支持 B 树索引 Hash索引 底层数据结构是用哈希表实现的, 只有精确匹配索引列的…

ShardingProxy分库分表实战

目录 ShardingProxy简述 快速使用 ShardingProxy部署 ShardingProxy使用 ShardingProxy的服务治理 Shardingproxy的其他功能 ShardingProxy的SPI扩展 ShardingSphere总结 ShardingProxy简述 ShardingProxy的功能同样是分库分表&#xff0c;但是他是一个独立部署的服务…

林曦讲座 | 关于“无用之美”的11个闪光

林曦老师的新书《无用之美》即将和大家见面啦~    究竟什么是“无用之美”呢&#xff1f;早在2013年&#xff0c;林曦老师就曾在“一席”做过一场关于“无用之美”的分享。2019年又在微软做过一次《中国人的闲情逸致——无用之美》的演讲。这次将两次演讲的内容精华整理出来…

【LeetCode】14. 最长公共前缀

1. 问题 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 “”。 示例 1 输入&#xff1a;strs [“flower”,“flow”,“flight”] 输出&#xff1a;“fl” 示例 2 输入&#xff1a;strs [“dog”,“racecar”,“car”] 输出…

虹科动态 | 2023成都国际工业博览会精彩瞬间回顾

2023成都国际工业博览会&#xff08;CDIIF&#xff09;于中国国际西部博览城圆满落下帷幕。本届成都工博会紧紧围绕“工业引领&#xff0c;赋能产业新发展”主题&#xff0c;聚焦工业自动化、数控机床与金属加工、机器人、新一代信息技术与应用、工业互联网、新材料、节能与工业…

在VMware上对于CentOS虚拟机的克隆

一. 执行克隆操作 对已有的虚拟机右键&#xff0c;找到克隆操作&#xff0c;选择完整克隆&#xff0c;之后修改一下虚拟机名称和位置&#xff0c;点击完成即可。 克隆之后还需要修改一些东西&#xff0c;以防止运行期间的 ip 浮动之类的问题。 二. 修改配置 先关闭原来的虚拟…

三菱GOT2000人机界面设置用户报警和系统报警弹出报警显示的具体方法

三菱GOT2000人机界面设置用户报警和系统报警弹出报警显示的具体方法 弹出报警显示功能可以将用户报警、系统报警直接显示再各窗口上起到提示作用,在不切换窗口的情况下直观的提示客户当前设备报警信息。 该功能可以实现将当前发生的用户和系统报警,显示在各个窗口的指定位置(…

Springboot整合Jasypt实战

Springboot整合Jasypt实战 引入依赖 <dependency><groupId>com.github.ulisesbocchio</groupId><artifactId>jasypt-spring-boot-starter</artifactId><version>3.0.5</version> </dependency>配置jasypt # 配置jasypt相关信息…

PowerShell系列(一):PowerShell介绍和cmd命令行的区别

目录 1、cmd命令行窗口有哪些缺点呢&#xff1f; 2、PowerShell的产生 3、PowerShell优点 4、PowerShell使用场景 什么是Windows系统的命令行环境&#xff0c;之前我们在使用XP、Win7系统的时候&#xff0c;用的最多的就是微软官方自带的cmd命令窗口了&#xff0c;我们通过敲命…

面向万物智联的应用框架的思考和探索(下)

原文&#xff1a;面向万物智联的应用框架的思考和探索&#xff08;下&#xff09;&#xff0c;点击链接查看更多技术内容。 应用框架&#xff0c;是操作系统连接开发者生态&#xff0c;实现用户体验的关键基础设施。其中&#xff0c;开发效率和运行体验是永恒的诉求&#xff0c…