[LeetCode] 3Sum
2015-09-18 17:59
288 查看
sum3问题:
对于给定的一组int,找到其中的三个数,这三个数相加为0。比如:
输入:
int[] nums= {-1 0 1 2 -1 -4}
输出:
(-1, 0, 1)
(-1, -1, 2)
第一个思路,最简单明了的,三循环暴力求解。。。时间复杂度当然是不敢恭维。。。
如果我们先进行排序,然后前面两个数循环,第三个数去二分查找,就可以得到一个O(n2*logn)的算法。
考虑下加法的特征,我们还可以稍微简化一下。
三个数相加等于0,则第一个数必然小于0,最后一个数必然大于0。
所以,如果我们取头尾的数,然后在中间进行二分查找,则还存在三个数学性质,可以简化判断。
第一个数大于0
最后一个数小于0
中间数小于第一个数或者大于最后一个数。
这样可以在同阶的情况下,稍微减少点循环数。
反向思考,我们既然能先固定两头去查找中间的数,当然也能先固定中间的数,再去查找两头。尤其在计算了sum是否大于0后,我们可以确定遍历的方向。因此不需要漫无目的的遍历(0至i)*(i至length)了,而只需要遍历(0至length)即可。因此最后这个复杂度就下降到了i循环的O(n)以及查找low,high两者加一起的O(n)。时间复杂度为O(n2)。
对于2sum, 3sum closest, 4sum这三个问题,解题思路也都是一样的。
暴力查找最简单但复杂度最高。
利用排序,对最后一个数进行二分查找,可以把一个n降低到logn。
利用排序,对最后两个数进行加加减减的遍历,则可以由于方向的确定,把复杂度降低一个n阶。
最后附上一个4sum的代码实现:
对于给定的一组int,找到其中的三个数,这三个数相加为0。比如:
输入:
int[] nums= {-1 0 1 2 -1 -4}
输出:
(-1, 0, 1)
(-1, -1, 2)
第一个思路,最简单明了的,三循环暴力求解。。。时间复杂度当然是不敢恭维。。。
public List<List<Integer>> threeSum(int[] nums) { List<List<Integer>> list = new ArrayList<List<Integer>>(); int length = nums.length; for(int i =0; i < length -2; i++){ int a = nums[i]; for(int j = i+1; j <length-1 ; j++){ int b = nums[j]; for(int k = j+1; k< length; k++){ int c = nums[k]; if(a+b+c == 0){ ArrayList<Integer> item = new ArrayList<Integer>(); item.add(a); item.add(b); item.add(c); Collections.sort(item); if(!list.contains(item)){ list.add(item); } } } } } return list;
如果我们先进行排序,然后前面两个数循环,第三个数去二分查找,就可以得到一个O(n2*logn)的算法。
考虑下加法的特征,我们还可以稍微简化一下。
三个数相加等于0,则第一个数必然小于0,最后一个数必然大于0。
所以,如果我们取头尾的数,然后在中间进行二分查找,则还存在三个数学性质,可以简化判断。
第一个数大于0
最后一个数小于0
中间数小于第一个数或者大于最后一个数。
这样可以在同阶的情况下,稍微减少点循环数。
//先排序,复杂度O(nlogn) Arrays.sort(nums); int length = nums.length; List<List<Integer>> list = new ArrayList<List<Integer>>(); //两遍循环,进行查找。复杂度(n2*logn) for(int i=0; i<length; i++){ int a = nums[i]; //第一个数大于0 if(a > 0){ break; } for(int j=length-1; j>1;j--){ int c = nums[j]; //第三个数小于0 if(c < 0){ break; } int b = -(a+c); //中间的数最小或者最大了 if(b < a || b > c){ break; } if(contains(nums, b, i+1, j-1)){ ArrayList<Integer> item = new ArrayList<Integer>(); item.add(a); item.add(b); item.add(c); if(!list.contains(item)){ list.add(item); } } } } return list; //二分查找 public boolean contains(int[] nums, int a, int low, int high){ while(low <= high) { int middle = (low + high)/2; if(a == nums[middle]) { return true; }else if(a <nums[middle]) { high = middle - 1; }else { low = middle + 1; } } return false; }
反向思考,我们既然能先固定两头去查找中间的数,当然也能先固定中间的数,再去查找两头。尤其在计算了sum是否大于0后,我们可以确定遍历的方向。因此不需要漫无目的的遍历(0至i)*(i至length)了,而只需要遍历(0至length)即可。因此最后这个复杂度就下降到了i循环的O(n)以及查找low,high两者加一起的O(n)。时间复杂度为O(n2)。
//先排序,复杂度O(nlogn) Arrays.sort(nums); int length = nums.length; List<List<Integer>> list = new ArrayList<List<Integer>>(); //复杂度O(n2) int low,high,sum; for (int i = 1; i < length - 1; i++) { low = 0; high = length - 1; while (low < i && high > i) { sum = nums[i] + nums[low] + nums[high]; if (sum == 0) { ArrayList<Integer> item = new ArrayList<Integer>(); item.add(nums[low]); item.add(nums[i]); item.add(nums[high]); if (!list.contains(item)) { list.add(item); } high--; low++; } else if (sum > 0) { high--; } else { low++; } } } return list;
对于2sum, 3sum closest, 4sum这三个问题,解题思路也都是一样的。
暴力查找最简单但复杂度最高。
利用排序,对最后一个数进行二分查找,可以把一个n降低到logn。
利用排序,对最后两个数进行加加减减的遍历,则可以由于方向的确定,把复杂度降低一个n阶。
最后附上一个4sum的代码实现:
public class Solution { public List<List<Integer>> fourSum(int[] nums, int target) { int length = nums.length; List<List<Integer>> list = new ArrayList<List<Integer>>(); if(length < 4){ return list; } //排序 Arrays.sort(nums); for(int i=0;i <length-3;i++){ for(int j=i+1; j<length-2;j++){ //先双循环 int sum = nums[i]+nums[j]-target; int m =j+1; int n =length-1; while(m<n){ //回到2sum的思路,按照result>或<0,进行++-- int result =nums[m]+nums +sum; if(result==0){ ArrayList<Integer> item = new ArrayList<Integer>(); item.add(nums[i]); item.add(nums[j]); item.add(nums[m]); item.add(nums ); if(!list.contains(item)){ list.add(item); } m++; n--; }else if(result >0){ n--; }else{ m++; } } } } return list; } }
相关文章推荐
- leetcode 179 Largest Number
- leetcode 24 Swap Nodes in Pairs
- leetcode 2 Add Two Numbers 方法1
- leetcode 2 Add Two Numbers 方法2
- [LeetCode]47 Permutations II
- [LeetCode]65 Valid Number
- [LeetCode]123 Best Time to Buy and Sell Stock III
- [LeetCode] String Reorder Distance Apart
- [LeetCode] Sliding Window Maximum
- [LeetCode] Find the k-th Smallest Element in the Union of Two Sorted Arrays
- [LeetCode] Determine If Two Rectangles Overlap
- [LeetCode] A Distance Maximizing Problem
- leetcode_linearList
- leetcode_linearList02
- LeetCode[Day 1] Two Sum 题解
- LeetCode[Day 2] Median of Two Sorted Arrays 题解
- LeetCode[Day 3] Longest Substring Without... 题解
- LeetCode [Day 4] Add Two Numbers 题解
- LeetCode [Day 5] Longest Palindromic Substring 题解
- LeetCode [Day 6] ZigZag Conversion 题解