题目要求:
分析:
这道题目最烦的一点就是要不断地进行优化。我最初写好的雏形代码是超出时间限制的,所以优化的过程也是一点一点来的。
OK,先不说优化的问题,先说一说拿到这道题目我是如何思考的。
- 由于我们想要找到三数之和为0的三个数,并且放在集合中,脑海里首先就应该要想到:
(1) 将nums数组进行排序,并设置left和right两个指针,分别先指向头跟尾,往中间夹击;
(2) 结果要要放在一个集合中,并且这个集合中还有一个一个的小集合,所以需要定义两个集合:大集合用来存放所有小集合,小集合存放加起来等于0的三个数; - 有了1中的思路之后,代码雏形就出来了:
(1) 我们对排序后的nums数组进行遍历,让nums[i]作为三个数中的一个;
(2) 令left指向nums[i + 1](left的值为i + 1,指向的数字是nums[i + 1],后同),right指向排过序之后的nums数组的最后一个数字nums[length - 1];
(3) 将这三个数进行相加,判断它们的和是否为0: - 如果为0,则添加到小集合中,并将这个小集合添加到大集合中;
- 如果大于0,则将right --;
- 如果小于0,则将left ++.
至此,代码的雏形就完成了,接下来我们要做的事情是对这个雏形代码进行优化。
我们可以从以下几个方面来对代码进行优化:
(1) 当nums的长度小于3时,直接不用判断了,返回一个空的集合list即可;
(2) 如果一个数与前面的数是相同的,如nums = [-3, -2, -2, 2, 3, 5]中,走到nums[2]时,发现nums[2]与nums[1]相等,就直接忽略它,将i++;
(3) 同样的,在判断left和right进行移动的时候,也像3中那样去判断;
(4) 如果说第一个数字就大于0,那么就没有找下去的必要了。
好了,经过这些分析,我们最终的代码如下所示:
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> list = new ArrayList<>();
Arrays.sort(nums);
List<Integer> list2 = null;
if(nums.length < 3)
return list;
for(int i = 0; i < nums.length; i++) {
if(i > 0 && nums[i] == nums[i-1])
continue;
if(nums[i] > 0) {
break;
}
int left = i + 1, right = nums.length - 1;
while(left < right) {
int t = nums[left] + nums[right] + nums[i];
if(t == 0) {
list2 = new ArrayList<Integer>();
list2.add(nums[i]);
list2.add(nums[left]);
list2.add(nums[right]);
list.add(list2);
while(left < right && nums[right] == nums[right - 1])
right --;
while(left < right && nums[left] == nums[left + 1])
left ++;
}
if(t > 0) {
right --;
} else {
left ++;
}
}
}
return list;
}
}