算法导论之最大子数组问题

例如我们在求解下面的最大子数组时

13-3-2520-3-16-231820-712-5-2215-47

 

 

最简单的做法就是暴力求解,但是时间复杂度为O(n^2);

//
//  main.cpp
//  算法导论
//
//  Created by SJCHEN on 2019/1/19.
//  Copyright © 2019 SJCHEN. All rights reserved.
//

#include <iostream>
using namespace std;

#define INF 10000000
int A[] = {13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
int len = sizeof(A)/sizeof(A[0]);
int max = -INF;

int FindMaxSubarray(int A[])
{
    int max = -INF;
    int sum = 0;
    for (int left = 0; left < len; left++) {
        sum = 0;
        for (int right = left; right < len; right++) {
            sum += A[right];
            if (sum > max) {
                max = sum;
            }
        }
    }
    return max;
}

int main()
{
    cout << FindMaxSubarray(A) << endl;
    return 0;
}

那么有没有更好的做法呢?

答案当然是有,我们可以使用分治策略的求解方法。

使用分治技术意味着我们要将子数组划分为两个规模尽量相等的子数组。

当然我们可以发现,在A[low, high]中的任何连续子数组A[i,j]所处的位置必然是以下三种情况之一:

一,完全位于子数组A[low, mid]中,low <= i <= j <= mid

二,完全位于子数组A[mid + 1, high]中,mid < i<= j <=high

三,跨越了中点,因此low <= i <=mid <= j <= high

//
//  main.cpp
//  算法导论
//
//  Created by SJCHEN on 2019/1/19.
//  Copyright © 2019 SJCHEN. All rights reserved.
//

#include <iostream>
using namespace std;

#define INF 10000000
int A[] = {13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
int len = sizeof(A)/sizeof(A[0]);
int MaxLeft = 0, MaxRight = 0;
int leftsum = -INF, rightsum = -INF, crosssum = -INF;
int leftlow = -INF, lefthigh = -INF, rightlow = -INF, righthigh = - INF;
int crosslow = - INF, crosshigh = -INF;

int FindMaxCrossingSubarray(int low, int mid, int high)
{
    leftsum = -INF;
    int sum = 0;
    for (int i = mid; i >= low; i--) {
        sum += A[i];
        if (sum > leftsum) {
            leftsum = sum;
            MaxLeft = i;
        }
    }
    rightsum = -INF;
    sum = 0;
    for (int j = mid + 1; j <= high; j++) {
        sum += A[j];
        if (sum > rightsum) {
            rightsum = sum;
            MaxRight = j;
        }
    }
    return (leftsum + rightsum);
}

int FindMaxIMUMSubarray(int low, int high)
{
    if (high == low)
        return A[low];
    else {
        int mid = (low + high) / 2;
        leftsum = FindMaxIMUMSubarray(low, mid);//递归求解左边
        rightsum = FindMaxIMUMSubarray(mid + 1, high);//递归求解右边
        crosssum = FindMaxCrossingSubarray(low, mid, high);//横跨左右
        if (leftsum >= rightsum && leftsum >= crosssum)//左
            return leftsum;
        else if (rightsum >= leftsum && rightsum >= crosssum)//右
            return rightsum;
        else return crosssum;//两边
    }
}

int main()
{
    cout << FindMaxIMUMSubarray(0, len - 1) << endl;
    return 0;
}

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值