【每日刷题】最大子序和

题目地址

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

题目描述:最大子序和

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

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4],

输出: 6

解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

解答

针对该问题,现给出三种解法。


解法一:暴力求解(最直观的方法)
对于长度为 n 的数组A, 任选两个位置作为区间起始和末尾,计算该区间所代表的的子数组的和,选择最大的一个。
因为需要两重循环,因此时间复杂度为O(n^2).
由于计算区间和时需要借助一个辅助数组,因此空间复杂度为O(n).

代码:

int find_max_subArray( vector<int>& A){
    // 构造辅助数组,用来暂存区间和
    vector<int> B = A;
    for( int i = 1; i < A.size(); i++)
        B[i] += B[i-1];
    
    //暴力求解
    int res = INT_MIN;
    for( int i = 0; i < A.size(); i++)
        for( int j = i + 1; j < A.size(); j++)
            res = max( max( res, B[j] - B[i]), A[i]);
    
    return res;
}

解法二:分治算法(不好理解且代码长)
假设将数组A[low, …, high] 以位置mid处划分为两个长度大致相等的子数组,则最大子数组A[i, …, j] 必定为以下三种情况之一:

  1. 最大子数组完全位于 A[low, …, mid] 之间,即 low <= i <= j <= mid.
  2. 最大子数组完全位于 A[mid, …, high] 之间,即 mid <= i <= j <= high.
  3. 最大子数组跨越了 mid 位置,即 low <= i <= mid < j <= high.

三种情况见下图:
【每日刷题】最大子序和_第1张图片

代码:

int find_max_subArray( vector<int>& A, int left, int right){
    // 处理基准情况
    if( left > right)   
        return INT_MIN;   
    if(left == right)   // 仅有一个元素
        return A[left];
    
    int mid = left + (right - left) / 2; // 防止溢出
    int L = find_max_subArray( A, left, mid - 1);   // 寻找左侧最大和
    int R = find_max_subArray( A, mid + 1, right);  // 寻找右侧最大和
    
    // 跨过中间位置时
    int sum = A[mid], sum_max = A[mid];
    for( int i = mid - 1; i >= left; i--){
        sum += A[i];
        sum_max = max( sum, sum_max);
    }
    sum = sum_max; // 向另外一侧移动时需要初始化
    for( int i = mid + 1; i <= right; i++){
        sum += A[i];
        sum_max = max( sum, sum_max);
    }
    
    return max( max( L, R), sum_max);
    
}
// 在主程序中输入的参数应该为 find_max_subArray(A, 0, A.size() - 1) 

解法三:动态规划(不易理解但短小精悍)
初始化变量 sum = 0, 从头遍历数组,对于每一个元素 A[i], 变量 sum += A[i], 一旦 sum < 0, 立即让 sum = 0, 并向后移动一个元素,直到数组尾部。最终选择最大的 sum 值。

为直观起见,以数组 A = [-2, 3, -1, 2, -3] 为例:
【每日刷题】最大子序和_第2张图片
代码:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        if( nums.size() == 0)
            return 0;
        int res = nums[0], sum = 0;
        for( auto it:nums){
           // cout<<" sum = "<
            if( sum < 0)
                sum = 0;
            
            sum += it;
            res = max( res, sum);        
        }
        
        return res;
    }
};

你可能感兴趣的:(每日刷题)