leetcode:15.三数之和

简介: 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。

题目描述:


给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。


注意:答案中不可以包含重复的三元组。


示例:


例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
  [-1, 0, 1],
  [-1, -1, 2]
]


题目难度:中等


分析:

比较经典的一道题。题目要求在一个数组中找到3个数,使得三数相加等于0,并且这三数一体不重复。比较好抽象为排列组合问题,找出所有的3数组合,去除重复,然后判断相加是否等于0,或者先判断是否等于0,把所有等于0的组合放在一起再去除重复,但是问题难就难在,怎么去重这个步骤。


较简单的方法就是通过Set集合去重,但是要注意[1, 2, 3] 和 [1, 3, 2] 并不算重复,必须连顺序也一样才算重复。这里可以对数组排序,然后按照顺序去执行逻辑,那么就不需要考虑重复了。


排序后的思路:首先从下标0开始,选取一个基准,然后对右边的数组进行操作,分别用两个指针一前一后,这样再加上一个基准,就是3个指针,判断这三个数相加是否等于0,是的话就放入Set中,要按顺序放,[基准,左指针,右指针] 这样就可以达到去重的目的。


代码如下:


class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
      // 定义一个Set集合用来存放结果集,去重
        Set<List<Integer>> set = new HashSet();
        // 用来判断基准是否重复,很明显如果基准重复了,那么即使相加等于0,也是重复的数据
        Set<Integer> set1 = new HashSet();
        // 如果数组为空,直接返回一个空集合
        if(nums.length == 0) return new ArrayList<>(set);
        // 对数组进行排序,简化去重操作
        Arrays.sort(nums);
        // 因为基准数只和右边的数进行逻辑处理,所以循环到倒数第三个就可以了
        for(int i = 0; i < nums.length-2; i++){
          // 每个基准判断一次即可(测试用例里有个很恶心的数组,全部都是0,不判断的话会超时)
          if(!set1.add(nums[i])) continue;
          // 左指针从i的下一位开始
            int j = i + 1;
            // 右指针从数组最后一位开始
            int k = nums.length - 1;
            // 判断循环结束的条件就是左 < 右
            while(j < k){
              // 三数相加的临时变量
                int sum = nums[i] + nums[j] + nums[k];
                /*
                * 算法核心:如果sum > 0,那么说明这三个数偏大,而基准是不能动的,
                * 就左右指针来看,左指针右移数值会更大,右指针左移数值才会变小,
                * 通过不断的移动指针就可以最终找到我们想要的结果,
                * 这题和前面一道 盛水最多的容器 道理一样
        */
                if(sum > 0){
                    k--;
                }else if(sum < 0){
                    j++;
                }else{
                  // 如果正好等于0,那么把数值加入Set集合,并同时移动左右指针
                    set.add(Arrays.asList(nums[i], nums[j++], nums[k--]));
                }
            }
        }
        return new ArrayList<>(set);
    }
}


总结:


时间复杂度为O ( n 2 ) ,需要双层循环,效率一般,但是毕竟好理解,代码量也不多,就应该先从解决问题着手,然后再考虑优化,先不管三七二十一,通过所有测试用例,排名靠前的代码,一般都没有注释,思路比较奇特。(毕竟是大佬,想法比较难琢磨)。再一次用到了双指针算法,可见这个套路能解决很多问题。

目录
相关文章
|
传感器 自动驾驶 算法
JAVA实战演练之自动驾驶系统
JAVA实战演练之自动驾驶系统
|
消息中间件 算法 Java
弥补延时消息的不足,RocketMQ 基于时间轮算法实现了定时消息!
弥补延时消息的不足,RocketMQ 基于时间轮算法实现了定时消息!
1067 1
弥补延时消息的不足,RocketMQ 基于时间轮算法实现了定时消息!
|
9月前
|
存储 弹性计算 人工智能
阿里云发票申请图文教程及常见问题解析
在购买完阿里云服务器或者其他云产品之后,如何申请发票成为了许多用户关注的焦点。尤其是对于初次购买阿里云服务器的用户来说,发票申请流程可能并不熟悉。本文将为大家详细介绍阿里云服务器购买之后如何申请发票,以及申请过程中可能遇到的常见问题,帮助大家轻松完成发票申请。
|
人工智能 自然语言处理 搜索推荐
AIGC: 2 语音转换新纪元-Whisper技术在全球客服领域的创新运用
全球客服领域的发展设想结合点: 1.智能客服语音助手: 2.多语言无缝服务体验: 3.语音分析与情感智能
1402 2
|
前端开发 安全 Java
一文弄懂spring validate(上)
一文弄懂spring validate(上)
1397 0
|
定位技术 Python
Python根据经纬度在地图上显示(folium)
Python根据经纬度在地图上显示(folium)
744 0
Python根据经纬度在地图上显示(folium)
|
程序员 数据库
如何快速画出一副漂亮的架构图
为什么要画好一幅架构图?一幅漂亮的架构图既是创作者的深度结构化思考和表达,对于读者来说也更加容易理解架构所要表达的意思。
30749 16
|
JSON 数据格式
Node convert pdf to json
Node convert pdf to json
318 0
|
编解码 Android开发
分享快手极速版助手APK和源代码
分享快手极速版助手APK和源代码
1144 0
|
分布式计算 资源调度 Java
MapReduce入门(一篇就够了)(下)
MapReduce入门(一篇就够了)(下)
861 0