跳至主要內容

53, 最大子序和

Mike大约 3 分钟greedymediumarraydivide and conquerdynamic programming

一、题目描述

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

子数组是数组中的一个连续部分。

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

示例 2
输入: nums = [1]
输出: 1

示例 3
输入: nums = [5, 4, -1, 7, 8]
输出: 23

提示

  • 1 <= nums.length <= 10⁵
  • -10⁴ <= nums[i] <= 10⁴

进阶
如果你已经实现复杂度为O(n)的解法,尝试使用更为精妙的分治法求解。

相关主题

  • 数组
  • 分治
  • 动态规划

二、题解

方法 1: 动态规划

/// 时间复杂度:O(n)
/// 空间复杂度:O(1)
pub fn max_sub_array(nums: Vec<i32>) -> i32 {
    let (mut pre, mut res) = (0, nums[0]);

    for num in nums {
        pre = max(pre + num, num);
        res = max(res, pre);
    }

    res
}

方法 2: 前缀和

/// 时间复杂度:O(n)
/// 空间复杂度:O(1)
pub fn max_sub_array(nums: Vec<i32>) -> i32 {
    let mut res = i32::MIN;
    let (mut min_pre_sum, mut pre_sum) = (0, 0);

    for num in nums {
        pre_sum += num;
        res = max(res, pre_sum - min_pre_sum);
        min_pre_sum = min(min_pre_sum, pre_sum);
    }

    res
}

方法 3: 分治

/// 时间复杂度:O(n)
/// 空间复杂度:O(log(n))
pub fn max_sub_array(nums: Vec<i32>) -> i32 {
    struct Status {
        l_sum: i32,
        r_sum: i32,
        m_sum: i32,
        i_sum: i32,
    }

    const PUSH_UP: fn(Status, Status) -> Status = |l, r| Status {
        l_sum: max(l.l_sum, l.i_sum + r.l_sum),
        r_sum: max(r.r_sum, r.i_sum + l.r_sum),
        m_sum: max(max(l.m_sum, r.m_sum), l.r_sum + r.l_sum),
        i_sum: l.i_sum + r.i_sum,
    };

    const GET: fn(&[i32], usize, usize) -> Status = |nums, l, r| {
        if l == r {
            return Status {
                l_sum: nums[l],
                r_sum: nums[l],
                m_sum: nums[l],
                i_sum: nums[l],
            };
        }

        let m = (l + r) >> 1;
        let l_sub = GET(nums, l, m);
        let r_sub = GET(nums, m + 1, r);

        PUSH_UP(l_sub, r_sub)
    };

    GET(&nums, 0, nums.len() - 1).m_sum
}