动态规划由简及繁(一)

动态规划由简及繁(一)

连续子数组最大和

输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。

要求时间复杂度为O(n)。

示例1:

输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lian-xu-zi-shu-zu-de-zui-da-he-lcof

分析:

  1. 问题拆解

    求连续子数组的和的最大值。

    假设数组长度为N。

    那么如果知道前N-1子数组的和的最大值Maxn-1,那么到第N个数组的最大值就容易求得了。

  2. 状态定义

一维数组。

设以nums[i]为结尾的最大子数组和为dp[i]。

其实看到有很多博文总结的说是以这个条件,但是我个人思考了一段时间,不知道为什么需要这样。因为一般来说,我们更常见的是用dp{i]去记录到i为止整个数组和的最大值,而不是所谓的 以nums[i]为结尾的子数组和的最大值

我个人的思考是这样的。如果我们选择前者,那么造成的结果就是我们计算的是非连续的,只是整个数组的和的最大值。

那么我们就需要把整个数组看成很多满足前者的情况,也就是说,需要把整个数组看成很多子数组,每个子数组有每个子数组的最大值,我们遍历取最终的最大值即可。当然子数组需要连续。所以才有了后者的状态定义。

  1. 转移方程

    考虑Maxi和Maxi-1的关系。

    1. 如果Maxi-1是负数,那么无论nums[i]是正数还是负数,加上一个负数都会比原来更小。所以不要,以当前数字为结尾的最大子数组和应该是自身。
    2. 如果Maxi-1是正数,nums[i]可正可负,是正数没话说,是负数的话,因为我们需要记录的是以当前数字为结尾的最大子数组和,所以我们需要加上前面的值。(加上正数总会比自身大)。
    dp[i] = dp[i - 1] < 0?
        	nums[i]:
    		dp[i - 1] + nums[i];
    
  2. 边界条件

    1. 刚开始的以自己结尾的最大值就是自己没错了。

      dp[0] = nums[0];
      
    2. 如果数组长度只有0,直接返回0;只有1,第一个值就是最大的了。

  3. 整体代码

    class Solution {
        public int maxSubArray(int[] nums) {
            if (nums.length == 0) {
                return 0;
            }
            if (nums.length == 1) {
                return nums[0];
            }
            
    		int[] dp = new int[nums.length];
            dp[0] = nums[0];
            for (int i = 0; i < nums.length; i++) {
                dp[i] = dp[i - 1] < 0?
                        nums[i]:
                        dp[i - 1] + nums[i];
            }
            
            int max = dp[0];
            for (int i = 1; i < nums.length; i++) {
            	if (dp[i] > max) {
                    max = dp[i];
                }
            }
            
            return max;
        }
    }
    
  4. 考虑优化

    不必存储所有的子数组的最大和,只把子数组和的最大值存起来,每次比对当前累加的值和最大值的大小并且更新最大值就可以了。

    class Solution {
        public int maxSubArray(int[] nums) {
     		int max = nums[0];
            int res = nums[0];
            
            for (int i = 1; i < nums.length; i++) {
            	if (res < 0) {
                    res = nums[i];
                    max = Math.max(max, res);
                } else {
                    res += nums[i];
                    max = Math.max(max, res);
                }
            }
            
            return max;
        }
    }
    

猜你喜欢

转载自blog.csdn.net/qq_42254247/article/details/107994026