问题描述
最大子段和问题是指在给定的序列中找到元素之和最大的那一段(连续的一段),即为该序列的最大子段。
分治思路
既然我们要用分治的思想来解决这个问题,自然就要划分出子问题来。而这个划分子问题的策略很容易可以想到,就是最经典的均分法。子问题可分为如下三种情况:
- 原序列的最大子段包含中间元素
- 原序列的最大子段不包含中间元素,且在左半段
- 原序列的最大子段不包含中间元素,且在右半段
递归函数的思路大体描述如下:
- 分别求出原序列前后1/2的最大子段和
- 求出包含原序列中间元素的最大子段和
- 合并结果,得出原序列的最大子段和
代码详解
#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:
由主定理可知算法solve的时间复杂度为