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()