剑指offer 42 连续子数组的最大和
举例分析数组的规律
class Solution {
public int maxSubArray(int[] nums) {
int sum = 0;
int res = nums[0];
int len = nums.length;
for(int i=0;i<len;i++){
sum+=nums[i];
if(sum<nums[i]){
sum = nums[i];
}
if(res<sum){
res = sum;
}
}
return res;
}
}
时间复杂度
O
(
n
)
O(n)
O(n)。
空间复杂度
O
(
1
)
O(1)
O(1)。
动态规划
用
d
p
[
i
]
dp[i]
dp[i]来表示以第
i
i
i个数字结尾的子数组的最大和,那么需要求出
m
a
x
(
d
p
[
i
]
)
max(dp[i])
max(dp[i]),其中
0
<
=
i
<
n
0<=i<n
0<=i<n,递归公式:
这个公式的意义:当以第
i
−
1
i-1
i−1个数字结尾的子数组中所有数字的和小于0时,如果把这个负数与第
i
i
i个数累加,则得到的结果比第
i
i
i个数字本身还要小,所以这种情况下以第
i
i
i个数字结尾的子数组就是第
i
i
i个数字本身。如果以第
i
−
1
i-1
i−1个数字结尾的子数组中所有数字的和大于0,则与第
i
i
i个数字累加就得到以第
i
i
i个数字结尾的子数组中所有数字的和。
class Solution {
public int maxSubArray(int[] nums) {
int[] dp = new int[nums.length];
int len = nums.length;
int res;
dp[0] = nums[0];
for(int i=1;i<len;i++){
if(dp[i-1]<=0){
dp[i] = nums[i];
}
else{
dp[i] = dp[i-1]+nums[i];
}
}
res = dp[0];
for (int i=1;i<len;i++){
if(res<dp[i]){
res = dp[i];
}
}
return res;
}
}
时间复杂度
O
(
n
)
O(n)
O(n)。
空间复杂度
O
(
n
)
O(n)
O(n),使用额外的数组来保存中间值。
动态规划改进(空间复杂度降低)
- 由于 d p [ i ] dp[i] dp[i]只与 d p [ i − 1 ] dp[i-1] dp[i−1]和 n u m s [ i ] nums[i] nums[i]有关系,因此可以将原数组 n u m s nums nums用作 d p dp dp列表,直接在 n u m s nums nums上修改即可。
- 由于省去 d p dp dp列表使用的额外空间,因此空间复杂度从 O ( n ) O(n) O(n)降到 O ( 1 ) O(1) O(1)。
class Solution {
public int maxSubArray(int[] nums) {
int len = nums.length;
int res;
for(int i=1;i<len;i++){
if(nums[i-1]>0){
nums[i] = nums[i-1]+nums[i];
}
}
res = nums[0];
for(int i=1;i<len;i++){
if(res<nums[i]){
res = nums[i];
}
}
return res;
}
}
时间复杂度
O
(
n
)
O(n)
O(n)。
空间复杂度
O
(
1
)
O(1)
O(1)。