15.三个数之和

本文详细解析了经典的三数之和算法问题,探讨了如何从给定数组中找出所有三个数之和为0的不重复三元组,介绍了通过排序和双指针技巧解决该问题的方法,并提供了Java代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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的不重复的三元组集合,这里有三个要求:

  1. 从给定数组中找出任意三个数之和为0.
  2. 是找出所有符合条件的三元组集合,不是只要找到一组即结束。是找出所有符合条件的三元组集合,不是只要找到一组即结束。
  3. 这些三元组不能重复,如[-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);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值