分而治之
分而治之(D&C)是一种重要的算法设计范例。在分治策略中,我们递归地求解一个问题,在每层递归中应用如下三步骤:
- 分解(Divide):将问题划分为一些子问题,子问题的形式与原问题一样,只是规模更小
- 解决(Conquer):递归地求解出子问题。如果子问题规模足够小,则停止递归,直接求解
- 合并(Combine):将子问题的解组合成原问题的解
分治的核心是合并(Combine/Merge)
例子(Examples):
- Maximum Contiguous Subarray(最大子数组)
- Counting Inversions(逆序计数)
- Integer Multiplication(整数乘法)
- Ploynomial Multiplication(多项式乘法)
- QuickSort and Partition(快速排序与划分)
- Deterministic and Randomized Selection(确定性与随机化选择)
Maximum Contiguous Subarray(最大子数组)
正式定义:
- 输入:一实数数组A[1...n]
- 子数组A[i...j]的值是:
找到i <= j,使V(i,j)最大化。
暴力求解
计算每一对i <= j的V(i,j)的值,返回最大值。c++代码实现:
/***************************************************************
暴力求解(Brute Force):
计算每一对i <= j的V(i,j)的值,返回最大值。
复杂度:O(n^3)
****************************************************************/
double MCS_BF(vector<double> &A)
{
int sz = A.size();
if(sz == 0){
cout << "输入数组为空" << endl;
return -1;
}
double vmax = A[0];
for(int i= 0; i < sz; ++i){
for(int j = i; j < sz; ++j){
double sum = 0;
for(int x = i; x <= j; ++x){
sum += A[x];
}
if(sum > vmax)
vmax = sum;
}
}
return vmax;
}
数据再利用
不需要从头计算每一个V(i,j), V(i,j) = V(i,j-1) + A[j]。c++代码实现:
/****************************************************************
数据再利用(Data_Reuse) :
不需要从头计算每一个V(i,j), V(i,j) = V(i,j-1) + A[j]
复杂度:O(n^2)
*****************************************************************/
double MCS_DR(vector<double> &A)
{
int sz = A.size();
if(sz == 0){
cout << "输入数组为空" << endl;
return -1;
}
double vmax = A[0];
for(int i= 0; i < sz; ++i){
double sum = 0;
for(int j = i; j < sz; ++j){
sum += A[j];
if(sum > vmax)
vmax = sum;
}
}
return vmax;
}
分而治之
设 ,

数组A[low...high]的最大子数组定是以下三种之一:
-
:位于A[low...m];
-
:位于A[m+1...high];
- SM:跨越中点
.
c++代码实现:
/****************************************************************
分而治之(Divide-and-Conquer)
复杂度:O(nlogn)
*****************************************************************/
double FindMaxCrossingSubarr(vector<double> &A, int low, int mid, int high)
{
double SM1 = A[mid];
double sum = A[mid];
for(int i = mid-1; i >= low; --i){
sum += A[i];
if(sum > SM1)
SM1 = sum;
}
double SM2 = A[mid + 1];
sum = A[mid + 1];
for(int j = mid + 2; j <= high; ++j){
sum += A[j];
if(sum > SM2)
SM2 = sum;
}
return SM1+SM2;
}
double FindMaxSubarr(vector<double> &A, int low, int high)
{
if(low == high)
return A[low];
int m = floor((low + high) / 2);
double S1 = FindMaxSubarr(A,low,m);
double S2 = FindMaxSubarr(A,m+1,high);
double SM = FindMaxCrossingSubarr(A,low,m,high);
return max({S1,S2,SM});
}
double MCS_DC(vector<double> &A)
{
if(A.empty()){
cout << "输入数组为空" << endl;
return -1;
}
int low = 0;
int high = A.size() - 1;
return FindMaxSubarr(A,low,high);
}
运行效果:

用O(n)时间复杂度解决:Kadane算法