Skip to content

30 连续子数组的最大和

题目描述

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

示例

输入: [1, -2, 3, 10, -4, 7, 2, -5]
输出: 18 (子数组[3,10,-4,7,2])

解题思路

核心思想:动态规划。设dp[i]表示以第i个元素结尾的最大子数组和。

状态转移方程

  • dp[i] = max(dp[i-1] + nums[i], nums[i])
  • 即:要么扩展前面的子数组,要么从当前元素重新开始

时间复杂度:O(n) 空间复杂度:O(n) 或 O(1)(优化后)

Python 实现

python
def find_greatest_sum_of_subarray(nums):
    """
    求连续子数组的最大和

    Args:
        nums: 整型数组

    Returns:
        int: 最大子数组和
    """
    if not nums:
        return 0

    max_sum = nums[0]
    current_sum = nums[0]

    for i in range(1, len(nums)):
        # 要么扩展,要么重新开始
        current_sum = max(current_sum + nums[i], nums[i])
        max_sum = max(max_sum, current_sum)

    return max_sum


# 动态规划版本(记录子数组)
def find_greatest_sum_of_subarray_with_dp(nums):
    """
    动态规划版本,返回最大和及其子数组
    """
    if not nums:
        return 0, []

    dp = [0] * len(nums)
    dp[0] = nums[0]
    max_sum = nums[0]
    end_idx = 0

    for i in range(1, len(nums)):
        dp[i] = max(dp[i-1] + nums[i], nums[i])
        if dp[i] > max_sum:
            max_sum = dp[i]
            end_idx = i

    # 找出子数组的起始位置
    start_idx = end_idx
    current_sum = max_sum
    while start_idx > 0 and current_sum != nums[start_idx]:
        current_sum -= nums[start_idx]
        start_idx -= 1

    return max_sum, nums[start_idx:end_idx+1]


# 测试代码
if __name__ == "__main__":
    test_cases = [
        [1, -2, 3, 10, -4, 7, 2, -5],
        [-2, -3, -1, -5],
        [1, 2, 3, 4, 5],
        [-1, 2, 3, -2, 4],
    ]

    for nums in test_cases:
        max_sum, subarray = find_greatest_sum_of_subarray_with_dp(nums)
        print(f"{nums} → 最大和: {max_sum}, 子数组: {subarray}")

# 输出:
# [1, -2, 3, 10, -4, 7, 2, -5] → 最大和: 18, 子数组: [3, 10, -4, 7, 2]
# [-2, -3, -1, -5] → 最大和: -1, 子数组: [-1]
# [1, 2, 3, 4, 5] → 最大和: 15, 子数组: [1, 2, 3, 4, 5]
# [-1, 2, 3, -2, 4] → 最大和: 7, 子数组: [2, 3, -2, 4]

图解

示例: [1, -2, 3, 10, -4, 7, 2, -5]

动态规划过程:
i=0: dp[0] = 1, max=1
i=1: dp[1] = max(1-2, -2) = -1, max=1
i=2: dp[2] = max(-1+3, 3) = 3, max=3
i=3: dp[3] = max(3+10, 10) = 13, max=13
i=4: dp[4] = max(13-4, -4) = 9, max=13
i=5: dp[5] = max(9+7, 7) = 16, max=16
i=6: dp[6] = max(16+2, 2) = 18, max=18
i=7: dp[7] = max(18-5, -5) = 13, max=18

最大和: 18

找出子数组: 从dp[6]=18往前推
18-2=16, 继续往前
16-7=9, 继续往前
9-(-4)=13, 继续往前
13-10=3, 继续往前
3≠3, 停止

子数组: [3, 10, -4, 7, 2]
最近更新

基于 MIT 许可发布