问题描述

问题分析
分析题目,使用3个变量i、j、k暴力求解显然是不太现实的,想都不用想肯定超时。思考一番后,觉得可以改为a+b=-c,即固定一个数,移动另外两个数,这样将时间复杂度降到O(n^2)。并且,可以使用对撞指针提高性能。此题难点在去除重复的三元组,考虑了半天,最后还是老老实实用指针来去除重复三元组。
算法思路如下:
- 先对数组进行排序。数组被分为小于0、等于0、大于0三部分。
- 首先外层使用一层循环,first指针从左往右(从小到大)扫描,一直到0为止(包含0)。扫描过程中,first指针不动,对于first指针右边的剩余数组采用对撞指针的形式,i、j分别表示剩下的两个数的指针。
- 显然,若nums[i] + nums[j] + nums[first] == 0,则表示找到一个解。若nums[i] + nums[j] + nums[first] > 0,则表示i和j所指元素的和太大了,则让j–,这样两者的和就变小了。反之,i++,使两者的和变大。
- 经过如上步骤,可以找到所有解。但是其中有很多重复解。重复解的造成主要是因为数组中有很多重复数字,对于这种情况,我的解决方法是:通过指针解决,即,每次移动指针时,不是仅仅i++就够了,而是遇到重复数字继续++,直到遇到不相同的数字为止。
解法:对撞指针
- 时间复杂度:O( n2 ),其中n表示数组的长度。
Java代码
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> results = new ArrayList<>();
Arrays.sort(nums);
for (int first = 0; (nums.length >= 3) && (nums[first] <= 0) && (first < nums.length-2); first++) {
//与前一个first所对的数字不重复
if (!(first > 0 && nums[first] == nums[first-1])){
int i = first + 1;
int j = nums.length - 1;
while (i < j){
if (nums[i] + nums[j] + nums[first] == 0){
List<Integer> result = new ArrayList<>();
result.add(nums[first]);
result.add(nums[i]);
result.add(nums[j]);
results.add(result);
//去重(与前一个i或者j所对的数字不重复)
do {
i++;
}while (i > 0 && i < j && nums[i] == nums[i-1]);
do {
j--;
}while (j < nums.length-1 && i < j && nums[j] == nums[j+1]);
} else if (nums[i] + nums[j] + nums[first] > 0){
do {
j--;
}while (j < nums.length-1 && i < j && nums[j] == nums[j+1]);
} else {
do {
i++;
}while (i > 0 && i < j && nums[i] == nums[i-1]);
}
}
}
}
return results;
}
}
结果分析
以上代码的执行结果:
| 执行时间 | 内存消耗 |
|---|---|
| 106ms | 56.7MB |


1万+

被折叠的 条评论
为什么被折叠?



