zoukankan      html  css  js  c++  java
  • 一道算法题,看看大家的思路(续)

      “一道算法题,看看大家的思路”,看了众多的回复,本人愚钝,没有看明白其中的奥妙。在细细研究《编程之美》中的文章后,终于理解了这个算法的思路。现将这个算法的演算过程以及代码实现(VB2005)赋予其后,和各位交流。

      现再将题目复述一遍:

      题目描述:有31,-41,59,26,-53,58,97,-93,-23,84十个数。SUM(N,M)表示从第N个数到到第M个数的和。例如:SUM(2,3)=-41+59=18。问:最大的和是多少?对应的N和M是多少?

      先不管N和M的计算,直接计算SUM,看看用什么算法。

      算法一:直接遍历穷举,求出SUM。代码如下:

      Public Function MaxSum1() As Integer
        Dim i As Integer, j As Integer, k As Integer, _
        Sum As Integer, Maximum As Integer = Integer.MinValue

        For i = 0 To A.GetUpperBound(0)
          For j = i To A.GetUpperBound(0)
            Sum = 0
            For k = i To j
              Sum += A(k)
              If Sum > Maximum Then Maximum = Sum
            Next
          Next
        Next
        Return Maximum
      End Function

      这个代码最容易理解,但是效率最低,算法的复杂度为O(N3)

      算法二,在算法一的基础上改进,因为SUM(N,M)=SUM(N,M-1)+A(M),基于这个原理,将上述代码中的最里面的一层循环去掉。

      Public Function MaxSum2() As Integer
        Dim i As Integer, j As Integer, Sum As Integer, _
          Maximum As Integer = Integer.MinValue
        For i = 0 To A.GetUpperBound(0)
          Sum = 0
          For j = i To A.GetUpperBound(0)
            Sum += A(j)
            If Sum > Maximum Then Maximum = Sum
          Next
        Next
        Return Maximum
      End Function

      这个代码也很容易理解,算法执行效率有明显的提高,算法的复杂度为O(N2),但还不够。

      算法三:

      考虑数组第一个元素A(0)和最大和的一段数组A(N),……,A(M)。他们之间有如下关系:

      1、当0=N=M时,元素A(0)本身构成最大和的一段

      2、当0=N<M时,最大和的一段以A(0)开始

      3、当0<N时,A(0)和最大和一段没有什么关系。

      假设数组有N个元素,分别为A(0),A(1),……,A(N-1)

      并且我还知道从A(1)到A(N-1)的最大和为All(1),从A(1)到A(N-1)中包含A(1)的最大和为Start(1)

      那么,从A(0)到A(N-1)的最大和All(0)就一定有下面的关系式:

      All(0)=Max{A(0),A(0)+Start(1),All(1)}

      而Start(0)有如下的关系式:

      Start(0)=Max{A(0),A(0)+Start(1)}

      看了上面的分析,将N个元素的问题就转化为了N-1个元素的问题。这是我想到了递推。(书上以及很多其他的博客说是动态规划,我没有理解,个人比较愚钝)

      将上面的式子整理一下,建立好递推关系:

      Start(i)=Max{A(i),A(i)+Start(i+1)}

      All(i)=Max{Start(i),All(i+1)}

      代码如下:

      Public Function Max(ByVal X As Integer, ByVal Y As Integer) As Integer
        Return IIf(X > Y, X, Y)
      End Function

      Public Function MaxSum3() As Integer
        Dim i As Integer, Start() As Integer, All() As Integer
        ReDim Start(A.GetUpperBound(0))
        ReDim All(A.GetUpperBound(0))

        Start(A.GetUpperBound(0)) = A(A.GetUpperBound(0))
        All(A.GetUpperBound(0)) = A(A.GetUpperBound(0))

        For i = A.GetUpperBound(0) - 1 To 0 Step -1
          Start(i) = Max(A(i), A(i) + Start(i + 1))
          All(i) = Max(Start(i), All(i + 1))
        Next

        Return All(0)
      End Function

      这个算法的效率很高,算法复杂度为O(N),但是引用了两个数组。仔细观察两个数组的使用情况,发现其实只要使用两个变量就完全可以了,下面是改进的代码。

      Public Function Max(ByVal X As Integer, ByVal Y As Integer) As Integer
        Return IIf(X > Y, X, Y)
      End Function

      Public Function MaxSum4() As Integer
        Dim i As Integer, Start As Integer, All As Integer
        Start = A(A.GetUpperBound(0))
        All = A(A.GetUpperBound(0))
        For i = A.GetUpperBound(0) - 1 To 0 Step -1
          Start = Max(A(i), A(i) + Start)
          All = Max(Start, All)
        Next
        Return All
      End Function

      将上面的代码,仔细分析一下可以发现:

      Start=Max(A(i),A(i)+Start)

      可以改写为:

      If Start<0 Then

        Start=A(i)

      Else

        Start=A(i)+Start

      End If

      继而可以改写为

      If Start<0 Then Start=0

      Start=A(i)+Start

      而All = Max(Start, All)可以改写为

      If Start>All Then All=Start

      故上面的代码,可以改写为一个函数,减少系统的开销

     

      Public Function MaxSum5() As Integer
        Dim i As Integer, Start As Integer, All As Integer
        Start = A(A.GetUpperBound(0))
        All = A(A.GetUpperBound(0))

        For i = A.GetUpperBound(0) - 1 To 0 Step -1
          If Start < 0 Then Start = 0
          Start += A(i)

          If Start > All Then All = Start
        Next
        Return All
      End Function


      至此,代码效率高,又简洁明了。唯一的缺憾是从数组的最后一个倒推,下面的代码改成正推

      Public Function MaxSum6() As Integer
        Dim i As Integer, Start As Integer, All As Integer
        Start = A(0)
        All = A(0)

        For i = 1 To A.GetUpperBound(0)
          If Start < 0 Then Start = 0
          Start += A(i)

          If Start > All Then All = Start
        Next

        Return All
      End Function

      以上的推导过程就是为了求出一个最大和,没有求出具体的下标。关于下标的计算,留待后文详述。

      代码格式修正于2012年1月6日

  • 相关阅读:
    springboot CRUD+分页(基于JPA规范)
    springboot中yml配置文件
    springboot中配置切换
    springboot中修改端口和上下文路径
    springboot中全局异常处理器
    springboot热部署
    新的表格展示利器 Bootstrap Table Ⅰ
    关于html转换为pdf案例的一些测试与思考
    java设计模式 策略模式Strategy
    java设计模式 模板方法模式Template Method
  • 原文地址:https://www.cnblogs.com/grenet/p/1670208.html
Copyright © 2011-2022 走看看