最大子段和问题——分治

问题描述

最大子段和问题是指在给定的序列中找到元素之和最大的那一段(连续的一段),即为该序列的最大子段


分治思路

既然我们要用分治的思想来解决这个问题,自然就要划分出子问题来。而这个划分子问题的策略很容易可以想到,就是最经典的均分法。子问题可分为如下三种情况:

  1. 原序列的最大子段包含中间元素
  2. 原序列的最大子段不包含中间元素,且在左半段
  3. 原序列的最大子段不包含中间元素,且在右半段

递归函数的思路大体描述如下:

  1. 分别求出原序列前后1/2的最大子段和
  2. 求出包含原序列中间元素的最大子段和
  3. 合并结果,得出原序列的最大子段和
    对原始串的分治

代码详解

#pragma comment(linker, "/STACK:102400000,102400000")  
#include <iostream>  
#include <cstring>  
#include <cstdlib>  
#include <cstdio>   
#include <algorithm>  
#include <cmath>  
#include <stack>  
#include <string.h>  
#define  ms(a) memset(a,0,sizeof(a))
#define LL long long

using namespace std;
const int MAXN = 101;
//避免带参,数组设为全局变量
int arr[] = { -20, 11, -4, 13, -5, -2 };

int solve(int low, int high) {
    //low==high
    //只有一个元素返回其值
    if (low == high) return arr[low];

    //否则,均分两组分别找出其最大子段和
    int mid = (low + high) / 2;
    int max_left = solve(low, mid);
    int max_right = solve(mid + 1, high);

    //再找包含arr[mid]元素的最大子段和
    //m1为以arr[mid]为最右端元素的最大字段和
    //m2为以arr[mid]为最左端元素的最大字段和
    int m1 = 0, m2 = 0, max_mid = 0;
    int temp = 0;
    for (int i = mid; i >= low; i--) {
        temp += arr[i];
        if (temp > m1) m1 = temp;
    }
    temp = 0;
    for (int i = mid + 1; i <= high; i++) {
        temp += arr[i];
        if (temp > m2) m2 = temp;
    }
    max_mid = m1 + m2;

    //返回三部分(左,中,右)中最大的子段和
    //即为整个数组的最大子段和
    max_left = max(max_left, max_right);
    max_mid = max(max_left, max_mid);
    return max_mid;
}

int main() {
    printf("%d", solve(0, 5));
    return 0;
}

效率分析

就递归函数solve:

T ( n ) = { 1 , n = 1 2 T ( n / 2 ) + n , n > 1

主定理可知算法solve的时间复杂度为 O ( n l o g 2 n )


猜你喜欢

转载自blog.csdn.net/conlink/article/details/79824648