算法复杂度体验
题目:最大子列和问题
给定N个整数序列{A1,A2,…,AN},求函数f(i,j)=max{0,Ai + … +Aj}的最大值
- 三层循环,暴力破解,算法复杂度O(N^3)
//时间复杂度O(N^3)
int MaxSequenceSum1(int *a , int cnt)
{
int ThisSum, MaxSum = 0;
int i, j, k;
for( i = 0; i < N; i++){//确定左起点
for( j = i; j < N; j++){//确定右终点
ThisSum = 0;
for( k = i; k <= j; k++){//求i ~ j之间的和
ThisSum += a[k];
}
if(ThisSum >= MaxSum){//判断,更新结果
MaxSum = ThisSum;
}
}
}
return MaxSum; //反回结果
}
- 双层循环,暴力破解,算法复杂度O(N^2)
//时间复杂度O(N^2)
int MaxSequenceSum2(int *a , int cnt){
int ThisSum, MaxSum = 0;
int i, j;
for( i = 0; i < N; i++){//确定左起点
ThisSum = 0;
for( j = i; j < N; j++){//确定右终点
ThisSum += a[j];//原基础上加后面一位的值
if(ThisSum >= MaxSum){//判断,更新结果
MaxSum = ThisSum;
}
}
}
return MaxSum; //返回结果
}
- 分治法,二叉树求解,算法复杂度O(NlogN)
//分治 、二叉树 时间复杂度:O(NlogN)
int max(int a, int b, int c){
return a > b ? a > c ? a : c : b > c ? b : c;//返回三者最大值
}
int MaxOpration(int *a, int left, int right){
int MaxLeftBorderSum = 0, MaxRightBorderSum = 0;//存放跨分界线的结果
int MaxLeftSum = 0,MaxRightSum = 0;//左右两个子列的结果
int LeftSum = 0, RightSum = 0;
if( left == right) return a[left] > 0 ? a[left] : 0;//递归结束条件
int center = (left + right)/2;//二叉划分
MaxLeftSum = MaxOpration( a, left, center); //左子叶结果
MaxRightSum = MaxOpration( a, center+1, right);//右子叶结果
int i;
//左子叶之和 ,若大于0则赋给MaxLeftBorderSum,若小于0,则 MaxLeftBorderSum不变
for( i = center; i >= left; i--){
LeftSum += a[i];
if(LeftSum > MaxLeftBorderSum) MaxLeftBorderSum = LeftSum;
}
//右子叶之和 ,大于0则赋给MaxRightBorderSum,若小于0,则 MaxRightBorderSum不变
for( i = center+1; i <= right; i++){
RightSum += a[i];
if(RightSum > MaxRightBorderSum){
MaxRightBorderSum = RightSum;
}
}
int MidSum = MaxLeftBorderSum + MaxRightBorderSum;//左右子叶之和
return max(MaxLeftSum, MaxRightSum, MidSum);//返回左子叶结果、右子叶结果、边界之和三者最大值
}
int MaxSequenceSum3(int *a , int cnt){
//保持不同算法接口一致
return MaxOpration( a, 0,cnt - 1 );
}
- 在线处理法,算法复杂度O(N)
“在线”是指每输入一个数据就进行即使处理,在任何一个地方终止,算法都能正确给出当前的解。
int MaxSequenceSum4(int *a , int cnt){
int i;
int ThisSum = 0, MaxSum = 0;
for( i = 0; i < cnt; i++){
ThisSum += a[i];//累加
if(ThisSum > MaxSum) MaxSum = ThisSum;//更新结果
else if(ThisSum < 0) ThisSum = 0;//若当前子列结果小于0,表明不会使最大和变大,则舍弃,从当前位置重新开始累加
}
return MaxSum;
}
- 完整代码展示
//给定N个整数序列{A1,A2,...,AN},求函数f(i,j)=max{0,Ai + ... +Aj}的最大值
#include <stdio.h>
#define N 8 //定义长度,可调
//时间复杂度O(N^3)
int MaxSequenceSum1(int *a , int cnt)
{
int ThisSum, MaxSum = 0;
int i, j, k;
for( i = 0; i < N; i++){//确定左起点
for( j = i; j < N; j++){//确定右终点
ThisSum = 0;
for( k = i; k <= j; k++){//求i ~ j之间的和
ThisSum += a[k];
}
if(ThisSum >= MaxSum){//判断,更新结果
MaxSum = ThisSum;
}
}
}
return MaxSum; //反回结果
}
//时间复杂度O(N^2)
int MaxSequenceSum2(int *a , int cnt){
int ThisSum, MaxSum = 0;
int i, j;
for( i = 0; i < N; i++){//确定左起点
ThisSum = 0;
for( j = i; j < N; j++){//确定右终点
ThisSum += a[j];//原基础上加后面一位的值
if(ThisSum >= MaxSum){//判断,更新结果
MaxSum = ThisSum;
}
}
}
return MaxSum; //返回结果
}
//分治 、二叉树 时间复杂度:O(NlogN)
int max(int a, int b, int c){
return a > b ? a > c ? a : c : b > c ? b : c;//返回三者最大值
}
int MaxOpration(int *a, int left, int right){
int MaxLeftBorderSum = 0, MaxRightBorderSum = 0;//存放跨分界线的结果
int MaxLeftSum = 0,MaxRightSum = 0;//左右两个子列的结果
int LeftSum = 0, RightSum = 0;
if( left == right) return a[left] > 0 ? a[left] : 0;//递归结束条件
int center = (left + right)/2;//二叉划分
MaxLeftSum = MaxOpration( a, left, center); //左子叶结果
MaxRightSum = MaxOpration( a, center+1, right);//右子叶结果
int i;
//左子叶之和 ,若大于0则赋给MaxLeftBorderSum,若小于0,则 MaxLeftBorderSum不变
for( i = center; i >= left; i--){
LeftSum += a[i];
if(LeftSum > MaxLeftBorderSum) MaxLeftBorderSum = LeftSum;
}
//右子叶之和 ,大于0则赋给MaxRightBorderSum,若小于0,则 MaxRightBorderSum不变
for( i = center+1; i <= right; i++){
RightSum += a[i];
if(RightSum > MaxRightBorderSum){
MaxRightBorderSum = RightSum;
}
}
int MidSum = MaxLeftBorderSum + MaxRightBorderSum;//左右子叶之和
return max(MaxLeftSum, MaxRightSum, MidSum);//返回左子叶结果、右子叶结果、边界之和三者最大值
}
int MaxSequenceSum3(int *a , int cnt){
//保持不同算法接口一致
return MaxOpration( a, 0,cnt - 1 );
}
int MaxSequenceSum4(int *a , int cnt){
int i;
int ThisSum = 0, MaxSum = 0;
for( i = 0; i < cnt; i++){
ThisSum += a[i];//累加
if(ThisSum > MaxSum) MaxSum = ThisSum;//更新结果
else if(ThisSum < 0) ThisSum = 0;//若当前子列结果小于0,表明不会使最大和变大,则舍弃,从当前位置重新开始累加
}
return MaxSum;
}
int main()
{
int a[N] = {1,2,-1,2,-3,1,-1,2};
int sum1 = MaxSequenceSum1(a, N);
int sum2 = MaxSequenceSum2(a, N);
int sum3 = MaxSequenceSum3(a, N);
int sum4 = MaxSequenceSum4(a, N);
printf("测试一结果:%d\n测试二结果:%d\n测试三结果:%d\n测试结果四:%d", sum1, sum2, sum3,sum4);
return 0;
}