我现在在做一个叫《leetbook》的免费开源书项目,力求提供最易懂的中文思路,目前把解题思路都同步更新到gitbook上了,需要的同学可以去看看
书的地址:https://hk029.gitbooks.io/leetbook/

015. 3Sum

问题

Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note:
Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
The solution set must not contain duplicate triplets.
For example, given array S = {-1 0 1 2 -1 -4},

A solution set is:
(-1, 0, 1)
(-1, -1, 2)

思路

这个问题其实就是2 SUM的变种问题,和这个问题类似的还有4SUM,解题思路也可以参考2SUM。我们知道2SUM还可以用暴力两重循环解决,3SUM如果暴力就要三重循环,想想也可怕。

考虑一下如何将3SUM问题转变一下:如果我们随机确定了一个数a,问题是不是就变成了,在剩下的数里面找到2个数和为0-a,是不是就和2SUM问题一样了?

其实这题相比2SUM多了几个难点:
1. 数组里允许重复的数
2. 结果要按升序排列
3. 结果中不能出现重复的结果

当然,我们可以通过写很多条判断语句解决这些问题,但是其实稍微想一下,可以发现,只要保证数组一开始就有序就好办很多了。

我们可以选择3个变量,left,mid,right。在循环的时候,永远保证相对顺序就行了。这样在插入结果的时候,就自然是升序的。

我们可以参考2SUM的思路2解决这道题。

首先,我们考虑如何确定第一个数left,这肯定是我们第一层循环。第一个数可不能无限制的随便选,因为我们要保证上面的几个条件都满足,我们要保证它时刻是最小的数,那么我们可以考虑left取到全部非正数就行了。(如果要和为0,至少要有1个非正数)

    for (int left = 0; left < nums.length && nums[left] <= 0; left++)

然后就是mid和right的确定了,我们采用思路2的方案,mid和right分别从两端往中央扫描,如果mid+right还比较小,那就需要mid右移,反之right左移

我们可以写出如下的代码:

 mid = left+1; right = nums.length-1;
while(mid < right)
{
int tmp = 0-nums[left];
if(nums[mid] + nums[right] == tmp)
addtolist;
else if(nums[mid] + nums[right] < tmp)
mid++;
else
right--;
}

一切看起来特别美好了,可以当你提交的时候,你会发现,还是会报错,因为它虽然能解决问题2,但是不能处理重复结果。举个最简单的例子:
-2 -2 -1 -1 0 1 1 2 2
这个代码会输出数个[-2 0 2] [-1 0 1] ,解决方案也很简单,如果一个left指向的数是之前判断过的,跳过,如果mid和right往中间移动的时候,是刚才的数,也跳过。

 mid = left+1; right = nums.length-1;
while(mid < right)
{
int tmp = 0-nums[left];
//跳过left重复匹配
if(left > 0 && nums[left] == nums[left-1])
continue; if(nums[mid] + nums[right] == tmp)
{
int tmp_mid = nums[mid],tmp_right= nums[right];
list.add(Arrays.asList(nums[left], nums[mid], nums[right]));
//跳过right和mid的重复匹配
while(mid < right && nums[++mid] == tmp_mid);
while(mid < right && nums[--right] == tmp_right);
}
else if(nums[mid] + nums[right] < tmp)
mid++;
else
right--;
}

代码

public class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> list;
list = new ArrayList<List<Integer>>();
int mid,right;
//left只用循环所有的非正数就行了(不是负数是因为还要考虑[0 0 0]的情况所以是非正数)
for (int left = 0; left < nums.length && nums[left] <= 0; left++) {
mid = left+1; right = nums.length-1;
int tmp = 0-nums[left];
//跳过left重复匹配
if(left > 0 && nums[left] == nums[left-1])
continue;
while(mid < right)
{
if(nums[mid] + nums[right] == tmp)
{
int tmp_mid = nums[mid],tmp_right= nums[right];
list.add(Arrays.asList(nums[left], nums[mid], nums[right]));
//跳过right和mid的重复匹配
while(mid < right && nums[++mid] == tmp_mid);
while(mid < right && nums[--right] == tmp_right);
}
else if(nums[mid] + nums[right] < tmp)
mid++;
else
right--;
}
}
return list;
}
}

《LeetBook》leetcode题解(15):3Sum[M]的更多相关文章

  1. 【LeetCode】15. 3Sum 三数之和

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 个人公众号:负雪明烛 本文关键词:3sum, 三数之和,题解,leetcode, 力扣,P ...

  2. LeetCode:15. 3Sum(Medium)

    1. 原题链接 https://leetcode.com/problems/3sum/description/ 2. 题目要求 数组S = nums[n]包含n个整数,请问S中是否存在a,b,c三个整 ...

  3. 《LeetBook》leetcode题解(16):3Sum Closest [M]

    我现在在做一个叫<leetbook>的免费开源书项目,力求提供最易懂的中文思路,目前把解题思路都同步更新到gitbook上了,需要的同学可以去看看 书的地址:https://hk029.g ...

  4. 【一天一道LeetCode】#15 3Sum

    一天一道LeetCode系列 (一)题目 Given an array S of n integers, are there elements a, b, c in S such that a + b ...

  5. LeetCode OJ 15. 3Sum

    题目 Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all ...

  6. Leetcode Array 15 3sum

      思考的方向不对,即使用了多于别人几倍的时间,也不一定能够达到终点. 我的错误的想法(可以跳过):在leetcode上面做的第四道题,走路一个很大的弯路,收到之前做过的 Container With ...

  7. 【LeetCode】15. 3Sum 三个数和为0

    题目: Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find al ...

  8. 【leetcode】15. 3Sum

    题目描述: Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find ...

  9. LeetCode题解 15题 第二篇

    之前写过一篇,这是第二篇.上一篇用了多种编程语言来做,这一次是以学算法为主,所以打算都用python来完成. 4. Median of Two Sorted Arrays There are two ...

随机推荐

  1. ROM初始化HEX文件

    intel hex格式 记录格式 Intel HEX由任意数量的十六进制记录组成.每个记录包含5个域,它们按以下格式排列: :llaaaatt[dd...]cc 每一组字母对应一个不同的域,每一个字母 ...

  2. timescale

    `timescale 1ns/100ps     表示时延单位为1ns, 时延精度为100ps.`timescale 编译器指令在模块说明外部出现, 并且影响后面所有的时延值.

  3. ubuntu 14.04查看java的安装路径

    有时候,使用apt-get install 安装了某个软件之后,却不知道这个软件的安装路径在哪里. 那怎么样去找出这个软件的安装路径呢? 下面我们java 这个软件为例, 找出ubuntu 14.04 ...

  4. 《SLAM for Dummies》中文版《SLAM初学者教程》

    SLAM for Dummies  SLAM初学者教程A Tutorial Approach to Simultaneous Localization and Mapping  一本关于实时定位及绘图 ...

  5. Spark RDD详解

    1.RDD是什么 RDD(Resilient Distributed Dataset):是Spark的核心数据结构,指的是一个只读的.可分区的分布式数据集,这个数据集的全部或部分可以缓存在内存中,在多 ...

  6. lock wait timeout exceeded; try restarting transactio解决方案

    问题原因:       今天线上环境,突然出现一个问题,追踪原因是数据库中的一条语句报错,错误内容:lock wait timeout exceeded; try restarting transac ...

  7. dubbo 源码编译记录

    DUBBO是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,是阿里巴巴SOA服务化治理方案的核心框架,阿里内部采用sofa框架,同属于分布式RPC框架,dubbo开源,而sofa ...

  8. 摘抄-----java codeReview要做的事

    整洁的代码 清单项目 分类 使用可以表达实际意图(Intention-Revealing)的名称 有意义的名称 每一个概念只用一个词 有意义的名称 使用方案/问题领域名称 有意义的名称 类应该是比较小 ...

  9. 基于jTopo的拓扑图设计工具库ujtopo

    绘制拓扑图有很多开源的工具,知乎上也有人回答了这个问题: https://www.zhihu.com/question/41026400/answer/118726253 ujtopo是基于jTopo ...

  10. dorado-SplitSpanel控件

    1.这是一个界面布局控件 2.分为SideControl边区域和MainControl主区域 3.常用属性 3.1 collapsed:打开页面时,边区域是否显示 3.2 position:边区域占总 ...