剑指offer | 面试题42:连续子数组的最大和

转载本文章请标明作者和出处
本文出自《Darwin的程序空间》
本文题目和部分解题思路来源自《剑指offer》第二版

在这里插入图片描述

开始行动,你已经成功一半了,献给正在奋斗的我们

题目

输入一个整型数组,数组里有正数也有负数。数组中一个或连续的多个整数组成一个子数组。求所有子数组的和的最大值。要求时间复杂度为O(n)。

例如:输入的数组为{1, -2, 3, 10, -4, 7, 2, -5},和最大的子数组为{3, 10, -4, 7, 2}。因此输出为该子数组的和18。

解题分析

这道题,很多人可能想到的是穷举出这个数组所有的非空子集,然后算出所有子集的和,在其中取最大值即为答案,这我们也可以称之为暴力破解法;

但是一个数组的非空子集的个数为n(n+1)/2个,这样看的话,时间复杂度怎么的也得在O(n^2),显然,这是不符合题意的;

我们仔细审题,其实题目已经给了我们提示,既然他的时间复杂度的要求是O(n),所以这就间接说明了我们要在一次遍历中搞定这个事情;双层乃至三层for循环,就不要再想了;

既然是一遍循环就能搞定,那么我们想一下,在遍历的过程中,首先是1,那么遍历到这,我们所知道的最大值就是1,然后是-2,-2加1是-1,所以最大值还是1。然后是3,那么要用-1加3么?肯定不!因为加上-1只会让3变得小,所以3开始是不会再要前面加起来为-1的子数组了,新的最长子数组应该从3为头计算,那么3和之前最大的1比,明显比1要大,所以最大值就变成3。后面是10,10加上3能变得更大,于是最大值变成了13,然后然后遇到了-4,13加上-4等于9,9没有当前最大值13大,于是最大值还是13。然后后面是7,那么7要和前面的【3,10,-4】在一起么?为什么不呢?7加上前面的9更大了啊!所以现在的最长子串是【3,10,-4,7】,最大值是16,然后后面是2,最长子串变成了【3,10,-4,7,2】,最大值变成了18,然后最后是-5,18加-5等于13,并没有18大,所以最后的结果是18;

精髓就是,每遍历到一个节点,是都要用前面的子数组,取决于,前面的子数组是否大于0,你大于0我加上你就更大,我就要你,否则,我就成为新的子数组的起点,我们没遍历一个节点就比较一下和当前最大值,最后就能求出连续子数组的最大和;

后面的结果和前面的结果息息相关,这是什么思想呢?


那些遗忘过去的人注定要重蹈覆辙 ~ 动态规划
所谓动态规划: 现在通过分析这个问题,我们可以将新的输入(或者不在数据结构中的输入)与其对应的输出存储下来。或者在字典中查找输入并返回相应的输出结果。这样当你在进行一些计算时,你可以检查数据结构中是否存在该输入,如果数据输入存在的话就可以直接获得结果。我们将与这种方法相关的技巧称作动态规划。--来源于百度


我们定义两个变量,一个max(用于记录所求结果,最大的子数组和),一个temp用于记录下一个节点前的最大连续和(用于判断本节点要不要和前面的节点组成子数组还是单独成为起始节点)。

这两个节点先图同时指向第一个元素,max每次就负责和temp比较,一旦temp超过了它,就用temp替换掉它;因为temp可能遇到一个负数,也有可能遇到正数,在temp变成负数之前不会被贵0,而max只负责记住最大的连续和;所以temp对下一个节点负责,max对整体的结果负责;

要特别注意的是,我们要重点考虑数组全为负数的情况,此时应该返回最大的负数,做好代码的健壮性;

代码(JAVA实现)

ps:这里笔者使用的jdk为1.8版本

测试数据即为图示数据;

public class SubArray {

    public static void main(String[] args) {
        int[] arr = new int[]{1, -2, 3, 10, -4, 7, 2, -5};
        int max = getMax(arr);
        System.out.println(max);
    }

    private static int getMax(int[] arr) {
        int max = arr[0];
        int temp = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] + temp < 0) {
                if (arr[i] + temp > max) {
                    max = arr[i] + temp;
                }
                temp = 0;
                continue;
            }
            if (arr[i] + temp > 0) {
                temp += arr[i];
            }
            if (temp > max) {
                max = temp;
            }
        }
        return max;
    }
}
  • 动态规划精简版
public class SubArray {

    public static void main(String[] args) {
        int[] arr = new int[]{1, -2, 3, 10, -4, 7, 2, -5};
        int max = getMax(arr);
        System.out.println(max);
    }

    private static int getMax(int[] arr) {
        int temp = arr[0];
        int max = arr[0];
        for (int i = 1; i < arr.length; i++) {
            temp = Math.max(temp + arr[i], arr[i]);
            max = Math.max(max, temp);
        }
        return max;
    }
}

题外话

其实这道题对比笔者来说是很重要的,因为这是笔者做出的第一道算法题,是来成都之后一个面试官给我出的,当时我翻遍朋友全的大神,会算法的竟然屈指可数,当我做出来这道题之后,我高兴了很久…

我把当时面试官的面试题贴出来,留一个纪念;
在这里插入图片描述


喜欢的朋友可以加我的个人微信,我们一起进步
发布了156 篇原创文章 · 获赞 19 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/qq_36929361/article/details/104382584
今日推荐