leetcode题解——53. Maximum Subarray

题意
题目的意思就是:在给定的数组中选取一组连续的子数组,使得这个子数组的和是所有子数组和最大值。

解法一(分治策略)

思路:

 我首先想到的是算法导论分治策略一章给出的解法:
     假设我们要寻找数组A[left,right]中的最大子数组,分治策略要求我们把问题分解两个规模相当的子数组,也就是说要找的子数组的中心middle,然后考虑求解两个子数组A1[left,middle],A2[middle+1,right]。求出的子数组肯定出自下面三种情景:
  1. 子数组完全位于middle左侧
  2. 子数组完全位于middle右侧
  3. 子数组跨越了middle

这里写图片描述

第三种情况下,子数组最好求,只需要在middle左侧开始找到连续和最大子数组L,在middle右侧开始找到连续和最大子数组R,两个数组合并就可以得到跨越middle最大的子数组。

代码
str_array 结构体是用来存储最大子数组的区间和最大值;
find_Max_Crossing_Array()函数:因为寻找数组必须从middle开始,所以两个for循环均从middle开始,分别向左右查找。找到最大数组就更新索引和最大和,直到到达数组的两边。

typedef struct arra{
    int left_;
    int right_;
    int sum_;
}str_array;

str_array find_Max_Crossing_Array(int *a, int left, int middle, int right) {
    int left_sum_max = INT_MIN;
    int right_sum_max = INT_MIN;
    int max_left = 0;
    int max_right = 0;
    int sum = 0;
    str_array tmp;

    for (int i = middle; i >= left; i--) {
        sum += *(a + i);
        if (sum >= left_sum_max) {
            left_sum_max = sum;
            max_left = i;
        }
    }
    sum = 0;
    for (int i = middle+1; i <= right; i++) {
        sum += *(a + i);
        if (sum >= right_sum_max) {
            right_sum_max = sum;
            max_right = i;
        }

    }
    tmp.left_ = max_left;
    tmp.right_ = max_right;
    tmp.sum_ = left_sum_max + right_sum_max;
    return tmp;
}
    算法复杂度,两个for循环都是遍历了整个数组,所以复杂度为O(n),线性时间复杂度。

有了上述代码,最可以设计最大子数组的代码了:
代码分析:如果数组只含有一个元素,直接返回;

  1. 如果数组只含有一个元素,直接返回
  2. 将数组分解,分别求解三种情况下的最大数组,各数组信息用left_array, right_array, acrossing_array保存
  3. 通过比较left_array.sum_,right_array.sum_,acrossing_array.sum_,选出这三个数组中和最大的数组
str_array find_Max_Sum_Child_Array(int *a, int left, int right) {
    str_array tmp;
    if (left == right) {
        tmp.left_ = left;
        tmp.right_ = right;
        tmp.sum_ = *(a + left);
        return tmp;
    }
    else {
        int middle = (left + right) / 2;
        str_array left_array, right_array, acrossing_array;
        left_array = find_Max_Sum_Child_Array(a, left, middle);
        right_array = find_Max_Sum_Child_Array(a, middle + 1, right);
        acrossing_array = find_Max_Crossing_Array(a, left, middle, right);

        if (left_array.sum_ >= right_array.sum_ && left_array.sum_ >= acrossing_array.sum_)
            return left_array;
        else if (right_array.sum_ >= left_array.sum_ && right_array.sum_ >= acrossing_array.sum_)
            return right_array;
        else return acrossing_array;
    }
}

算法复杂度:递归结果调用了递归树,树的高度h=lgn,
复杂度T(n)=n*lgn;
下面是主函数,可以方便的获取最大子数组索引和sum:

int main() {
    int a[9] = { -2,1,-3,4,-1,2,1,-5,4 };
    str_array result = find_Max_Sum_Child_Array(a, 0, 8);
    cout << result.left_ << " " << result.right_ << " " << result.sum_ << endl;
    system("pause");
    return 0;
}

运行结果:
这里写图片描述

问题差不多,所以在提交的时候基本上就是原来思路:

class Solution {
    int divide(vector<int>& nums,int l,int r){
        if(l==r)    return nums[l];

        int m=(l+r)/2;
        int left=divide(nums,l,m);
        int right=divide(nums,m+1,r);
        int middle=nums[m];
        int tmp=middle;
        for(int i=m-1;i>=l;i--){
            tmp+=nums[i];
            middle=max(middle,tmp);
        }
        tmp=middle;
        for(int i=m+1;i<=r;i++){
            tmp+=nums[i];
            middle=max(middle,tmp);
        }
        return max(middle,max(left,right));

    }
public:
    int maxSubArray(vector<int>& nums) {
        return  divide(nums,0,nums.size()-1);
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值