连续子数组的最大和
1 题目描述
输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
要求时间复杂度为O(n)。
示例1:
输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
2 解题思路
本题使用暴力法两层循环可解决,时间复杂度为O(n²)。
可使用动态规划降低时间复杂度。在第一次使用动态规划时想到用二维数组保存结果dp[i][j]
表示从nums[i]
到nums[j]
的子数组的和。dp[i][j]=nums[j-1]+dp[i][j-1]
在填充dp
数组时得到最大值。
class Solution {
public int maxSubArray(int[] nums) {
int[][] dp = new int[nums.length+1][nums.length+1];
int max = nums[0];
for(int i = 1;i< dp.length;i++){
for (int j = i; j < dp.length; j++) {
dp[i][j]=nums[j-1]+dp[i][j-1];
if (max<dp[i][j])
max=dp[i][j];
}
}
return max;
}
}
然而这种思想是错误的,并没用起到动态规划减少时间复杂度的作用,时间复杂度仍然为O(n²)。
因此不能使用二维dp数组,使用一维dp数组解题。重新构造状态转换公式。
因为本题只需要找出最大值,而不用得到子序列因此可使用一维数组dp[i]
表示到nums[i]
结尾的子数组的最大和。当dp[i-1]
为负数时,到nums[i]
结尾子数组的最大和即为nums[i]
。因此
d
p
[
i
]
=
d
p
[
i
−
1
]
+
n
u
m
s
[
i
]
(
d
p
[
i
−
1
]
>
0
)
dp[i]=dp[i-1]+nums[i](dp[i-1]>0)
dp[i]=dp[i−1]+nums[i](dp[i−1]>0)
d
p
[
i
]
=
n
u
m
s
[
i
]
(
d
p
[
i
−
1
]
<
=
0
)
dp[i]=nums[i](dp[i-1]<=0)
dp[i]=nums[i](dp[i−1]<=0)
为进一步节省空间,可以直接以nums
作为dp
数组直接修改得到(i从1开始,res初始为nums[0]
)
n
u
m
s
[
i
]
+
=
m
a
x
(
n
u
m
s
[
i
−
1
]
,
0
)
nums[i]+=max(nums[i-1],0)
nums[i]+=max(nums[i−1],0)
r e s = m a x ( r e s , n u m s [ i ] ) res=max(res,nums[i]) res=max(res,nums[i])
3 代码
class Solution {
public int maxSubArray(int[] nums) {
int res = nums[0];
for(int i =1;i<nums.length;i++){
nums[i]+=Math.max(nums[i-1],0);
res=Math.max(res,nums[i]);
}
return res;
}
}