#if 0
三种求解递归式的方法,即算法的O渐近界的方法:
(1)代入法:猜测一个界,然后用 数学归纳法证明 这个界正确。
(2)递归树法:将递归式转换为一棵递归树。其结点表示不同层次的递归调用产生的代价。
然后用边界和技术 求解递归式。
(3)主方法:可求解 形如下面公式的递归式的界——T(n) = aT(n/b) + f(n)。
其中a>=1, b>1,f(n)是一个给定的函数。f(n) = O(n^k)。
分治策略中,我们递归地求解每个问题,每层递归可以分为如下三个步骤:
(1)分解(Divide):将问题划分为一些子问题。子问题的形式与原问题一样,只是规模更小——即递归情况。
(2)解决(Conquer):递归地求解出子问题。如果子问题足够小,则停止递归,直接求解——即基本情况。
(3)合并(Combine):将子问题的解组合合成原问题的解。
如该例子中跨越中间位置的子数组,并不与原问题完全一样,将该子问题看做合并步骤的一部分。
INPUT:int a[] = { 13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7 };
OUTPUT:7 10 43
其中,7为low,10为high,43为a[low...high]的和
#endif
#if 1
#include <iostream>
#include <vector>
#define MIXINT 0x80000000
using namespace std;
struct SubArray{
int low;
int high;
int sum;
friend ostream& operator<<( ostream& out, const SubArray& sa );
};
// 重载友元
ostream& operator<<( ostream& out, const SubArray& sa )
{
out << sa.low << "\t" << sa.high << "\t" << sa.sum;
return out;
}
// A[low...high]的任何连续子数组A[i...j],该子数组拥有最大的和
SubArray find_max_subarray( int a[], int low, int high );
int main( void )
{
cout << "2014-6-3 10:05:05" << endl;
// 18为中点
int a[] = { 13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7 };
SubArray sa;
sa = find_max_subarray( a, 0, sizeof( a ) / sizeof( int) - 1 );
//printf( "%d\t%d\t%d\n", sa.low, sa.high, sa.sum );
cout << sa << endl;
return 0;
}
// 不是问题的子问题,故作为合并内容的一部分
// 子数组跨越中点,因此low <= i <= mid < j <= high
SubArray find_max_crossing_subarray( int a[], int low, int mid, int high )
{
SubArray sa;
int sum, left_sum, right_sum;
// 求跨越中点子数组的左侧
sum = 0;
left_sum = MIXINT;
for( int i = mid; i >= low; --i ){
sum += a[i];
if( sum > left_sum ){
sa.low = i;
left_sum = sum;
}
}
// 求跨越中点子数组的右侧
sum = 0;
right_sum = MIXINT;
for( int i = mid + 1; i <= high; ++i ){
sum += a[i];
if( sum > right_sum ){
sa.high = i;
right_sum = sum;
}
}
sa.sum = left_sum + right_sum;
return sa;
}
// 问题描述:公司股票收益,哪天买入,哪天卖出的收益最大化。
// 暴力解法:任取两天求差值,问题转换:得出相邻两天之间收益差值的数组,即求连续子数组的最大和值。
// 暴力解法:n天有n种日期C(n, 2) = O(n^2)-->分治法策略:O(nlgn)
// 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
SubArray find_max_subarray( int a[], int low, int high )
{
SubArray sa, sa_l, sa_r, sa_c;
if( low == high ){
sa.low = low;
sa.high = high;
sa.sum = a[low];
return sa;
}
int mid = ( low + high ) / 2;
sa_l = find_max_subarray( a, low, mid );
sa_r = find_max_subarray( a, mid + 1, high );
sa_c = find_max_crossing_subarray( a, low, mid, high );
if( sa_l.sum >= sa_r.sum && sa_l.sum >= sa_c.sum )
return sa_l;
else if( sa_r.sum >= sa_l.sum && sa_r.sum >= sa_c.sum )
return sa_r;
else
return sa_c;
}
#endif
#if 0
采用动态规划方式:O(n)的时间复杂度解决
f(i) = pData[i] if( i == 0 || f(i -1) <= 0 )
f(i) = f[i - 1] + pData[i] if( i != 0 && f(i -1) > 0 )
#endif
SubArray find_max_subarray_D( int a[], int low, int high )
{
//vector<SubArray> vecSA( high - low + 1 );
SubArray saPre, saCur, saMax;
saPre.sum = 0x80000000;
saPre.low = -1;
saPre.high = -1;
saMax = saPre;
for( int i = low; i <= high; ++i){
if( saPre.sum <= 0 ){
saCur.sum = a[i];
saCur.low = i;
saCur.high = i;
}else{
saCur.sum = saPre.sum + a[i];
saCur.low = saPre.low;
saCur.high = i;
}
saPre = saCur;
if( saMax.sum < saCur.sum ){
saMax = saCur;
}
}
return saMax;
}
#endif