题目描述
给一个数组,返回它的最大连续子序列的和.
题目分析
这道题可以利用动态规划来解决.
令状态dp[i]表示以A[i]为结尾的连续序列的最大和.
此时以A[i]结尾的序列有两种情况:
- 只有一个元素, 即为A[i]
- 有多个元素, 即从A[k] ~ A[i] (k < i)
于是我们得到状态转移方程:
d
p
[
i
]
=
m
a
x
(
A
[
i
]
,
d
p
[
i
−
1
]
+
A
[
i
]
)
,
d
p
[
0
]
=
A
[
0
]
dp[i] = max(A[i], dp[i-1]+A[i]),dp[0]=A[0]
dp[i]=max(A[i],dp[i−1]+A[i]),dp[0]=A[0]
边界为dp[0] = A[0].
怎么理解
一开始接触这道题的时候, 比较难理解的点的就是:
为什么状态转移方程要比较当前值?
我们一起构造这样一种序列:
{
3
,
−
8
,
6
,
1
,
2
,
5
}
\{3,-8,6,1,2,5\}
{3,−8,6,1,2,5}
求一下dp数组:
- dp[0] = 3, 因为最长子序列是它本身, 是固定的值.
- dp[1] = -5, 因为上一个最长子序列对以当前元素为末尾的最长子序列起了正向作用.(也就是上一个最长子序列是正数, 正+正=正)
- dp[2] = 6, 这里是因为上一个dp[1]=-5, 对本序列起到了负向作用, 也就是加进来会让整体的值变小, 所以我们直接取当前的值.
所以只要明白了这个原理(正向/负向作用), 这道题就很容易推出来.
代码
public class Solution {
// Time: O(n), Space: O(n)
public int FindGreatestSumOfSubArray(int[] array) {
// 动态规划
// 状态转移方程: dp[i] = max(array[i], dp[i - 1] + array[i])
int max = Integer.MIN_VALUE;
int[] dp = new int[array.length];
dp[0] = array[0]; //设置边界
for (int i = 1; i < array.length; i++) {
dp[i] = Math.max(dp[i - 1] + array[i], array[i]);
if (dp[i] > max) max = dp[i];
}
return max;
}
}
另外一种写法(原理相同), 不另外开辟数组, 直接判断上一个序列是否为负, 为负直接舍弃即可.
public class Solution {
// Time: O(n), Space: O(1)
public int maxSumOfSubArray(int[] nums) {
int max = Integer.MIN_VALUE, cur = 0;
for (int i = 0; i < nums.length; ++i) {
cur = cur <= 0 ? nums[i] : (cur + nums[i]);
max = Math.max(max, cur);
}
return max;
}
}