力扣(LeetCode) 53.最大子数组和
- 最大子数组和
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:
输入:nums = [1]
输出:1
示例 3:
输入:nums = [5,4,-1,7,8]
输出:23
提示:
1 <= nums.length <= 105
-104 <= nums[i] <= 104
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-subarray
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
数组都会有最后一个元素,我们从最后一个元素入手。
dp[i]表示以nums[i]结尾的最大子数组的和,
以数组nums = [-2 , 1 , -3 , 4 , -1 , 2 , 1 , -5 , 4]为例,
- 当以nums[0]结尾时,最大子数组的和dp[0] = nums[0] = -2;
- 当以nums[1]结尾时,最大子数组的和dp[1] = nums[1] = 1;
- 当以nums[2]结尾时,最大子数组的和dp[2] = nums[2] + dp[2 - 1] = -2;
- 当以nums[3]结尾时,最大子数组的和dp[3] = nums[3] = 4;
- 当以nums[4]结尾时,最大子数组的和dp[4] = nums[4] + dp[4 - 1] = 3;
- 当以nums[5]结尾时,最大子数组的和dp[5] = nums[5] + dp[5 - 1] = 5;
- 当以nums[6]结尾时,最大子数组的和dp[6] = nums[6] + dp[6 - 1] = 6;
- 当以nums[7]结尾时,最大子数组的和dp[7] = nums[7] + dp[7 - 1] = 1;
- 当以nums[8]结尾时,最大子数组的和dp[8] = nums[8] + dp[8 - 1] = 5;
选出dp数组中最大的值,最大为dp[6] = 6;
从上面我们可以得到规律,如果dp[i - 1] < 0时,dp[i] = nums[i],否则dp[i] = nums[i] + dp[i - 1]。
所以得到状态转移方程:dp[i] = max(nums[i], nums[i] + dp[i - 1]);
代码如下:
代码
class Solution {
public int maxSubArray(int[] nums) {
if(nums.length == 0)
return 0;
int max;
int[] dp = new int[nums.length];
dp[0] = nums[0];
max = nums[0];
for(int i = 1; i < nums.length; i++){
dp[i] = Math.max(nums[i], nums[i] + dp[i - 1]);
max = Math.max(max, dp[i]);
}
return max;
}
}
此方法时间复杂度O(n),空间复杂度O(n)。
简化代码
上面代码中我们发现求dp[i]时,不会用到nums[i - 1],所以我们可以用nums[i]来存取dp[i]的值,以此来降低空间复杂度。
class Solution {
public int maxSubArray(int[] nums) {
if(nums.length == 0)
return 0;
int m = nums[0];
for(int i = 1; i < nums.length; i++){
nums[i] = Math.max(nums[i], nums[i] + nums[i - 1]);
m = Math.max(m, nums[i]);
}
return m;
}
}
此方法时间复杂度O(n),空间复杂度O(1)。