Leetcode Array 15 3sum
思考的方向不对,即使用了多于别人几倍的时间,也不一定能够达到终点。
我的错误的想法(可以跳过):在leetcode上面做的第四道题,走路一个很大的弯路,收到之前做过的 Container With Most Water 的思路的影响,自己也想到了可以使用两个指针从左右遍历数组, 然而自己在这里走偏了,上来的第一个想法就是可以将整个解集合分为四种情况:全零,一正一负一零,两正一负,两负一正。这样整个程序就大致分为了四块,出现这种想法是由于我在第一层循环上面使用了两个指针向中间遍历,为内循环里面选择了一个指针分别根据四种情况来决定从哪边开始遍历。这时每种情况都需要控制相似的条件,而且需要控制的条件也比较多,这里就不在赘述了,将自己的代码贴一下,警醒一下自己。。(过了126组数据)
public class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> LL = new ArrayList<List<Integer>>();
        List<Integer> L = new ArrayList<Integer>();
        if(nums.length<3)
            return LL;
        //先对数组进行排序
        Arrays.sort(nums);
        //寻找数组中可能存在的零
        int index0 = 0;
        boolean bIndex = false;
        while(index0<nums.length){
            if(nums[index0] == 0){
                bIndex = true;
                break;
            }
            index0++;
        }
        //首位为0
        if(bIndex){
            int c = 0;
            int t0 = index0;
            while(t0<nums.length){
                if(nums[t0++] == 0)
                    c++;
                else
                    break;
            }
            if(c>=3){
                L.add(0);
                L.add(0);
                L.add(0);
                LL.add(L);
                L = new ArrayList<Integer>();
            }
        }
        int i=0,j=nums.length-1;
        //一正一负一零
        if(bIndex){
            while(i<index0 && j>index0){
                if(Math.abs(nums[i]) == Math.abs(nums[j])){
                    L.add(nums[i]);
                    L.add(0);
                    L.add(nums[j]);
                    LL.add(L);
                    L = new ArrayList<Integer>();
                    while(nums[i] == nums[i+1]){
                        i++;
                    }
                    while(nums[j] == nums[j-1]){
                        j--;
                    }
                    i++;j--;
                }
                else if(Math.abs(nums[i])>Math.abs(nums[j])){
                    i++;
                }
                else{
                    j--;
                }
            }
        }
        //两负一正
        i=0;j=nums.length-1;
        while(i<j && nums[i]*nums[j]<0){
            if(Math.abs(nums[i])>=Math.abs(nums[j])){ // 负数的绝对值大于正数的 不可能有两负一
                i++;
                continue;
            }
            //
            int k=i+1;
            for(;nums[k]<0;k++){  //这里还可以优化```
                if(-(nums[i]+nums[k]) < nums[j]){
                   j--;
                   break;
                }
                if(nums[i]+nums[k] == -nums[j]){
                    L.add(nums[i]);
                    L.add(nums[k]);
                    L.add(nums[j]);
                    LL.add(L);
                    L = new ArrayList<Integer>();
                       //去除重复
                    while(nums[i+1] == nums[i]){
                        i++;
                    }
                    if(nums[i] != nums[k])  //  -4 -4 8   -4 -1 5
                        i++;
                    break;
                }
            }
            if(nums[k]>=0){ //去除重复
                while(nums[j-1] == nums[j]){
                    j--;
                }
                j--;
            }
        }
        //两正一负
        i=0;j=nums.length-1;
        while(i<j && nums[i]*nums[j]<0){
            if(Math.abs(nums[i])<=Math.abs(nums[j])){ // 负数的绝对值大于正数的 不可能有两负一
                j--;
                continue;
            }
            int k = j-1;
            for(;nums[k]>0;k--){
                if(nums[k]+nums[j] < -nums[i]){
                    i++;
                    break;
                }
                if(nums[k]+nums[j] == -nums[i]){
                    L.add(nums[i]);
                    L.add(nums[k]);
                    L.add(nums[j]);
                    LL.add(L);
                    L = new ArrayList<Integer>();
                    while(nums[j] == nums[j-1])
                        j--;
                    if(nums[j] != nums[k])
                        j--;
                    break;
                }
            }
            if(nums[k]<=0){
                while(nums[i] == nums[i+1]){
                    i++;
                }
                i++;
            }
        }
        return LL;
    }
}
在看了别人的代码之后自己感觉恍然大悟,只要在外层循环从左到右遍历一遍(跳过重复的数据),然后内层循环按照 two sum的做法,将外循环遍历得到的值的相反数作为内循环的target就可以了,然后left,right分别遍历,所得到的值大于target就right--,否则left++ ,在++,--的过程中需要跳过重复值。代码如下:
public class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> LL = new ArrayList<List<Integer>>();
        int len = nums.length;
        if(len<3)
            return LL;
        Arrays.sort(nums);
        for(int i=0;i<len;i++){
            if(nums[i]>0)
                break;
            if(i>0&&nums[i] == nums[i-1])
                continue;
            int begin = i+1,end = len-1;
            while(begin<end){
                int sum = nums[i]+nums[begin]+nums[end];
                if(sum == 0){
                    List<Integer> L = new ArrayList<Integer>();
                    L.add(nums[i]);
                    L.add(nums[begin]);
                    L.add(nums[end]);
                    LL.add(L);
                    begin++;end--;
                    while(begin<end && nums[begin]==nums[begin-1])begin++;
                    while(begin<end && nums[end]==nums[end+1])end--;
                }
                else if(sum>0)
                    end--;
                else
                    begin++;
            }
        }
        return LL;
    }
}
下面的这种方法可以更好的理解:第一层循环作为target:
    public class Solution {
        List<List<Integer>> ret = new ArrayList<List<Integer>>();  
        public List<List<Integer>> threeSum(int[] num) {
            if (num == null || num.length < 3) return ret;  
            Arrays.sort(num);  
            int len = num.length;
            for (int i = 0; i < len-2; i++) {
                if (i > 0 && num[i] == num[i-1]) continue;
                find(num, i+1, len-1, num[i]); //寻找两个数与num[i]的和为0
            }  
            return ret;
        }  
        public void find(int[] num, int begin, int end, int target) {
            int l = begin, r = end;
            while (l < r) {
                if (num[l] + num[r] + target == 0) {
                    List<Integer> ans = new ArrayList<Integer>();
                    ans.add(target);
                    ans.add(num[l]);
                    ans.add(num[r]);
                    ret.add(ans); //放入结果集中
                    while (l < r && num[l] == num[l+1]) l++;
                    while (l < r && num[r] == num[r-1]) r--;
                    l++;
                    r--;
                } else if (num[l] + num[r] + target < 0) {
                    l++;
                } else {
                    r--;
                }
            }
        }
    }
注意,对于 num[i],寻找另外两个数时,只要从 i+1 开始找就可以了。
这种写法,可以避免结果集中有重复,因为数组时排好序的,所以当一个数被放到结果集中的时候,其后面和它相等的直接被跳过。
Leetcode Array 15 3sum的更多相关文章
- 【LeetCode】15. 3Sum 三数之和
		作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 个人公众号:负雪明烛 本文关键词:3sum, 三数之和,题解,leetcode, 力扣,P ... 
- LeetCode:15. 3Sum(Medium)
		1. 原题链接 https://leetcode.com/problems/3sum/description/ 2. 题目要求 数组S = nums[n]包含n个整数,请问S中是否存在a,b,c三个整 ... 
- 【一天一道LeetCode】#15 3Sum
		一天一道LeetCode系列 (一)题目 Given an array S of n integers, are there elements a, b, c in S such that a + b ... 
- 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 ... 
- 《LeetBook》leetcode题解(15):3Sum[M]
		我现在在做一个叫<leetbook>的免费开源书项目,力求提供最易懂的中文思路,目前把解题思路都同步更新到gitbook上了,需要的同学可以去看看 书的地址:https://hk029.g ... 
- Leetcode Array 16 3Sum Closest
		Given an array S of n integers, find three integers in S such that the sum is closest to a given num ... 
- 【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 ... 
- 【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 ... 
- [LeetCode]题15:3Sum
		第一次解: res = [] nums.sort() if len(nums)<3:return [] for i in range(len(nums)-2): left = i+1 right ... 
随机推荐
- 【VBA】全局常量定义
			[说明] 全局常量定义 Public Const RESULT_SHEET As String = "result" Public Const APPROVER_START_CEL ... 
- Python基础教程笔记  第一章
			/ 表示整除,当导入_future_模块中的version时,/ 表示正常的的除法, 此时可用//表示整除,不论数字是整型还是浮点型,都可以用//表示整除. ** 表示幂次方 例如 2**3 ... 
- 8个学习.net的博客链接 (以前收藏过更多的,被百度新版搞没了,恨死了)
			原文发布时间为:2012-09-18 -- 来源于本人的百度文章 [由搬家工具导入] Simone Chiaretta’s CodeClimber http://www.haacked.com/ ( ... 
- 用email实现邮件模板
			<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ... 
- SpringTest(一)
			SpringMvcTest总结: 最近要做单元测试,所以选择的是SpringTest这个测试框架. 1.准备工作.(导入jar包) 因为使用Maven管理jar包,所以在要做单元测试的模块中的p ... 
- selenium题
			一.selenium中如何判断元素是否存在? 首先selenium里面是没有这个方法的,判断元素存在需要自己写一个方法了. 元素存在有几种形式,一种是页面有多个元素属性重复的,这种直接操作会报错的:还 ... 
- 【转载】51CTO-Android设置模拟器屏幕大小
			在Eclipse Android中设置模拟器屏幕大小是本文要介绍的内容,主要是来了解并学习Eclipse Android中模拟器的设置,具体关于Eclipse Android内容的详解来看本文. ... 
- HDU 5135.Little Zu Chongzhi's Triangles-字符串 (2014ACM/ICPC亚洲区广州站-重现赛)
			Little Zu Chongzhi's Triangles Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 512000/512000 ... 
- Oracle 时间字符 转
			http://www.cnblogs.com/linximf/archive/2011/11/21/2257036.html oracle数据类型看起来非常简单,但用起来会发现有许多知识点,本文是我对 ... 
- Educational Codeforces Round 34 D. Almost Difference【模拟/stl-map/ long double】
			D. Almost Difference time limit per test 2 seconds memory limit per test 256 megabytes input standar ... 
