15.三个数之和
第一次用Markdown写博客,有点小激动,哈哈哈,GitHub一直是被用作代码备份仓库,也没有在上面创作,所以一直没有机会接触Markdown,但呗网上安利了Markdown是可以如何高效码字,就想自己体验一波,拥抱变化
1. 题目描述
题目链接
给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
2. 题目分析
从给定数组中找出所有三个数之和为0的不重复的三元组集合,这里有三个要求:
- 从给定数组中找出任意三个数之和为0.
- 是找出所有符合条件的三元组集合,不是只要找到一组即结束。是找出所有符合条件的三元组集合,不是只要找到一组即结束。
- 这些三元组不能重复,如[-1,1,0] 和 [0,-1,1]这其实是重复的三元组。
3. 解决思路
刷过剑指offer的题目的同学一定知道,从给定数组中如何找出两个数之和为定值的解决思路,即,首先将数组排序,然后使用两个指针left,right,分别从首尾遍历数组,if num[left]+num[right]<target,则left++; if num[left]+num[right] > target,则right–;直到 num[left]+num[right]==target,则跳出循环;
时间复杂度分析: 使用稳定高效的排序算法的时间复杂度为O(nlog2n) ,遍历查找的时间复杂度为O(n),则最终时间复杂度为O(nlog2n)。
那如何从两数之和的解决方法中找到解决三数之和问题的思路呢?方法很简单:既然要求三数之和,num[i]+num[j]+num[k] = target ,那么num[j]+num[k] = target -num[i],是不是就变成了求两数之和了呢?即,两层循环,第一层循环遍历i,第二层循环从数组中找num[j]和num[k]。
那如何控制三元组不重复呢?我使用的java变成语言,所以可以,直接使用set集合类来自动去重,其他语言我不了解有没有这个集合类,另外要是想要手动去重,我的想法是,需要每次去比较已经找到的三元组,但这样效率会很低,虽然使用set去重的底层实现也是这个原理。有没有其他高效的去重方法,我暂时没有想法,希望有思路的博友,可以不啬赐教。
4. 代码实现(java)
package com.algorithm.leetcode.string;
import java.util.*;
/**
* Created by 凌 on 2018/12/8.
* 描述:15.给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
*/
public class ThreeSum {
public static void main(String[] args) {
// int[] nums = {-1, 0, 1, 2, -1, -4};
// int[] nums = {};
// int[] nums = {0,0,0};
int[] nums = {-2,0,0,0,-2,-2,2,2,2};
// int[] nums = {-2,0,1,1,2};
List<List<Integer>> result =threeSum(nums);
for(List<Integer> list : result){
System.out.println(list.get(0)+"\t"+list.get(1)+"\t"+list.get(2));
}
}
public static List<List<Integer>> threeSum(int[] nums) {
if (nums == null || nums.length < 3){
return new ArrayList<List<Integer>>();
}
//使用set集合去重
Set<List<Integer>> result = new HashSet<>(nums.length-3);
List<Integer> list;
Arrays.sort(nums);
int sum = 0;
for (int i = 0; i < nums.length-2; i++) {
//去从,如果后面一位跟当前位相同,则直接跳过,虽然set可以自动去重,但可提高效率
if (i>0 && nums[i]==nums[i-1]){
continue;
}
sum = 0 - nums[i];
int low = i+1;
int high = nums.length-1;
while (low < nums.length-1 && low < high) {
list = new ArrayList<>(3);
if (nums[low] + nums[high] == sum){
list.add(nums[i]);
list.add(nums[low]);
list.add(nums[high]);
result.add(list);
low++;
high--;
}else if (nums[low] + nums[high]<sum ){
low++;
}else{
high--;
}
}
}
return new ArrayList<>(result);
}
}