zoukankan      html  css  js  c++  java
  • 最大子序列

    一 问题描述:

    输入一组整数,求出这组数字子序列和中最大值。也就是只要求出最大子序列的和,不必求出最大的那个序列。例如:

    序列:-3 18 -4 5 -5 -2,则最大子序列和为23。

    二 解法1:穷举解法

     1 int maxsequence(int a[],int len){
     2   int maxsum = 0;
     3   for(int i = 0;i < len;i++){
     4     for(int j = i;j<len;j++){
     5       int newsum = 0;
     6       for(int k = i;k <=j;k++){
     7         newsum+=a[k];
     8       }   
     9       if(newsum > maxsum)
    10         maxsum = newsum;
    11     }   
    12   }
    13   return maxsum;
    14 }

         这个算法本身是非常简单和容易理解的,通过三个for循环直接给出所有可能出现的子序列,从中选出一个最大值即可。但是该方法时间复杂度真的是太大了,达到了O(n3)有很多操作完成是重复性的操作。例如当i = 0时,j = 1 时:该算法会计算a[0]+a[1],而当i = 0,j = 2时候,该算法会计算a[0]+a[1]+a[2],显然a[0]+a[1] 被重复计算了。

    三 解法2:穷举解法2

     1 int maxsequence2(int a[],int len){
     2   int maxsum = 0;
     3   for(int i = 0;i < len;i++){
     4     int newsum = 0;
     5     for(int j = i;j<len;j++){
     6       newsum+=a[j];
     7       if(newsum > maxsum)
     8         maxsum = newsum;
     9     }   
    10   }
    11   return maxsum;
    12 }

    这个算法本身其实也是非常容易理解的,它不过是上面那个解法的改进,当我们计算i..j的值时候,i--j-1已经被计算过了,可以直接利用,不用重新计算一次i..j-1。其时间复杂度为O(n2),当然了,很明显的,这个时间复杂度也还是非常高的,在计算机里面,一个算法复杂度达到O(n2)其实还是一件比较可怕的事情。

    四 解法3:分治法

    int max3(int i, int j, int k)
    {
      if (i>=j && i>=k)
        return i;
      else if(j >= i && j >= k)
        return j;
      else
        return k;
    }
    
    int max_seq(int a[],int left,int right)
    {
      if(left > right)
        return 0;
      if(left == right)
        return a[left];
    
      int mid = (left + right)/2;
    
      int lmax=a[mid], lsum = 0;
      for(int i = mid;i >=left;i--){
        lsum += a[i];
        if (lsum > lmax)
          lmax = lsum;
      }
    
      int rmax = a[mid+1];
      int rsum = 0;

    for(int i = mid+1;i<=right;i++){ rsum += a[i]; if(rsum > rmax) rmax = rsum; } return max3(lmax+rmax,max_seq(a,left,mid),max_seq(a,mid+1,right)); } int maxsequence3(int a[],int len){ return max_seq(a,0,len-1); }

    这个算法的核心就是分治思想。我们假设将我的已经知道的序列分成左右两部分,那么最大子序列存在的位置显然有三种可能:

      (1)  存在在序列的左部

      (2)  存在在序列的右部

      (3)  既存在在序列的左部又存在在序列的右部。

    显然如果是情况(3),是比较容易算出来的。如果是情况(1)和 (2)的话,我们可以将左部和右部当中一个重新的序列计算,那么新的序列又可以分成左右部分,重复以上即可。该算法的时间复杂度了O(n * lg(n))。

    五 解法四:动态规划

    int maxsequence4(int a[],int len){
    
      int maxsum = a[0];
      int maxnew = a[0];
      for(int i = 1;i < len;i++){
        if(maxnew <= 0)
          maxnew = a[i];
        else
          maxnew += a[i];
    
        if(maxnew > maxsum)
          maxsum = maxnew;
      }
      return maxsum;
    }

    该算法的时间复杂度显然就是O(n),对于计算机来说当然是非常友好的一件事情了,当是对于人来说就不是那么友好了(当然了,神人除外)。我们可以想一下,最大的子序列有什么特点呢?那就是其前m个元素之和也一定不能小于0,为什么?我们假设序列a的长度为len,假设a[i].....a[j],表示为a的最大子序列。如果sum[i->i+m]< 0,那么sum[i+m+1->j] > sum[i->j],矛盾。

    代码体现:

        if(maxnew <= 0)
          maxnew = a[i];
  • 相关阅读:
    直线方程和直线系方程
    多个参数之和积的取值范围
    解析几何习题
    React之Perf
    一文看懂npm、yarn、pnpm之间的区别
    Cannot read property 'properties' of undefined
    为什么要用PolyFill(JS中的修补匠)
    es6-promise
    原生js实现each方法
    有趣的js获取input标签中光标的索引
  • 原文地址:https://www.cnblogs.com/bspp1314/p/9369029.html
Copyright © 2011-2022 走看看