53. 最大子序和
题目:给定一个整数数组 nums
,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例1:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
进阶:
如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。
解题思路:
按照动态规划的思想,我们应该找出与原问题相符的子问题,于是便有如下过程:
- 根据题意可知,题目要求我们在
nums
中找到最大和的连续子数组,那么我们可以将问题变成在nums
的n个子数n组中找出最大和的连续子数组; - 将问题逐步拆分我们可以得出n个子数组的最大和的连续子数组;
- 最后在进行比较便得到最大和的连续子数组;
根据上面的描述我们可以看出nums
中的最大和的连续子数组为n个子数组中的最优解,因此我们可以得到如下过程(类似斐波那契数列):
nums[n] = Max(nums[n], num[n-1],nums[n-2],...)
nums[n-1] = Max(nums[n-1], num[n-2],nums[n-3],...)
nums[n-2] = Max(nums[n-2], num[n-3],nums[n-4],...)
...
所以要得到我们最后的nums
为最优解,前提就是要得到n个子问题的最优解,而n个子问题的最优解又由他们的子问题得到,逆推过来我们可以得到该题的状态转移方程;
nums[1] = Max(nums[0] + nums[1] , nums[1])
nums[2] = Max(nums[1] + nums[2] , nums[2])
nums[3] = Max(nums[2] + nums[3] , nums[3])
...
nums[n] = Max(nums[n-1] + nums[n] , nums[n])
也就是说当前的状态是取决于上一个状态加上当前状态来对比当前状态得出的最优解,如果我们能从一开始保证每个状态都是最优解,那么到最后我们推出的结果也将是最优解。
解题步骤
- 初始化变量和数组,通过
max
记录最优子问题的解; - 遍历数组,通过状态转移方程得出每一个子问题的解,判断是否为当前最优解并记录;
- 判断特殊情况,即数组长度为1时直接返回;
- 返回结果。
分析时间复杂度和空间复杂度:
- 只遍历了一遍数组,所以时间复杂度为O(n);
- 只使用了一些变量,并没有额外的空间开销,所以空间复杂度为O(1);
代码
class Solution {
public int maxSubArray(int[] nums) {
//记录最大的数
int max = nums[0];
int result = nums[0];
for(int i = 1;i<nums.length ;i++){
//当前数组的状态和当前状态加上上一个状态进行比较
nums[i] = Math.max(nums[i] + nums[i-1], nums[i]);
result = nums[i];
//判断是否为当前的最优解
if(result > max)
max = result;
}
if(nums.length == 1)
max = nums[0];
return max;
}
}
提交记录
202 / 202 个通过测试用例
执行用时:1 ms
总结:
第一次在刷题的时候想到用动态规划来解题,尽管好几次因为一些小细节导致解答错误,但好在整体的思路是正确的,最终不断调试后通过了这题。因为小细节导致了错误说明了自己对这种基础的动态规划题还未掌握,往后要加强该方面的练习。