JZ85 连续子数组的最大和(二)

JZ85 连续子数组的最大和(二)

描述

输入一个长度为n的整型数组array,数组中的一个或连续多个整数组成一个子数组,找到一个具有最大和的连续子数组。

1.子数组是连续的,比如[1,3,5,7,9]的子数组有[1,3],[3,5,7]等等,但是[1,3,7]不是子数组

2.如果存在多个最大和的连续子数组,那么返回其中长度最长的,该题数据保证这个最长的只存在一个

3.该题定义的子数组的最小长度为1,不存在为空的子数组,即不存在[]是某个数组的子数组

4.返回的数组不计入空间复杂度计算

数据范围:

$1<=n<=105$

$−100<=a[i]<=100$

要求:时间复杂度$O(n)$,空间复杂度$O(n)$

进阶:时间复杂度$O(n)$,空间复杂度$O(1)$

示例略

题解

仔细看了一下,这道题和JZ42还不一样,JZ42只需要返回最大值即可,这道题需要返回最长的最大子数组本身。

首先我们还是定义最小子问题,我们要找的目标是一样的,仍然是具有最大和的连续子数组,这次我们则可以定义一个二维数组$dp$,然后在其中储存数对,用来表示以i结尾的最长的最大子数组。

到这里我想到并不需要二维数组,只需要一维数组$indexDp$即可,其中保存的是以i为结尾拥有最大和的子数组的开头即可,这样再维护一个数组用来表示这个子数组的和就可以了。

这道题提到了可能存在多个有着相同的最大和的最大子数组,需要返回一个最长的,我们只需要在最后再次遍历一遍$dp$,寻找最大值的同时,将相应的$i-index+1$长度比较一下就可以了。

最后寻找最长最大的时候的边界条件写了很久,这道题的优化和JZ42的空间$O(1)$优化一样,$dp$都只依赖于它的前一项,所以只需要做一个$pre$来进行迭代就可以了。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <algorithm>
#include <vector>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param array int整型vector
* @return int整型vector
*/
vector<int> FindGreatestSumOfSubArray(vector<int>& array) {
vector<int> dp;
vector<int> indexDp;
dp.push_back(array[0]);
indexDp.push_back(0);
for (int i = 1; i < array.size(); i++) {
if (array[i] > dp[i - 1] + array[i]) {
dp.push_back(array[i]);
indexDp.push_back(i);
} else {
dp.push_back(dp[i - 1] + array[i]);
indexDp.push_back(indexDp[i - 1]);
}
}
int maxSum = -101;
int maxLength = -1;
int start = 0;
int end = 0;
for (int i = 0; i < dp.size(); i++) {
cout << dp[i] << " " << maxSum << " " << indexDp[i] << " " << maxLength << endl;
if (dp[i] > maxSum || (dp[i] == maxSum && (i - indexDp[i] + 1) > maxLength)) {
maxSum = dp[i];
maxLength = i - indexDp[i] + 1;
start = indexDp[i];
end = i;
}
}
vector<int> ans;
for (int i = start; i <= end; i++)
ans.push_back(array[i]);


return ans;
}
};