zoukankan      html  css  js  c++  java
  • 扫描算法求最大子序列的一次简单非严格证明

    先给出实现程序,如下:

       1:  int max_sub_sum2(const int v[],int n)
       2:  {
       3:     int max=0;
       4:     int currentSum=0;
       5:     int i=0;
       6:   
       7:     for(i=0;i<n;i++)
       8:     {
       9:         currentSum+=v[i];
      10:         if(currentSum>max)
      11:         {
      12:             max=currentSum;
      13:         }
      14:         else if(currentSum<0)
      15:         {
      16:             currentSum=0;
      17:         }
      18:     }
      19:   
      20:     return max;
      21:  }

    扫描算法是Jon Bentley在编程珠玑里给出的名字,程序看起来非常简洁,不过简介并非意味着简单,至少在当时,问题的发现与提出者Ulf Grenander只想到了O(n2)的算法,而之后的Michael Shamos给出了分治算法,把复杂度降低到O(NlogN),当Bentley以及其它数学家都以为Shamos的算法最好的时候,卡梅隆大学的统计学家Jay Kadane发现了本文算法。

    在这里我们至少能获得关于算法学习的一个重要启示:任何一个看似简单的算法都来之不易,只有经过广泛的研究和实践,你才能熟练地运用算法设计技术。这也是Bentley在编程珠玑八章深入阅读一节种所给出的建议。

    该算法的复杂度很明显是O(N),甚至无需证明。

    但是为理解该算法,我们仍有必要简单分析证明一下该算法的正确性。

    image

    现在命题为:如上图所示序列A1~AN,最大子序列Ai-Aj,则该最大子序列一定可以由上述算法求得。

    证明:

    A[i~j]为最大子序列,则意味着A[i-1]<=0与A[j+1]>=02,论点(1)

    且更可推导出A[1]+A[2]+…+A[i]<=0与A[j+1]+A[j+2]+…+A[N]<=0; 论点(2)

    论点(2)亦可简单地由反证法推得,如二者任意之一若大于零,则很明显A[i~j]不是最大子序列,这与命题所给条件矛盾。

    由论点(2)也可推导出A[i-1]与A[1~i-2]之间的任意子集之和皆<=0,也即|A[i-1]|>A[1]+…+A[i-2],论点(3)

    而论点(2)(3)的情况恰可由程序14~17行规避。

    而程序10~13行计算的又是论点(2)(3)情况之后的子序列的最大值。max用来保存该最大值,currentSum则用来判断是否会出现下一个符合(2)(3)的位置出现,如出现,则该值被清零,并从新位置寻找下一个可能会超过max值的位置,以此归纳,可值命题得证,也即max就是最大子序列的值。

  • 相关阅读:
    微信小程序开发--页面之间的跳转
    iOS基础UI控件介绍-Swift版
    iOS技术栈-Swift版
    SpringBoot实战(四)获取接口请求中的参数(@PathVariable,@RequestParam,@RequestBody)
    SpringBoot实战(三)代码热部署
    SpringBoot实战(二)Restful风格API接口
    SpringBoot实战(一)HelloWorld
    Spring Boot浅谈(是什么/能干什么/优点和不足)
    CentOS的基本设置界面
    虚拟机VM安装Linux系统CentOS7
  • 原文地址:https://www.cnblogs.com/dancewithautomation/p/2552567.html
Copyright © 2011-2022 走看看