求解整型数组的最大子串和 

题目描述

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。

问题分析

首先,这是一个最优化问题,这里的“优”指的是“最大和”
其次,此问题可分解成重叠子问题,设 f(i) 为 [0,i] 之间的连续子串的最大和。那么整个数组的连续子串最大和为:\(\max_{0 \leq i \leq n-1}{f(i)}\) 也即选取其中最大的 f(i)。

如何分解子问题?要想求解 f(i),得先求解 f(i-1),分解公式为:f(i) = max{f(i-1)+nums[i], nums[i]}
为什么是这个分解公式呢?根据以前求最长回文子串的解法,我一开始想到的是:f(i) = max{f(i-1)+nums[i], f(i-1)} 。求解最长回文子串参考:https://www.cnblogs.com/hapjin/p/16185680.html
这两个公式有何区别?其关键点在“连续”二字上。f(i) = max{f(i-1)+nums[i], f(i-1)} 求解出来的 f(i) 并不一定是连续的子串之和。举个例子:
nums = [2, 10, -1, 30],按 f(i) = max{f(i-1)+nums[i], f(i-1)} 求解出来的最大子串和为:
f(0)=2
f(1)=12
f(2) = max{12+(-1), 12} = 12
f(3)= max{12+30, 12} = 42
显然,f(3)=42 计算出来的最大子串和并不是“连续”的!因为 f(3) 其实质上是忽略了 nums[2]=-1 这个值的。

f(i)的连续子串和,意味着:f(i) 要么是从 f(i-1) 再加上第 i 个元素、要么是直接从第 i 个元素开始,这样才算是连续的,因此:max{f(i-1)+nums[i], nums[i]} 才是最大连续子串和的分解式。它计算出来的结果如下:
f(0)=2
f(1)=12
f(2) = max{12+(-1), -1} = 11
f(3)= max{11+30, 30} = 41

代码实现

class Solution {
    public int maxSubArray(int[] nums) {
        //状态数组,dp[i] == f(i)
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        for (int i = 1; i < nums.length; i++) {
            //状态转移公式
            dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);
        }

        //find max:找出 f(i) 的最大值,就是最大连续子串
        int max = Integer.MIN_VALUE;
        for (int i = 0; i < dp.length; i++) {
            if (dp[i] > max) {
                max = dp[i];
            }
        }
        return max;
    }
}

leetcode链接:https://leetcode-cn.com/problems/maximum-subarray/

posted @ 2022-05-02 10:27  大熊猫同学  阅读(47)  评论(0编辑  收藏  举报