我现在在做一个叫《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},

  1. A solution set is:
  2. (-1, 0, 1)
  3. (-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个非正数)

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

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

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

  1. mid = left+1; right = nums.length-1;
  2. while(mid < right)
  3. {
  4. int tmp = 0-nums[left];
  5. if(nums[mid] + nums[right] == tmp)
  6. addtolist;
  7. else if(nums[mid] + nums[right] < tmp)
  8. mid++;
  9. else
  10. right--;
  11. }

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

  1. mid = left+1; right = nums.length-1;
  2. while(mid < right)
  3. {
  4. int tmp = 0-nums[left];
  5. //跳过left重复匹配
  6. if(left > 0 && nums[left] == nums[left-1])
  7. continue;
  8. if(nums[mid] + nums[right] == tmp)
  9. {
  10. int tmp_mid = nums[mid],tmp_right= nums[right];
  11. list.add(Arrays.asList(nums[left], nums[mid], nums[right]));
  12. //跳过right和mid的重复匹配
  13. while(mid < right && nums[++mid] == tmp_mid);
  14. while(mid < right && nums[--right] == tmp_right);
  15. }
  16. else if(nums[mid] + nums[right] < tmp)
  17. mid++;
  18. else
  19. right--;
  20. }

代码

  1. public class Solution {
  2. public List<List<Integer>> threeSum(int[] nums) {
  3. Arrays.sort(nums);
  4. List<List<Integer>> list;
  5. list = new ArrayList<List<Integer>>();
  6. int mid,right;
  7. //left只用循环所有的非正数就行了(不是负数是因为还要考虑[0 0 0]的情况所以是非正数)
  8. for (int left = 0; left < nums.length && nums[left] <= 0; left++) {
  9. mid = left+1; right = nums.length-1;
  10. int tmp = 0-nums[left];
  11. //跳过left重复匹配
  12. if(left > 0 && nums[left] == nums[left-1])
  13. continue;
  14. while(mid < right)
  15. {
  16. if(nums[mid] + nums[right] == tmp)
  17. {
  18. int tmp_mid = nums[mid],tmp_right= nums[right];
  19. list.add(Arrays.asList(nums[left], nums[mid], nums[right]));
  20. //跳过right和mid的重复匹配
  21. while(mid < right && nums[++mid] == tmp_mid);
  22. while(mid < right && nums[--right] == tmp_right);
  23. }
  24. else if(nums[mid] + nums[right] < tmp)
  25. mid++;
  26. else
  27. right--;
  28. }
  29. }
  30. return list;
  31. }
  32. }

《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. MyEclipse2014中Java类右键Run as没有JUnit Test

    Java初学,想试试连接本地数据库,按照百度经验中的方法,在最后执行测试的卡住了,为啥?因为MyEclipse中右键Run as没有JUnit Test选项! 6.1.测试数据库mysql是在项目中连 ...

  2. iOS 5 故事板进阶(2)

    让我们回到游戏排行窗口Ranking.创建一个 UITableViewController子类,命名为 RankingViewController. 编辑 RankingViewController. ...

  3. Citrus Engine简单Demo

    Citrus Engine是一个的开源flash平台(platform,也可以说是卷轴类)游戏引擎,它基于Starling Framework添加了各种物理引擎,3D引擎,动画引擎. Citrus实现 ...

  4. 关于单例的DCL方式分析

    public class Singleton { /** * 单例对象实例 */ private volatile static Singleton instance = null; public s ...

  5. WinRT 中后台任务类的声明

    要实现后台任务,需要实现IBackgroundTask接口 public sealed class SimpleTask : IBackgroundTask { public void Run(IBa ...

  6. 执行Docker命令报错解决办法

    shim error: docker-runc not installed on system   服务器重启以后,执行docker命令报以上错误,解决办法如下: cd /usr/libexec/do ...

  7. LeetCode145:Binary Tree Postorder Traversal

    题目: Given a binary tree, return the postorder traversal of its nodes' values. For example: Given bin ...

  8. JS和C#访问遇到QueryInterface调用出错

    在原来的WinForm里,我们只要在窗体类的头部添加属性[System.Runtime.InteropServices.ComVisibleAttribute(true)],然后 webBrowser ...

  9. net生成图片验证码--转自Lisliefor

    目前,机器识别验证码已经相当强大了,比较常见的避免被机器识别的方法,就是将验证码的字符串连到一起,这样就加大的识别的难度,毕竟机器没有人工智能.我找了很多的.net生成图片验证码的例子,后来经过一些修 ...

  10. C# 获取每一个像素点的RGB

    int x, y; x = e.X; y = e.Y; Color pixel = MyImage.GetPixel(x, y); byte R = pixel.R; byte G = pixel.G ...