最长子序列问题之系列一

   求解最大连续子序列和问题,最直接的办法就是求出每个连续子序列的和,然后找出最大和即可,但这种算法的效率为O(n^2),代码如下,


   
int LS()
{
int Max =- 999999999 ;
for ( int i = 0 ;i < n;i ++ )
{
int sum = 0 ;
for ( int j =i ;j < n;j ++ )
{
sum
+= a[j];
if (sum > Max) Max = sum;
}
}
return Max;
}

 这种算法适用于数据量比较小的情况。

   在这种方法里, 有许多不必要的重合计算,而正是这些不必要的计算影响了程序的执行效率。为了提高算法的效率,尽可能的排除那些不必要的计算过程,可以采用一下算法,此算法效率为O(n).

  此算法的改进之处就在于消除了前一个算法出现多次重复的弊端。


   

// 该算法满足连续子序列求和问题:sum>=0的情况
// 如果有最大和为负数的情况,可以以特殊情况单独处理即可
for (i = 0 ;i < n;i ++ )
{
cin
>> a[i];
sum
+= a[i];
if (sum > Max)
{
Max
= sum;
start
= k + 1 ;
end
= i + 1 ;
}
if (sum < 0 ) // 关键点,消除不必要的重复
{
k
= i + 1 ;
sum
= 0 ;
}
}

 算法思想:

    对于每个a[i]而言,在和前一次的sum相加后都会进行一次比较, 

  if(sum>Max)
   {
    Max=sum;
    start=k+1;
    end=i+1;
   } , 其中start记录最大连续子序列的起始位置,end记录其结束位置 ,而在如果出现sum<0的情况 ,直接将sum=0; 因为对于任何一个子序列来说,在保证了其sum>=0的前提下,出现负数是不可能的,故可将其直接清0;而此时需对起始位置进行记录,以便下一次如果出现sum>Max的情况,则可为start重新赋值。 

      此处还有一个需要注意的地方就是0<sum<Max的情况,其实这也好理解,如果0<sum<Max, 则继续执行 sum+=a[i], 在这种情况下不能对sum进行清0,因为sum是一个递增的过程,可能在某一时刻会出现sum>Max的情况。

做题的时候碰到了两种情况:

(1)http://acm.hdu.edu.cn/showproblem.php?pid=1003  上面的过程就是解决这个问题的

(2)http://acm.hdu.edu.cn/showproblem.php?pid=1231 

 因为上面的出现保证了sum>=0的情况,所以 对上面的算法做一个小处理就ok了,处理如下:

  1.   排除都为负数的情况
  2.   排除最大和为0的情况

代码如下,


   
for (i = 0 ;i < n;i ++ )
{
cin
>> a[i];
if (a[i] < 0 ) count ++ ; //排除都为负数的情况
if (a[i] == 0 && i < L) L = i; //排除最大和为0的情况
sum
+= a[i];
if (sum > Max)
{
Max
= sum;
start
= k + 1 ;
end
= i + 1 ;
}
if (sum < 0 )
{
k
= i + 1 ;
sum
= 0 ;
}
}
if (Max > 0 ) cout << Max << " " << a[start - 1 ] << " " << a[end - 1 ] << endl;
else if (count != n && Max == 0 ) cout << Max << " " << a[L] << " " << a[L] << endl;
else cout << Max << " " << a[ 0 ] << " " << a[n - 1 ] << endl;

  

转载于:https://my.oschina.net/garyun/blog/602806

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值