LeetCode0015-三数之和
题目:
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
分析(排序+双指针):
题目中要求找到所有不重复且和为0 的三元组,这个不重复的要求使得无法简单地使用三重循环枚举所有可能的三元组。这是因为在最坏的情况下,数组中的元素全部为0。
[0, 0, 0, 0, 0, ..., 0, 0, 0]
任意一个三元组的和都是0,如果直接使用三重循环枚举三元组,会得到O(N^3)个满足题目要求的三元组(N是数组的长度),时间复杂度至少为O(N ^3)。在这之后,还需要使用哈希表进行去重操作,得到不包含重复三元组的最终答案,有消耗了大量的空间,这种做法的时间复杂度和空间复杂度都很高。
采用排序+双指针的方法,通过一遍遍历确定第一个元素a,然后在求另外的俩个元素b+c=-1,类似有确定目标值的俩数之和,从而降低时间复杂度。
代码:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 0015-三数之和
* 给你一个包含 n个整数的数组 nums,判断nums 中是否存在三个元素 a,b,c,使得a+b+c=0?
* 请你找出所有满足条件且不重复的三元组。
* 注意:
* 答案中不可以包含重复的三元组
* <p>
* 示例:
* 给定数组 nums = [-1, 0, 1, 2, -1, -4],
* 满足要求的三元组集合为:
* [
* [-1, 0, 1],
* [-1, -1, 2]
* ]
*/
/**
* 排序+双指针
*/
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
// 数组的长度
int n = nums.length;
// 将数组排序
Arrays.sort(nums);
// 保存结果集
List<List<Integer>> result = new ArrayList<List<Integer>>();
// 枚举a
for (int first = 0; first < n; ++first) {
// 需要和上一次的枚举数不同
if (first > 0 && nums[first] == nums[first - 1]) {
continue;
}
// c 对应的指针初始指向数组的最右端
int third = n - 1;
int target = -nums[first];
for (int second = first + 1; second < n; ++second) {
//需要和上一次枚举的数不相同
if (second > first + 1 && nums[second] == nums[second - 1]) {
continue;
}
// 需要保证 b 的指针在 c 的指针的左侧
// 类似俩数之和问题
while (second < third && nums[second] + nums[third] > target) {
--third;
}
// 如果指针重合,随着 b 后续的增加
// 就不会有满足 a+b+c=0 并且 b<c 的 c 了,可以退出循环
if (second == third) {
break;
}
if (nums[second] + nums[third] == target) {
List<Integer> list = new ArrayList<Integer>();
list.add(nums[first]);
list.add(nums[second]);
list.add(nums[third]);
result.add(list);
}
}
}
return result;
}
}
/**
* 测试类
*/
public class Study0015 {
public static void main(String[] args) {
List<List<Integer>> result = new Solution().threeSum(new int[]{-1, 0, 1, 2, -1, -4});
for (List<Integer> list : result) {
for (Integer integer : list) {
System.out.print(integer + "\t");
}
System.out.println();
}
}
}