【LeetCode热题100】打卡第8天:三数之和

三数之和

⛅前言

大家好,我是知识汲取者,欢迎来到我的LeetCode热题100刷题专栏!

精选 100 道力扣(LeetCode)上最热门的题目,适合初识算法与数据结构的新手和想要在短时间内高效提升的人,熟练掌握这 100 道题,你就已经具备了在代码世界通行的基本能力。在此专栏中,我们将会涵盖各种类型的算法题目,包括但不限于数组、链表、树、字典树、图、排序、搜索、动态规划等等,并会提供详细的解题思路以及Java代码实现。如果你也想刷题,不断提升自己,就请加入我们吧!QQ群号:827302436。我们共同监督打卡,一起学习,一起进步。

博客主页💖:知识汲取者的博客

LeetCode热题100专栏🚀:LeetCode热题100

Gitee地址📁:知识汲取者 (aghp) - Gitee.com

Github地址📁:Chinafrfq · GitHub

题目来源📢:LeetCode 热题 100 - 学习计划 - 力扣(LeetCode)全球极客挚爱的技术成长平台

PS:作者水平有限,如有错误或描述不当的地方,恳请及时告诉作者,作者将不胜感激

🔒题目

原题链接:15. 三数之和 - 力扣(LeetCode)

在这里插入图片描述

🔑题解

  • 解法一:DFS(时间超限)

    看到找数组中符合记录的三个元素,第一时间就想到可以使用DFS(也就是深搜),但是没写之前就已经猜到,大概率会时间超限,但还是抱着侥幸的心理去尝试以下,于是我就使用DFS实现了,最终不出所料还是时间超限了┭┮﹏┭┮

    import java.util.*;
    import java.util.stream.Collectors;
    
    /**
     * @author ghp
     * @title 三数之和
     */
    class Solution {
        public List<List<Integer>> threeSum(int[] nums) {
            int[] path = new int[3];
            boolean[] vis = new boolean[nums.length];
            List<List<Integer>> ans = new ArrayList<>(10);
            // 通过DSF检索出所有符合条件的元素的组合
            dfs(ans, path, vis, nums, 0);
            // 对list集合进行排序,然后利用Set集合的特性进行去重
            for (List<Integer> list : ans) {
                Collections.sort(list);
            }
            Set<List<Integer>> set = new HashSet<>(ans);
            ans = new ArrayList<>(set);
            return ans;
        }
    
        private void dfs(List<List<Integer>> ans, int[] path, boolean[] vis, int[] nums, int step) {
            if (step >= path.length) {
                // 已经遍历到第三层了,结束搜索
                if (Arrays.stream(path).sum() == 0) {
                    // 将int[]转成Integer
                    List<Integer> t = Arrays.stream(path).boxed().collect(Collectors.toList());
                    ans.add(t);
                }
                return;
            }
            for (int i = 0; i < nums.length; i++) {
                if (!vis[i]){
                    // 将当前搜索到的元素添加到path数组中,同时标记位已遍历
                    path[step] = nums[i];
                    vis[i] = true;
                    // 搜索下一层
                    dfs(ans, path, vis, nums, step + 1);
                    // 恢复现场,用于回溯
                    vis[i] = false;
                }
            }
        }
    }
    

    复杂度分析:

    • 时间复杂度: O ( n 3 ) O(n^3) O(n3)
    • 空间复杂度: O ( 1 ) O(1) O(1)

    其中 n n n 为数组中元素的个数

  • 解法二:暴力(时间超限)

    这里再来使用暴力来实现以下,就是玩ヾ(≧▽≦*)o

    import java.util.*;
    
    /**
     * @author ghp
     * @title 三数之和
     */
    class Solution {
        public List<List<Integer>> threeSum(int[] nums) {
            List<List<Integer>> ans = new ArrayList<>(10);
            // 暴力枚举所有元素的组合
            for (int i = 0; i < nums.length; i++) {
                for (int j = i + 1; j < nums.length; j++) {
                    for (int k = j + 1; k < nums.length; k++) {
                        if (nums[i] + nums[j] + nums[k] == 0) {
                            List<Integer> list = new ArrayList<>(10);
                            Collections.addAll(list, nums[i], nums[j], nums[k]);
                            ans.add(list);
                        }
                    }
                }
            }
            // 对 list集合 进行排序,然后利用Set集合的特性进行去重
            for (List<Integer> list : ans) {
                Collections.sort(list);
            }
            Set<List<Integer>> set = new HashSet<>(ans);
            ans = new ArrayList<>(set);
            return ans;
        }
    }
    

    复杂度分析:

    • 时间复杂度: O ( n 3 ) O(n^3) O(n3)
    • 空间复杂度: O ( n ) O(n) O(n)

    其中 n n n 为数组中元素的个数

    代码优化。直接暴力是肯定不能通过的,我们可以对上面的代码进行优化,通过技巧:排序+双指针对上面代码进行优化,将时间复杂度 O ( n 3 ) O(n^3) O(n3) 降低至 O ( n 2 ) O(n^2) O(n2)。这个解法很巧妙,相信聪明的你看完下面这张图,应该就能够快速理解了

    PS:本解法参考自K神

    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    /**
     * @author ghp
     * @title 三数之和
     */
    class Solution {
        public List<List<Integer>> threeSum(int[] nums) {
            // 先对数据进行排序(升序),方便后续的逻辑处理
            Arrays.sort(nums);
            // 遍历nums,寻找出所有符合条件的元素组合,并且没有重复的组合
            List<List<Integer>> ans = new ArrayList<>(10);
            for (int i = 0; i < nums.length; i++) {
                if (nums[i] > 0) {
                    // 由于数组是升序排序的,当前值大于0,则后面的值一定大于0
                    break;
                }
                if (i > 0 && nums[i] == nums[i - 1]) {
                    // 去除重复的值,防止组合重复
                    continue;
                }
                int l = i + 1; // 左指针,从前往后遍历nums
                int r = nums.length - 1; // 右指针,从后往前遍历nums
                // 利用双指针寻找出符合题意的三个元素
                while (l < r) {
                    int sum = nums[i] + nums[l] + nums[r];
                    if (sum < 0) {
                        // 三数之和小于0,移动左指针(增),注意要去重,防止出现重复组合
                        while (l < r && nums[l] == nums[++l]) ;
                    } else if (sum > 0) {
                        // 三数之和大于0,移动左指针(减),注意要去重,防止出现重复组合
                        while (l < r && nums[r] == nums[--r]) ;
                    } else {
                        // 三数之和等于0,符合条件,则需要同时移动左右指针,并去重
                        ans.add(new ArrayList<>(Arrays.asList(nums[i], nums[l], nums[r])));
                        while(l < r && nums[l] == nums [++l]);
                        while (l < r && nums[r] == nums[--r]) ;
                    }
                }
            }
            return ans;
        }
    
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

知识汲取者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值