部分文章内容为公开资料查询整理,原文出处可能未标注,如有侵权,请联系我,谢谢。邮箱地址:gnivor@163.com ►►►需要气球么?请点击我吧!

LeetCode--15. 3Sum、4Sum

相关资料:http://tech-wonderland.net/blog/summary-of-ksum-problems.html

大意:给定一个数组,找到数组中的三个数,使得三个数的和为0。
注意  1. 要找到所有的这样的组合
    2. 每个组合内元素按照升序排列
    3. 不能有重复的组合
    4. 原始数组中可能有重复的元素

错误解法1: 想法:先将所有的数字两两求和,存为二维数组twosum[][],其中twosum[i][j] 存放的元素是nums[i]和nums[j]的和。 然后遍历一遍nums[],如果nums[k]和twosum[i][j]的和为0,那么就是满足条件的。但是这种想法是错误的!!!!!!

方法不能处理数组有两个数和相同元素的情况。

public static List<List<Integer>> threeSum(int[] nums) {
    Arrays.sort(nums);
    int len = nums.length;
    int[][] twosum = new int[len][len];
    for(int i = 0 ; i < len ; i++){ //先求出任意两个数的和
        for(int j = i+1 ; j < len ; j++){
            twosum[i][j] = nums[i]+nums[j];
        }
    }        
    
    for(int i = 0 ; i < len ; i++){
        for(int j = 0 ; j < len ; j++){
            System.out.print(twosum[i][j]+"\t");
        }
        System.out.println();
    }        
    
    HashSet set = new HashSet();
    for(int k = 0; k < len ; k++){
        int i = 0 , j = len-1;
        
        while(i<j){
            if(i==k) i++;
            else if(j==k) j--;
            else if(twosum[i][j]+nums[k]>0) j--;
            else if(twosum[i][j]+nums[k]<0) i++;
            else {
                int i1=i,j1=j , k1 = k;
                
                int t;
                if(i1>j1)        {t=i1;i1=j1;j1=t;}
                if(j1>k1)     {t=j1;j1=k1;k1=t;}
                if(i1>j1)     {t=i1;i1=j1;j1=t;}
                
                List<Integer> list = new ArrayList();
                list.add(nums[i1]);
                list.add(nums[j1]);
                list.add(nums[k1]);    
                set.add(list);
                break;
            }    
        }
    }
    System.out.println(set.size());
    List<List<Integer>> solu = new ArrayList<List<Integer>> (); 
    Iterator itr = set.iterator();
    while(itr.hasNext()){            
        solu.add((List)itr.next());
    }
    return solu;
}

 

思想:利用了编程之美2.12 快速寻找两个满足条件的数 http://www.cnblogs.com/gnivor/articles/4585152.html

1. 遍历每个数字,令这个数字为-target。
2. 在内层循环中,寻找两个数,使得和为target,这样,三个数的和就是0

正确解法1:(但是超时了)。 在上面的思想基础上,先对start end i 按从小到大排序,然后Hashset对重复的组合进行筛选。

public class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);
        int len = nums.length;
        int target ; //存放当前目标和
        int start ,end;
        int sum ;
        HashSet<List<Integer>> set = new HashSet<List<Integer>>();
        for(int i = 0 ; i < len ; i++){
            target =  - nums[i]; //只要令另外两个数和为target即可
            start = 0 ;
            end = len-1;
            
            while(start<end){
                if(start==i) { start++; continue;}
                if(end == i) { end-- ; continue; }
                sum = nums[start]+ nums[end];
                if(sum > target) end--;
                else if(sum < target) start++;
                else{
                    int i1,j1,k1;
                    
                    int t;
                    if(i>end) { i1 =start ;j1 = end ; k1=i;}
                    else if(i<start){ i1 = i; j1 = start ; k1 = end;}
                    else{ i1= start ; j1 = i ; k1 = end;}
                    
                    List<Integer> list = new ArrayList();
                    list.add(nums[i1]);
                    list.add(nums[j1]);
                    list.add(nums[k1]);    
                    set.add(list);
                    start++;
                }
                
            }
        }
        List<List<Integer>> solu = new ArrayList<List<Integer>> (); 
        Iterator<List<Integer>> itr = set.iterator();
        while(itr.hasNext()){            
            solu.add((List)itr.next());
        }
        return solu;
    }
}

 

正确解法: i始终为最小的下标,start为中间的下标,end为最大的下标。

详细的思路可以参考http://blog.csdn.net/li4951/article/details/8693212

这里怎样处理重复元素的方法是上面的代码所没想到的。可以参考。

public static List<List<Integer>> threeSum(int[] nums) {
    Arrays.sort(nums);
    int len = nums.length;
    int target ; //存放当前目标和
    int start  ,end; 
    int sum ;
    List<List<Integer>> solu = new ArrayList<List<Integer>> (); 
    for(int i = 0 ; i < len-2 ; i++){
        if(i!=0&&nums[i]==nums[i-1]) //如果前一个i和当前的i是一样的,直接处理下一个i就行了,否则会重复
            continue;
        target =  - nums[i]; //只要令另外两个数和为target即可            
        start = i+1; end = len -1 ;
        while(start<end){ 
            sum = nums[start]+ nums[end];
            if(sum > target) end--;
            else if(sum < target) start++;
            else{ 
                List<Integer> list = new ArrayList<Integer>();
                list.add(nums[i]);
                list.add(nums[start]);
                list.add(nums[end]);    
                solu.add(list);
                start++;
                end --;
                //如果下一个START元素和当前的相同,就没有必要再添加一遍了,直接跳过
                while(start < end && nums[start] == nums [start-1]){ 
                    start++;
                }
                //如果下一个end元素和当前的end相同,就没有必要在处理一遍,直接跳过
                while(start < end && nums[end] == nums[end+1]){ 
                    end--;
                }
            }            
        }
    }
    return solu;
}

 

 

4sum:思想和3sum类似,外部再添加一层循环即可

public static List<List<Integer>> fourSum(int[] nums, int target) {
    Arrays.sort(nums);
    int len = nums.length;
    int twotarg ; //存放当前目标和
    int start  ,end; 
    int sum ;
    List<List<Integer>> solu = new ArrayList<List<Integer>> (); 
    for(int m = 0 ; m < len-3 ; m++){
        if(m!=0&&nums[m]==nums[m-1]) //如果前一个m和当前的m是一样的,直接处理下一个i就行了,否则会重复
            continue;
    
        for(int i = m+1 ; i < len-2 ; i++){
            if(i!=m+1&&nums[i]==nums[i-1]) //如果前一个i和当前的i是一样的,直接处理下一个i就行了,否则会重复 (注意i的边界)
                continue;
            
            twotarg =  target -(nums[m]+ nums[i]); //只要令另外两个数和为twotarg即可            
            start = i+1; end = len -1 ;
            while(start<end){ 
                sum = nums[start]+ nums[end];
                if(sum > twotarg) end--;
                else if(sum < twotarg) start++;
                else{ 
                    List<Integer> list = new ArrayList<Integer>();
                    list.add(nums[m]);
                    list.add(nums[i]);
                    list.add(nums[start]);
                    list.add(nums[end]);    
                    solu.add(list);
                    start++;
                    end --;
                    //如果下一个START元素和当前的相同,就没有必要再添加一遍了,直接跳过
                    while(start < end && nums[start] == nums [start-1]){ 
                        start++;
                    }
                    //如果下一个end元素和当前的end相同,就没有必要在处理一遍,直接跳过
                    while(start < end && nums[end] == nums[end+1]){ 
                        end--;
                    }
                }
            }
        }
    }
    return solu;
}

 

posted @ 2015-07-15 22:22  流了个火  阅读(102)  评论(0)    收藏  举报
►►►需要气球么?请点击我吧!►►►
View My Stats