Question:

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: 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]
]
初级代码:
public List<List<Integer>> threeSum(int[] nums) {

        List<List<Integer>> res = new LinkedList<List<Integer>>();
        int len = nums.length;
        Arrays.sort(nums);
        if (len < 3 || nums[0] > 0)
            return res;

        for (int i = 0; i < len - 2; i++) {
            for (int j = i + 1; j < len - 1; j++) {
                for (int k = j + 1; k < len; k++) {
                    if (nums[i] + nums[j] + nums[k] == 0) {
                        List<Integer> nu = new LinkedList<Integer>();
                        nu.add(nums[i]);
                        nu.add(nums[j]);
                        nu.add(nums[k]);
                        res.add(nu);
                    }
                }
            }

        }

        // 去重

        for (int i = 0; i < res.size() - 1; i++) {
            for (int j = i + 1; j < res.size(); j++) {
                if (res.get(i).equals(res.get(j))) {
                    res.remove(j);
                    j--;
                }
            }

        }

        System.out.println(res.size());
        System.out.println(res);
        return res;

    }

这段代码可以在编译器运行通过,但是无法通过LeetCode的样例,

[-13,5,13,12,-2,-11,-1,12,-3,0,-3,-7,-7,-5,-3,-15,-2,14,14,13,6,-11,-11,5,-15,-14,5,-5,-2,0,3,-8,-10,-7,11,-5,-10,-5,-7,-6,2,5,3,2,7,7,3,-10,-2,2,-12,-11,-1,14,10,-9,-15,-8,-7,-9,7,3,-2,5,11,-13,-15,8,-3,-7,-12,7,5,-2,-6,-3,-10,4,2,-5,14,-3,-1,-10,-3,-14,-4,-3,-7,-4,3,8,14,9,-2,10,11,-10,-4,-15,-9,-1,-1,3,4,1,8,1]

出错原因是:超时 

目前代码时间复杂度较高为O(N*N*N),遇到这种较大的样例出现超时现象,需要改进搜索算法。

改进思路:固定第一个数字,另外两个数字从两头一起进行搜索,类似于指针移动。

第一次改进代码:

 

 1 public List<List<Integer>> threeSum(int[] nums) {
 2 
 3         List<List<Integer>> res = new LinkedList<List<Integer>>();
 4         int len = nums.length;
 5         Arrays.sort(nums);
 6         if (len < 3 || nums[0] > 0)
 7             return res;
 8           for (int i = 0; i < len - 2; i++) {
 9                 if (i > 0 && nums[i] == nums[i - 1])//去重的作用
10                     continue;
11                 int low = i + 1;
12                 int high = len - 1;
13                 while (low < high) {
14                     int begin = nums[low];
15                     int end = nums[high];
16                     int sum = nums[i] + begin + end;
17 
18                     if (sum == 0) {
19                         //res.add(Arrays.asList(nums[i], nums[low], nums[high]));
20                         List<Integer> nu = new LinkedList<Integer>();
21                         nu.add(nums[i]);
22                         nu.add(nums[low]);
23                         nu.add(nums[high]);
24                         res.add(nu);
25                         low++;
26                         high--;
27                          
28 
29                     } else if (sum > 0) {
30                         high--;
31                     } else {
32                         low++;
33                     }
34                 }
35 
36             }
37 
38         // 去重
39 
40         for (int i = 0; i < res.size() - 1; i++) {
41             for (int j = i + 1; j < res.size(); j++) {
42                 if (res.get(i).equals(res.get(j))) {
43                     res.remove(j);
44                     j--;
45                 }
46             }
47 
48         }
49 
50         System.out.println(res.size());
51         System.out.println(res);
52         return res;
53 
54     }

 

经过改进,过的样例更多了,但是还是被一个样例拦下来:

 

出错样例:
②去重的代码为O(N*N)也比较大,可以改进
第二次改进代码:
List<List<Integer>> res = new LinkedList<List<Integer>>();
        int len = nums.length;
        Arrays.sort(nums);
        if (len < 3 || nums[0] > 0)
            return res;

        for (int i = 0; i < len - 2; i++) {
            if (i > 0 && nums[i] == nums[i - 1])// 去重的作用
                continue;
            int low = i + 1;
            int high = len - 1;
            while (low < high) {
                int begin = nums[low];
                int end = nums[high];
                int sum = nums[i] + begin + end;

                if (sum == 0) {
                    res.add(Arrays.asList(nums[i], nums[low], nums[high]));
                    low++;
                    high--;

                } else if (sum > 0) {
                    high--;
                } else {
                    low++;
                }
            }

        }

        // 去重

        for (int i = res.size() - 1; i > 0; i--) {
            if (res.get(i).equals(res.get(i - 1))) {
                res.remove(i - 1);
            }
        }

        System.out.println(res.size());
        System.out.println(res);
        return res;

同样的还是复杂度太高,还是上面那个可恶的样例,太长了,哼!

第三次改进代码:

改进思路:

将去重的代码去掉,在搜索的过程中就排除出现重复的可能

package medium;

import java.util.List;
import java.util.Arrays;
import java.util.LinkedList;

public class L15 {
 
    public List<List<Integer>> threeSum(int[] nums) {

        List<List<Integer>> res = new LinkedList<List<Integer>>();
        int len = nums.length;
        Arrays.sort(nums);
        if (len < 3 || nums[0] > 0)
            return res;
        for (int i = 0; i < len - 2; i++) {
            if (i > 0 && nums[i] == nums[i - 1])//去重的作用
                continue;
            int low = i + 1;
            int high = len - 1;
            while (low < high) {
                int begin = nums[low];
                int end = nums[high];
                int sum = nums[i] + begin + end;

                if (sum == 0) {
                    res.add(Arrays.asList(nums[i], nums[low], nums[high]));
                    low++;
                    high--;
                     while(low<high&&nums[low]==nums[low-1])low++;
 while(low<high&&nums[high]==nums[high+1])high--;

                } else if (sum > 0) {
                    high--;
                } else {
                    low++;
                }
            }

        }
        System.out.println(res.size());
        System.out.println(res);
        return res;

    }

    public static void main(String[] args) {
        int[] nums = { 1, -1, -1, 0 };
        L15 l15 = new L15();
        l15.threeSum(nums);
    }
}
最终精简代码:
 1 public class Solution {
 2     public List<List<Integer>> threeSum(int[] nums) {
 3      List<List<Integer>> res = new LinkedList<List<Integer>>();
 4         int len = nums.length;
 5         Arrays.sort(nums);
 6         for (int i = 0; i < len - 2; i++) {
 7             if (i > 0 && nums[i] == nums[i - 1])// 去重的作用
 8                 continue;
 9             int low = i + 1;
10             int high = len - 1;
11             while (low < high) {
12                 int begin = nums[low];
13                 int end = nums[high];
14                 int sum = nums[i] + begin + end;
15 
16                 if (sum == 0) {
17                     res.add(Arrays.asList(nums[i], nums[low], nums[high]));
18                     low++;
19                     high--;
20                     while (low < high && nums[low] == nums[low - 1])
21                         low++;
22                     while (low < high && nums[high] == nums[high + 1])
23                         high--;
24                 } else if (sum > 0) {
25                     high--;
26                 } else {
27                     low++;
28                 }
29             }
30 
31         }
32         return res;
33     }
34 }

注:

①:Arrays.sort(nums);可以直接对int类型的数组进行排序

//import java.util.Arrays;

注意Arrays是util包里面的,这个类包含了各种方法来操作数组(比如排序和搜索)。

②List是util包里面的, 接口List
其上级接口 Collection
已知实现类:ArrayList,LinkedList,Stack,Vector,AbstractList,AbstractSequentialList,  CopyOnWriteArrayList
public interface List extends Collection
有序的Collection。此接口的用户可以对列表中的每个元素的插入位置进行精确的控制。用户可以根据元素的整数索引访问元素,并搜索列表中的元素。

③awt包里面也有List,在awt中Java.awt.List是一个滚动列表组件,List是一个文本项列表。该列表可以被​​配置给该用户可以选择一个或多个项目。

以下是的声明类java.awt.List:
public class List
   extends Component
      implements ItemSelectable, Accessible
④:List<List<Integer>> res = new LinkedList<List<Integer>>();
res.add(Arrays.asList(nums[i], nums[low], nums[high]));
可以直接给List<List<Integer>> res加入一个List<Integer>,而不用先将三个数字加入到List<Integer>,再将List<Integer>加到List<List<Integer>>中。
⑤去重部分,虽然最后没用到,但是还是需要记住
res.get(i)可以获取到List<List<Integer>>的第i个元素,即List<Integer>类型的元素。
比较List<Integer>类对象,需要用.equal()

相关文章: