LeetCode每日1题--三数之和

62 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情

前言

算法的重要性不言而喻!区分度高!

现在学习的门槛低了,只有能上网每个人都可以学编程!培训班6个月就可以培养出来能干活的人,你怎么从这些人中脱颖而出?没错!就是学算法,学一些底层和基础的东西。

说的功利点是为了竞争,卷死对手。真心话说就是能提高自己的基础能力,为技术可持续发展做好充分的准备!!!

提前入门学习书籍:CPrimerPlus、大话数据结构

image-20220705103735001

刷题网站

代码随想录 (programmercarl.com)

leetcode

我是按照代码随想录提供的刷题顺序进行刷题的,大家也可以去刷leetcode最热200道,都可以

刷题嘛,最重要的就是坚持了!!!

画图软件

OneNote

这个要经常用,遇见不懂的流程的话就拿它画一画!

笔记软件

Typoral

题目

image.png

解析

暴力思路

三层for循环 都可以想到的方法,但是它行不行呢?

public class TheSumOfThreeNumbers {
    public static void main(String[] args) {
        int[] nums = {-1, 0, 1, 2, -1, -4};
        ArrayList<List<Integer>> arrayList = new ArrayList<>();
​
        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++) {
                    int sum = nums[i] + nums[j] + nums[k];
                    if (sum == 0){
                        arrayList.add(Arrays.asList(nums[i],nums[j],nums[k]));
                    }
                }
            }
        }
        arrayList.forEach(x -> System.out.println(x));
​
    }
}

image-20220729222033842 不太行,因为[-1,0,1],[0,1,-1]]算是重复的啦,换位置也不行

双指针

这题的确不好想,看题解中的例子是使用指针的方法:

  1. 首先对数组排序
  2. 定义二个指针
  3. 循环for目的是遍历数组,i从下标0开始
  4. 第一个指针left从i+1开始,代表第二个数
  5. 第二个指针right在数组尾部,代表第三个数

相当于 a = nums[i],b = nums[left],c = nums[right]。

接下来如何移动left 和right呢?

想起我们刚开始对数组做的排序了吗?如果nums[i] + nums[left] + nums[right] > 0 就说明 此时三数之和大了所以right下标就应该向左移动,这样才能让三数之和小一些。

nums[i] + nums[left] + nums[right] < 0 说明三数之和小了,left就向右移动,才能让三数之和大一些,直到left与right相遇为止。

时间复杂度:O(n^2)。

public static List<List<Integer>> threeSum(int[] nums) {
        ArrayList<List<Integer>> result = new ArrayList<>();//存放结果集,格式为[[],[],[]....]
        Arrays.sort(nums); //对目标数据进行排序
​
        if (nums == null || nums.length < 3) {
            return result;
        }
​
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] > 0) {
                return result;      //临界条件的一些判断,如果排序后的第一个数都大于0那么三数之后不可能为0
            }
            /**
             * 加上i > 0是因为第一个数没和前一个数比较,会出现数组越界
             * 为i-1是因为,i是增加的,它要和后面的数比较看是否相等
             */
            if (i > 0 && nums[i] == nums[i - 1]) { //
                continue;   //这里是对i的去重
            }
            int left = i + 1;   //左指针
            int right = nums.length - 1;    //右指针
            while (right > left) {
                int sum = nums[i] + nums[left] + nums[right];
                if (sum > 0) {
                    right--;    //和大于0,说明加的太大了,只能让right左移
                } else if (sum < 0) {
                    left++; //和小于0,说明加的太小了,只能让left右移
                } else {
                    result.add(Arrays.asList(nums[i], nums[left], nums[right]));//等于0,加入结果集
                    while (right > left && nums[left] == nums[left + 1]) left++;//对右指针去重
                    while (right > left && nums[right] == nums[right - 1]) right--;//对左指针去重
                    right--;//往左移动
                    left++;//往右移动
                }
            }
        }
        return result;
​
    }

代码中也有详细的解释,实在不明白的话可以dubug一下 image-20220801105636108