• 数组的连续最大子段和


      问题描述:输入是一个大小为n的整型数组,要求输出数组的任何连续子数组中的最大值。例如:输入的数组为array[10] = {31,-41,59,26,-53,58,97,-93,-23,84};输出最大连续子数组和为array[2...6]:187

      算法1:对所有满足0<=i<=j<=n的(i,j)整数对进行迭代,对每个整数对,程序都要计算array[i...j]的总和,并检验该总和是否大于迄今为止的最大总和。

    算法1的伪代码描述如下:

    复制代码
    1 maxsofar = 0
    2 for(i=0;i<n;++j)
    3   for(j=i;j<n;++j)
    4     tmepsum = 0
    5 for(k=i;k<=j;++k)
    6       tempsum += array[k]
    7       maxsofar = max(maxsofar,tempmax)
    复制代码

    这段代码简洁明了,便于理解,但是程序执行的速度很慢,时间复杂度为O(n^3)。

      算法2:对于算法1有一个明显的方法可以使其运行起来快得多。使得时间复杂度控制住平方O(n^2)。

    第一个平方算法注意到,array[i...j]的总和与前面计算出的总和(array[i...j-1])密切相关,利用这一点可以达到算法2。

    算法2_1的伪代码描述如下:

    复制代码
    1 maxsofar = 0
    2 for(i=0;i<n;++i)
    3   tempsum = 0;
    4   for(j=i;j<n;++j)
    5 tempsum += array[j]
    6     maxsofar = max(maxsofar,tempsum)
    复制代码

    第二个平方算法是引入一个数组curarray,大小也为n,通过空间来换取时间,通过访问外循环执行之前计算[0...i]各个连续字段总和。curarrary中的第i个元素包含array[0...i]中各个数的累加和,所以x[i...j]中各个数的总和可以通过计算curarray[j] -curarray[i-1]得到.

    算法2_2的伪代码描述如下:

    复制代码
    1 curarray[-1] = 0
    2 for(i=0;i<n;++i)
    3   curarray[i] = curarray[i-1]+x[i]
    4 maxsofar = 0
    5 for(i=0;i<n;++i)
    6    for(j=i;j<n;++j)
    7       sum = curarray[j]-curarray[i-1]
    8 maxsofar = max(maxsofar,sum)
    复制代码

      算法3:可以考虑采用法治算法。初始问题是要处理大小为n的数组,所以可以将其划分为两个子数组a和b,然后递归的找出a、b中元素总和最大的子数组分别为MaxA、MaxB。而最大子数组要么在a中,要么在b中,要么跨越a和b之间的边界,我们将跨越边界的最大子数组记为MaxC。我们通过分治算法计算处了MaxA和MaxB,通过某种办法计算处MaxC。然后返回三个中的最大值就是我们所要的最大子数组和。算法的时间复杂度为O(nlogn)。如何计算MaxC呢?通过观察发现,MaxC在a中的部分是a中包含右边界的最大子数组,而MaxC在b中的部分是b中包含左边界的最大子数组。将这些综合一起我们得到算法3:

    复制代码
     1 int maxsum3(1,n)
     2 {
     3   if(n<1)  //空数组
     4     return 0
     5   if(n==1)  
     6 //只有一个元素的数组
     7     return array[1]
     8    mid = n/2  //分为两部分
     9   lmax = tempsum =0
    10   //包含右边界的最大子数组和
    11   for(i=mid;i>=1;--i)
    12     sum + array[i]
    13   lmax = max(lmax,sum)
    14   rmax = sum =0;//包含左边界的最大子数组和  
    15  for(i=mid;i<n;++i)
    16      sum += array[i] 
    17    rmax = max(rmax,sum)
    18   return max(lmax+rmax,maxsum3(1,mid),maxsum3(mid+1,n))
    19 }
    复制代码

      算法4:我们现在采用操作数组的最简单的算法:从数组最左端(元素x[0])开始扫描,一直到最右端(元素array[n-1])为止,并记下所遇到的最大总和的子数组。最大总和开始设为0.假设我们已经解决了array[0...i-1]的问题,那么如何将其扩展为包含x[i]的问题呢?我们用类似于分治算法的原理:前i个元素中,最大总和子数组要么在前i-1个元素中(将其存maxsofar中),要么其结束位置为i(将其存入maxendinghere中)。不从头开始计算结束位置为i的最大子数组,而是利用结束位置为i-1的最大子数组进行计算。这样就得到了算法4:

    1 maxsofar = 0
    2 maxendinghere = 0
    3 for(i=0;i<n;++i)
    4   maxendinghere = max(maxendinghere+array[i],0)
    5 maxsofar = max(maxsofar,maxendinghere)

      理解这个程序的关键在于maxendinghere。在循环中第一个赋值语句之前,maxendinghere是结束位置为i-1的最大子数组的和,赋值语句将其修改为结束位置为i的最大子数组的和。若加上array[i]的后的结果为正值,则该赋值语句使maxendinghere增大x[i],若加上x[i]之后结果为负值,该赋值语句将maxendinghere重新设置为0(因为结束位置为i的最大子数组现在为空)。这个地方有些难度,需要认真思考揣摩。时间复杂度为O(n),线性算法,效率最高。

    下面针对这4个算法写一个完成的程序来进行测试,程序如下:

    复制代码
      1 。#include <iostream>
      2 using namespace std; //求两个数种最大值
      3 int max(const int m,const int n)
      4 {
      5    return m>n ? m : n;
      6 } //求三个整数中的最大值
      7 int max(const int x,const int y,const int z)
      8 {
      9   int temp = x>y ?  x : y;
     10   temp = temp > z ? temp : z;
     11   return temp;
     12 } //算法1函数实现
     13 int maxsum1(int *array,const size_t len)
     14 {
     15   int maxsofar = 0;
     16   int tempsum = 0;
     17   for(size_t i=0;i<len;++i)
     18     for(size_t  j=i;j<len;++j)
     19     {     
     20       tempsum = 0;
     21       for(size_t k =i;k<=j;++k)
     22       {
     23          tempsum += array[k];
     24          maxsofar = max(maxsofar,tempsum);
     25       }
     26     }
     27   return maxsofar;
     28 } //算法2.1的实现
     29 int maxsum2_1(int *array,const size_t len)
     30 {
     31   int maxsofar = 0;
     32   int tempsum = 0;
     33   for(size_t i=0;i<len;++i)
     34   {
     35       tempsum = 0;
     36       for(size_t  j=i;j<len;++j)
     37       {
     38          tempsum += array[j];
     39          maxsofar = max(maxsofar,tempsum);
     40       }
     41   }
     42   return maxsofar;
     43 } //算法2.2的实现
     44 int maxsum2_2(int *array,const size_t len)
     45 {
     46    int *curarray =NULL;
     47    int maxsofar = 0;
     48    if(len>0)
     49      curarray = new int[len];
     50    curarray[-1] = 0;
     51    for(size_t  i=0;i<len;++i)
     52      curarray[i] = curarray[i-1] + array[i];
     53    for(size_t  j=0;j<len;++j)
     54      for(size_t  k=j;k<len;++k)
     55          //tempsum = curarray[k] - curarray[j-1];
     56         maxsofar = max(maxsofar,curarray[k]-curarray[j-1]);
     57    return maxsofar;
     58 } //算法3的实现
     59 int maxsum3(int *array,const int begin,const int end)
     60 {
     61    int mid = 0;
     62    int lmax=0,rmax =0;
     63    int tempsum = 0;
     64    if(begin==end)
     65      return array[begin];
     66    mid = (begin+end) / 2;
     67    for(int i=mid;i>=begin;--i)
     68    {
     69         tempsum += array[i];
     70         lmax = max(lmax,tempsum);
     71    }
     72    tempsum = 0;
     73    for(int j=mid+1;j<=end;++j)
     74    {
     75      tempsum += array[j];
     76      rmax = max(rmax,tempsum);
     77    }
     78    return max(lmax+rmax,maxsum3(array,begin,mid),maxsum3(array,mid+1,end));
     79 } //算法4的实现
     80 int maxsum4(int *array,const size_t len)
     81 {
     82    int maxendinghere = 0;
     83    int maxsofar = 0;
     84    for(size_t  i=0;i<len;++i)
     85    { 
     86       maxendinghere = max(maxendinghere+array[i],0);
     87       maxsofar = max(maxsofar,maxendinghere);
     88    }
     89    return maxsofar;
     90 } int main()
     91 {
     92    int array[10] = {31,-41,59,26,-53,58,97,-93,-23,84};
     93    int choise;
     94    cout<<"1.算法1"<<endl;
     95    cout<<"2.算法2_1"<<endl;
     96    cout<<"1.算法1"<<endl;
     97    cout<<"3.算法3"<<endl;
     98    cout<<"4.算法4"<<endl;  
     99    cout<<"5.算法2_2"  <<endl;
    100    cout<<"0.退出"<<endl;
    101    while(1)
    102    {
    103      cout<<"选择算法:"; 
    104      cin>>choise;
    105      cout<<"数组的最大字段和为:";
    106      switch(choise)
    107      {
    108      case 1:
    109        cout<<maxsum1(array,10)<<endl;
    110        break;
    111      case 2:
    112        cout<<maxsum2_1(array,10)<<endl;
    113        break;
    114      case 3:
    115        cout<<maxsum3(array,0,9)<<endl;
    116        break;
    117      case 4:
    118        cout<<maxsum4(array,10)<<endl;
    119        break;
    120      case 5:
    121        cout<<maxsum2_2(array,10)<<endl;
    122        break;
    123      case 0:
    124        exit(0);
    125      }
    126    }
    127    return 0;
    128 }
    复制代码

    参考文献:《编程珠玑》第二版 第八章 算法设计的艺术

  • 相关阅读:
    输入框组
    下拉菜单
    地毯文(立足根本的基础细节篇)
    按钮组 button group
    offices web apps server2013 部署
    appium学习
    python练习
    Jmeter分布式测试
    centos安装远程桌面
    进程与线程
  • 原文地址:https://www.cnblogs.com/alantu2018/p/8469133.html
Copyright © 2020-2023  润新知