子列和列_最大子列和(参考浙大-数据结构-MOOC)

参考中国大学Mooc (浙江大学)->数据结构

我把陈越姥姥讲的最大子列和记录一下,以备不时之需.

"最大子列和" 问题

给一个数组,让求出其中所有子列数据的和的Max 值.

1.暴力求解

拿到这个问题的第一瞬间想到的几乎都是暴力,

遍历所有的子序列,找到其中最大值

//暴力求解

int MaxSubseqSum1(int A[], int n)

{

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++)

{

ThisSum += a[k];

}// 求子列和

if(ThisSum > MaxSum)

{

int t = ThisSum;

ThisSum = MaxSum;

MaxSum = t;

}

}

}

return MaxSum;

}

优点:特别容易被人理解,特别简单

缺点:时间复杂度N的立方,太慢了

2.暴力的改进版本

仔细分析第一种方法,可以得到,最内层 的 k 循环,完全可以通过简单的变化消失掉.

即:建立在 j 循环基础,消除 k 循环

//对暴力的简单改进

int MaxSubseqSum1(int A[], int n)

{

int ThisSum, MaxSum = 0;

int i,j,k;

//找出所有子列

for (i = 0; i < n; i++)

{

ThisSum = 0;

for (j = i; j < n; j++)

{//此处使用累加,消除掉 k 循环

ThisSum += a[j];

if(ThisSum > MaxSum)

{

int t = ThisSum;

ThisSum = MaxSum;

MaxSum = t;

}

}

}

return MaxSum;

}

时间复杂:N的平方

较第一种改进较大.

3. 二分

int Max3( int A, int B, int C )

{ /* 返回3个整数中的最大值 */

return A > B ? A > C ? A : C : B > C ? B : C;

}

int DivideAndConquer( int List[], int left, int right )

{ /* 分治法求List[left]到List[right]的最大子列和 */

int MaxLeftSum, MaxRightSum; /* 存放左右子问题的解 */

int MaxLeftBorderSum, MaxRightBorderSum; /*存放跨分界线的结果*/

int LeftBorderSum, RightBorderSum;

int center, i;

if( left == right ) { /* 递归的终止条件,子列只有1个数字 */

if( List[left] > 0 ) return List[left];

else return 0;

}

/* 下面是"分"的过程 */

center = ( left + right ) / 2; /* 找到中分点 */

/* 递归求得两边子列的最大和 */

MaxLeftSum = DivideAndConquer( List, left, center );

MaxRightSum = DivideAndConquer( List, center+1, right );

/* 下面求跨分界线的最大子列和 */

MaxLeftBorderSum = 0; LeftBorderSum = 0;

for( i=center; i>=left; i-- ) { /* 从中线向左扫描 */

LeftBorderSum += List[i];

if( LeftBorderSum > MaxLeftBorderSum )

MaxLeftBorderSum = LeftBorderSum;

} /* 左边扫描结束 */

MaxRightBorderSum = 0; RightBorderSum = 0;

for( i=center+1; i<=right; i++ ) { /* 从中线向右扫描 */

RightBorderSum += List[i];

if( RightBorderSum > MaxRightBorderSum )

MaxRightBorderSum = RightBorderSum;

} /* 右边扫描结束 */

/* 下面返回"治"的结果 */

return Max3( MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum );

}

int MaxSubseqSum3( int List[], int N )

{ /* 保持与前2种算法相同的函数接口 */

return DivideAndConquer( List, 0, N-1 );

}

时间复杂度:N*log(N)

但是理论较难,代码晦涩.

4.在线处理

一个牛逼的算法

从前到后进行一次遍历,找到其中最大值,但是只要某一段子列和为0,即抛弃此时的ThisSum,重新置为0

//在线处理法

int MaxSubseqSum4(int A[], int n)

{

int ThisSum = 0, MaxSum = 0;

int i;

for(i = 0; i

{

ThisSum += a[i];

if(ThisSum >MaxSum)

{

MaxSum= ThisSum;

}

else if(ThisSum <0){

ThisSum = 0;

}

}

return MaxSum;

}

时间: N

缺点: 总有人怀疑其正确性(讲真,我还觉得这个算法有问题...)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值