Skip to content

Latest commit

 

History

History
119 lines (95 loc) · 3.77 KB

85.连续子数组的最大和(二).md

File metadata and controls

119 lines (95 loc) · 3.77 KB

85.连续子数组的最大和(二)

题目描述

输入一个长度为n的整型数组array,数组中的一个或连续多个整数组成一个子数组,找到一个具有最大和的连续子数组。

  • 1.子数组是连续的,比如[1,3,5,7,9]的子数组有[1,3][3,5,7]等等,但是[1,3,7]不是子数组
  • 2.如果存在多个最大和的连续子数组,那么返回其中长度最长的,该题数据保证这个最长的只存在一个
  • 3.该题定义的子数组的最小长度为1,不存在为空的子数组,即不存在[]是某个数组的子数组
  • 4.返回的数组不计入空间复杂度计算

示例 1

输入:[1,-2,3,10,-4,7,2,-5]
返回值:[3,10,-4,7,2]
说明:经分析可知,输入数组的子数组[3,10,-4,7,2]可以求得最大和为18,故返回[3,10,-4,7,2] 

示例 2

输入:[1]
返回值:[1]

思路 & 解答

这道题是比较经典的动态规划,假设现在有� n 个元素,突然加上一个元素,变成 n+1 个元素,对连续子数组的最大和有什么影响呢?

我们只需要知道以每一个元素结尾的最大连续子数组,再维护一个最大的值即可。

假设数组为num[],用 dp[i] 表示以下标 i 为终点的最大连续子数组和,遍历每一个新的元素nums[i+1],以 num[i+1] 为连续子数组的情况只有两种:

  • dp[i] + num[i+1]
  • 只有num[i+1]

所以以nums[n] 结尾的最大连续子数组和为:

$$ dp[i] = max(dp[i-1] + nums[i],nums[i]) $$

在计算的过程中,需要维护一个最大的值,并且把该连续子数组的左边界以及右边界维护好,最后根据维护的区间返回。

Java 代码实现如下:

public class Solution85 {
    public int[] FindGreatestSumOfSubArray(int[] array) {
        int[] dp = new int[array.length];
        dp[0] = array[0];
        int maxsum = dp[0];
        int left = 0, right = 0;
        int maxLeft = 0, maxRight = 0;

        for (int i = 1; i < array.length; i++) {
            right++;
            dp[i] = Math.max(dp[i - 1] + array[i], array[i]);
            if (dp[i - 1] + array[i] < array[i]) {
                left = right;
            }
            // 更新最大值以及更新最大和的子数组的边界
            if (dp[i] > maxsum
                    || dp[i] == maxsum && (right - left + 1) > (maxRight - maxLeft + 1)) {
                maxsum = dp[i];
                maxLeft = left;
                maxRight = right;
            }
        }
        // 保存结果
        int[] res = new int[maxRight - maxLeft + 1];
        for (int i = maxLeft, j = 0; i <= maxRight; i++, j++) {
            res[j] = array[i];
        }
        return res;
    }
}

C++ 代码如下:

class Solution {
public:
    vector<int> FindGreatestSumOfSubArray(vector<int> &array) {
        vector<int> dp(array.size(), 0);
        dp[0] = array[0];
        int maxsum = dp[0];
        int left = 0, right = 0;
        int maxLeft = 0, maxRight = 0;

        for (int i = 1; i < array.size(); i++) {
            right++;
            dp[i] = max(dp[i - 1] + array[i], array[i]);
            if (dp[i - 1] + array[i] < array[i]) {
                left = right;
            }
            // 更新最大值以及更新最大和的子数组的边界
            if (dp[i] > maxsum
                || dp[i] == maxsum && (right - left + 1) > (maxRight - maxLeft + 1)) {
                maxsum = dp[i];
                maxLeft = left;
                maxRight = right;
            }
        }
        // 保存结果
        vector<int> res;
        for (int i = maxLeft, j = 0; i <= maxRight; i++, j++) {
            res.push_back(array[i]);
        }
        return res;
    }
};