数组连续子序列的最大的和;四种算法,四种时间复杂度

给定一组数据:31, -41, 59, 26, -53, 58, 97, -93, -23, 84。要求找到这组数据中连和最大的子序列,相信很多人都看过这个算法,能够直接给出线性时间复杂度的解法。但是还是有其他解法的,而且是循序渐进的,从O(n^3), O(n^2), O(n*logn)到O(n)。

在开始算法之前要进行一下约定,如果当前输入的都是负数的时候,综合最大的子序列是空的,总和为0.

第一种方法就是brute-force解法,就是对满足所有的0<=i < j < n的组合(i,j)进行迭代,对于每个整数对都要计算a[i,j]的总和,这个算法有个特点,也就是造成时间复杂度很高的缺点,对于每次计算的结果没有记录,只是简单的将此次计算的结果和上次计算的结果进行比较,求得当前最大值后,就给扔掉了。下面给出算法:

[cpp]  view plain  copy
  1. current_max = 0;  
  2. sum = 0;  
  3. for(i = 0; i < n; i++) {  
  4.     for(j = i; j < n; j++) {  
  5.         sum = 0;  
  6.         for(k = i; k <= j; k++)  
  7.             sum += a[k];  
  8.         if(sum > current_max)  
  9.             current_max = sum;  
  10.     }  
  11. }  


很清楚的可以看出,对i和j的操作过程中,只是对当前和与上次的和做简单的比较,之后就扔弃了。想一想,可不可以这样做,对于特定的i,遍历所有可行的j值,记录此次(i,j)的操作,对于(i,j+1)的操作可以在(i,j)所得和的基础上简单的加a[j+1]就可以了。

下面给出算法:

[cpp]  view plain  copy
  1. current_max = 0;  
  2. for(i = 0; i < n; i++) {  
  3.     sum = 0;  
  4.     for(j = i; j < n; j++) {  
  5.         sum += a[j];  
  6.         if(sum > current_max)  
  7.             current_max = sum;  
  8.     }  
  9. }  
这个时间复杂度比上次的有所降低。

同时,这个问题还可以用分治算法来解决,可能会有疑问,因为分治算法是用来解决子问题之间没有联系的问题的。而求连续子序列和最大值得问题更多的和动态规划相关,因为用动态规划很容易解决这个问题。但是分治也可以,这种算法很巧妙,巧妙的让人不可思议。给出算法代码:

[cpp]  view plain  copy
  1. #include<stdio.h>  
  2. int max(int a, int b, int c) {  
  3.     if(a > b) {  
  4.         if(a > c) {  
  5.             return a;  
  6.         } else {  
  7.             return c;  
  8.         }  
  9.     } else {  
  10.         if(b > c) {  
  11.             return b;  
  12.         } else {  
  13.             return c;  
  14.         }  
  15.     }  
  16. }  
  17. int get_max(int *a, int low, int high) {  
  18.     int m = (low + high) / 2;  
  19.     int i;  
  20.     int sum, lmax, rmax;  
  21.   
  22.     if(low > high)  
  23.         return 0;  
  24.     if(low == high)  
  25.         return a[low] > 0 ? a[low] : 0;  
  26.   
  27.     sum = lmax = 0;  
  28.     for(i = m; i >= low; i--){  
  29.         sum += a[i];  
  30.         if(sum > lmax) {  
  31.             lmax = sum;  
  32.         }  
  33.     }  
  34.       
  35.     sum = rmax = 0;  
  36.     for(i = m + 1; i <= high; i++) {  
  37.         sum += a[i];  
  38.         if(sum > rmax) {  
  39.             rmax = sum;  
  40.         }  
  41.     }  
  42.   
  43.     return max(lmax + rmax, get_max(a, low, m), get_max(a, m + 1, high));  
  44. }  
  45.   
  46. void main() {  
  47.     int a[] = {31, -41, 59, 26, -53, 58, 97, -93, -23, 84};  
  48.     int n = sizeof(a) / sizeof(int);  
  49.     int result = get_max(a, 0, n - 1);  
  50.     printf("max_sum = %d\n", result);  
  51. }  
这个算法的巧妙之处就在于计算lmax和rmax之处,计算lmax是从m开始到low结束,计算rmax是从m+1开始,在high结束。

最后一种方法就是使用动态规划了,相信很多人能给出此种算法。直接给出代码:

[cpp]  view plain  copy
  1. #include<stdio.h>  
  2. int get_max2(int *a, int n) {  
  3.     int current_max = a[0];  
  4.     int final_max = a[0];  
  5.     int i;  
  6.     for(i = 1; i < n; i++) {  
  7.         if(current_max + a[i] > 0) {  
  8.             current_max += a[i];  
  9.         } else {  
  10.             current_max = 0;  
  11.         }  
  12.         if(current_max > final_max) {  
  13.             final_max = current_max;  
  14.         }  
  15.     }  
  16.     return final_max;  
  17. }  
  18. void main() {  
  19.     int a[] = {31, -41, 59, 26, -53, 58, 97, -93, -23, 84};  
  20.     int n = sizeof(a) / sizeof(int);  
  21.     int rst = get_max2(a, n);  
  22.     printf("max_sum = %d\n", rst);  
  23. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值