连续子数组最大和(动态规划)❗❗❗❗经典面试题,巨细❗❗❗❗

381 阅读3分钟

题目链接

力扣:leetcode.cn/problems/ma…

牛客:www.nowcoder.com/practice/17…

下面的解题使用的是牛客的OJ,和力扣稍微有点区别的就是需要自己写入数组。

题目描述

给定一个长度为 n 的数组,数组中的数为整数。

请你选择一个非空连续子数组,使该子数组所有数之和尽可能大,子数组最小长度为1。求这个最大值。

输入描述:

第一行为一个正整数 n ,代表数组的长度。 1n21051 ≤ n ≤ 2*10^5

第二行为 n 个整数 ai,用空格隔开,代表数组中的每一个数。$∣a~# 连续子数组最大和

题目链接

力扣:leetcode.cn/problems/ma…

牛客:www.nowcoder.com/practice/17…

下面的解题使用的是牛客的OJ,和力扣稍微有点区别的就是需要自己写入数组。

题目描述

给定一个长度为 n 的数组,数组中的数为整数。

请你选择一个非空连续子数组,使该子数组所有数之和尽可能大,子数组最小长度为1。求这个最大值。

输入描述:

第一行为一个正整数 n ,代表数组的长度。 1n21051 ≤ n ≤ 2*10^5

第二行为 n 个整数 aia_i,用空格隔开,代表数组中的每一个数。ai102∣a_i∣≤10^2

输出描述:

连续子数组的最大之和。

示例1

输入:

8
1 -2 3 10 -4 7 2 -5

输出:

18

说明:经分析可知,输入数组的子数组[3,10,-4,7,2]可以求得最大和为18

题目解析

此题当然有暴力解法,嵌套循环,但是本题考的知识点并不是它,如果面试官出的这题,我们应该使用动态规划来解。

1.状态表示

IMG_0513.PNG 我们要找到最大的子数组之和,也就需要从左往右进行遍历元素,在以 i 下标为结尾时,列出所有以 i 为结尾的子数组,寻找出最大子数组之和。

例如上图,当数组下标 i = 4的时候,此时的子数组有5种情况,但是最大的子数组为[7,0,8],结果为15

然后我们创建dp表,也就是一个数组,这个数组用于存储i所在位置的最大值。

例如,将i = 4的最大值记录到dp[4],所以dp[4] = 15


所以我们的状态表示:

dp[i] :以 i 为结尾的最大子数组和。


那此处如果是第一次了解动态规划的同学就会有疑问,为什么表示以i为结尾的最大子数组的和呢

在我的理解,我们的状态表示就是需要 直接展现出 变量在 此刻 的结果。而状态转移方程就是让“此刻”动起来

2.状态转移方程

IMG_0516.PNG

我们先看看方程有几种情况

状态表示——dp[i] :以 i 为结尾的最大子数组和。

如上图的dp表和数组arr所对应的情况,

i = 0时,子数组只有[3],所以dp[0] = 3

i = 1时,子数组有两种情况,[3, -4][-4],最大值为 - 1。而[3, -4]其实就是dp[0] + arr[1]的这种情况。所以dp[1] = dp[0] + arr[1] = -1。因为dp[0]是以0为结尾的最大的子数组之和,所以最大的(前提dp[i]为正数)加上arr[1]就是dp[1]的最大数。

i = 2时,子数组有3种,也就是图上黑线画出的[3, -4, 7][-4, 7][7],此时最大的结果为7,并不是dp[1] + arr[2],因为dp[1]为负数。

所以我们状态表示方程就出来了,但在写代码的时候为了方便,我们不需要判断dp[i - 1]的值是否大于0,而是直接比较这两种情况谁大就行。

IMG_0518.PNG

3.编写代码

image-20240129122614733.png