Problem: 15. 三数之和
题目描述
思路
我们将问题分解为两个待解决的问题:
1.如何实现不重复
2.如何更高效的实现输出和为0且不重复的三元组
1.如何实现不重复:
1.我们首先对数组进行一个排序,然后再实现三重循环。
2.在三重循环的大框架下,我们先利用第一层循环枚举a,在第二层循环中用来枚举b同时确保第二重循环枚举到的元素不小于当前第一层循环枚举的元素,同理第三层循环用来枚举c同时确保第三层循环枚举到的元素不小于第二层枚举到的元素
但我们应该注意:
**每一层循环中,相邻两次枚举的元素不能相同,否则也会造成重复!!!**例如:
[0, 1, 2 , 2, 2, 3]
当枚举出一个(0,1,2)后,第二层循环向后又会得到(0,1,2)
所以我们应该通过判断nums[i] 与 nums[i - 1]相等于否移动到于相邻元素第一个不相等的下标位置
如何更高效的实现输出和为0且不重复的三元组:
1.我们在实现第一层循环后立即选定当前的nums[first]的负数作为比较目标值(target)在开始第二层循环时我们定义third 指向数组的末尾,然后开始第三层循环运用双指针的思想保证second < third,对nums[second] + nums[third] 与target的大小进行比较,若nums[second] + nums[third] > target则表明third处的值大了,需要让已经排好序的数组中的third–
2.虽然我们是使用的三重循环的大框架,但是第二层和第三层时同时进行的,所以最后还是O(N^2)的复杂度
复杂度
时间复杂度:
O ( n 2 ) O(n^2) O(n2);其中 n n n为数组nums的大小
空间复杂度:
O ( 1 ) O(1) O(1)
Code
class Solution {
/**
* Sum of three numbers
*
* @param nums Given array
* @return List<List < Integer>>
*/
public List<List<Integer>> threeSum(int[] nums) {
int length = nums.length;
// Sort the array
Arrays.sort(nums);
List<List<Integer>> res = new ArrayList<>();
// Enumerate a
for (int first = 0; first < length; first++) {
//first cannot be repeated
if (first > 0 && nums[first] == nums[first - 1]) {
continue;
}
// Select a target
int target = -nums[first];
int third = length - 1;
// Enumerate b
for (int second = first + 1; second < length; second++) {
//second Cannot be repeated
if (second > first + 1 && nums[second] == nums[second - 1]) {
continue;
}
while (second < third && nums[second] + nums[third] > target) {
third--;
}
// Exit when equal
if (second == third) {
break;
}
// Add appropriate elements
if (nums[third] + nums[second] == target) {
List<Integer> temp = new ArrayList<>();
temp.add(nums[first]);
temp.add(nums[second]);
temp.add(nums[third]);
res.add(temp);
}
}
}
return res;
}
}