算法复习——动态规划篇之最大子数组问题

以下内容主要参考中国大学MOOC

《算法设计与分析》

,墙裂推荐希望入门算法的童鞋学习!



1. 问题背景

在这里插入图片描述


子数组

:数组中

连续

的一段序列,例如



X

[

3..7

]

X[3..7]






X


[


3


.


.


7


]






子数组和

:子数组中元素的求和,



X

[

3..7

]

X[3..7]






X


[


3


.


.


7


]





的和就是



3

+

5

4

+

3

+

2

=

9

3+5-4+3+2=9






3




+








5













4




+








3




+








2




=








9





​ 那么,问题就是如何寻找数组



X

X






X





中最大的非空子数组?



2. 问题定义


最大子数组问题(Max Continuous Subarray)

输入:

  • 给定一个数组



    X

    [

    1..

    n

    ]

    X[1..n]






    X


    [


    1


    .


    .


    n


    ]





    ,对于任意一对数组下标为



    l

    ,

    r

    (

    l

    r

    )

    l, r(l \leq r)






    l


    ,




    r


    (


    l













    r


    )





    的非空子数组,其和记为



    S

    (

    l

    ,

    r

    )

    =

    i

    =

    l

    r

    X

    [

    i

    ]

    S(l, r)=\sum_{i=l}^{r}X[i]






    S


    (


    l


    ,




    r


    )




    =





















    i


    =


    l










    r





















    X


    [


    i


    ]




输出:

  • 求出



    S

    (

    l

    ,

    r

    )

    S(l, r)






    S


    (


    l


    ,




    r


    )





    的最大值,记为



    S

    m

    a

    x

    S_{max}







    S











    m


    a


    x























3. 枚举过程分析

​ 如果使用暴力枚举的话,需要两层枚举:

  • 第一层:枚举位置



    i

    i






    i





    作为区间开头;

  • 第二层:枚举位置



    j

    j






    j





    作为区间结尾。

​ 如果想要降低时间复杂度,就需要从两层枚举中舍弃掉一层。

​ 我们可以定义一个记号



D

i

D_{i}







D











i






















,表示以



X

[

i

]

X[i]






X


[


i


]





开头的最大子数组,因此只要枚举出所有的



D

i

D_{i}







D











i






















,就得到了最大子数组。先看一个案例。

在这里插入图片描述



4. 规律



4.1 规律观察

  • 结尾位置相同




    • D

      1

      D_{1}







      D











      1






















      ,



      D

      2

      D_{2}







      D











      2






















      ,



      D

      3

      D_{3}







      D











      3
























      • D

        2

        =

        X

        [

        2

        ]

        +

        D

        1

        D_{2}=X[2]+D_{1}







        D











        2





















        =








        X


        [


        2


        ]




        +









        D











        1
























      • D

        1

        =

        X

        [

        1

        ]

        +

        D

        2

        D_{1}=X[1]+D_{2}







        D











        1





















        =








        X


        [


        1


        ]




        +









        D











        2





















  • 结尾位置不同




    • D

      3

      ,

      D

      4

      D_{3}, D_{4}







      D











      3



















      ,





      D











      4
























      • D

        3

        =

        X

        [

        3

        ]

        D_{3}=X[3]







        D











        3





















        =








        X


        [


        3


        ]







      • D

        4

        <

        0

        D_{4} < 0







        D











        4





















        <








        0




      • 按照结尾位置相同的规律,



        D

        3

        D_{3}







        D











        3






















        应该等于



        X

        [

        3

        ]

        X[3]






        X


        [


        3


        ]









        D

        4

        D_{4}







        D











        4






















        ,但是



        D

        4

        D_{4}







        D











        4






















        小于0,还不如直接等于



        X

        [

        3

        ]

        X[3]






        X


        [


        3


        ]





        效果好



4.2 规律描述

​ 设



D

i

D_{i}







D











i






















为以



X

[

i

]

X[i]






X


[


i


]





开头的最大子数组和。

  • 情况1:设



    D

    i

    +

    1

    >

    0

    D_{i+1} > 0







    D











    i


    +


    1





















    >








    0





    时,



    D

    i

    =

    X

    [

    i

    ]

    +

    D

    i

    +

    1

    D_{i}=X[i]+D_{i+1}







    D











    i





















    =








    X


    [


    i


    ]




    +









    D











    i


    +


    1





















  • 情况2:设



    D

    i

    +

    1

    0

    D_{i+1} \leq 0







    D











    i


    +


    1






























    0





    时,



    D

    i

    =

    X

    [

    i

    ]

    D_{i}=X[i]







    D











    i





















    =








    X


    [


    i


    ]






4.3 规律证明

  • 情况1:




    • D

      i

      +

      1

      D_{i+1}







      D











      i


      +


      1






















      :以



      X

      [

      i

      +

      1

      ]

      X[i+1]






      X


      [


      i




      +








      1


      ]





      开头的

      最大

      子数组和(



      D

      i

      +

      1

      >

      0

      D_{i+1} > 0







      D











      i


      +


      1





















      >








      0








    • S

      i

      +

      1

      S_{i+1}







      S











      i


      +


      1






















      :以



      X

      [

      i

      +

      1

      ]

      X[i+1]






      X


      [


      i




      +








      1


      ]





      开头的

      任一

      子数组和(



      S

      i

      +

      1

      D

      i

      +

      1

      S_{i+1} \leq D_{i+1}







      S











      i


      +


      1































      D











      i


      +


      1






















    • 显然



      X

      [

      i

      ]

      +

      D

      i

      +

      1

      X

      [

      i

      ]

      +

      S

      i

      +

      1

      X[i]+D_{i+1} \geq X[i]+S_{i+1}






      X


      [


      i


      ]




      +









      D











      i


      +


      1






























      X


      [


      i


      ]




      +









      S











      i


      +


      1






















      ,因此



      D

      i

      =

      X

      [

      i

      ]

      +

      D

      i

      +

      1

      D_{i}=X[i]+D_{i+1}







      D











      i





















      =








      X


      [


      i


      ]




      +









      D











      i


      +


      1





















    • 所以第一种情况成立
  • 情况2:




    • D

      i

      +

      1

      D_{i+1}







      D











      i


      +


      1






















      :以



      X

      [

      i

      +

      1

      ]

      X[i+1]






      X


      [


      i




      +








      1


      ]





      开头的

      最大

      子数组和(



      D

      i

      +

      1

      0

      D_{i+1} \leq 0







      D











      i


      +


      1






























      0








    • S

      i

      +

      1

      S_{i+1}







      S











      i


      +


      1






















      :以



      X

      [

      i

      +

      1

      ]

      X[i+1]






      X


      [


      i




      +








      1


      ]





      开头的

      任一

      子数组和(



      S

      i

      +

      1

      D

      i

      +

      1

      S_{i+1} \leq D_{i+1}







      S











      i


      +


      1































      D











      i


      +


      1






















    • 显然



      X

      [

      i

      ]

      +

      S

      i

      +

      1

      X

      [

      i

      ]

      +

      D

      i

      +

      1

      X

      [

      i

      ]

      X[i]+S_{i+1} \leq X[i]+D_{i+1} \leq X[i]






      X


      [


      i


      ]




      +









      S











      i


      +


      1






























      X


      [


      i


      ]




      +









      D











      i


      +


      1






























      X


      [


      i


      ]





      ,因此



      D

      i

      =

      X

      [

      i

      ]

      D_{i}=X[i]







      D











      i





















      =








      X


      [


      i


      ]




    • 所以第二种情况成立



5. 动态规划



5.1 问题结构分析

  • 给出问题表示:




    • D

      [

      i

      ]

      D[i]






      D


      [


      i


      ]





      :以



      X

      [

      i

      ]

      X[i]






      X


      [


      i


      ]





      开头的最大子数组和

  • 明确原始问题




    • S

      m

      a

      x

      =

      m

      a

      x

      1

      i

      n

      {

      D

      [

      i

      ]

      }

      S_{max}=max_{1 \leq i \leq n}\{D[i]\}







      S











      m


      a


      x





















      =








      m


      a



      x











      1





      i





      n



















      {



      D


      [


      i


      ]


      }






5.2 递推关系建立



5.2.1 分析最优(子)结构




  • D

    [

    i

    ]

    D[i]






    D


    [


    i


    ]





    :以



    X

    [

    i

    ]

    X[i]






    X


    [


    i


    ]





    开头的最大子数组和

  • 情况1:当



    D

    [

    i

    +

    1

    ]

    >

    0

    D[i+1]>0






    D


    [


    i




    +








    1


    ]




    >








    0





    时,



    D

    [

    i

    ]

    =

    X

    [

    i

    ]

    +

    D

    [

    i

    +

    1

    ]

    D[i]=X[i]+D[i+1]






    D


    [


    i


    ]




    =








    X


    [


    i


    ]




    +








    D


    [


    i




    +








    1


    ]




  • 情况2:当



    D

    [

    i

    +

    1

    ]

    0

    D[i+1] \leq 0






    D


    [


    i




    +








    1


    ]













    0





    时,



    D

    [

    i

    ]

    =

    X

    [

    i

    ]

    D[i]=X[i]






    D


    [


    i


    ]




    =








    X


    [


    i


    ]




  • 分析递推关系,我们可以发现在情况一中,



    D

    [

    i

    ]

    D[i]






    D


    [


    i


    ]





    是依赖于



    D

    [

    i

    +

    1

    ]

    D[i+1]






    D


    [


    i




    +








    1


    ]





    的,



    D

    [

    i

    ]

    D[i]






    D


    [


    i


    ]









    D

    [

    i

    +

    1

    ]

    D[i+1]






    D


    [


    i




    +








    1


    ]





    都是最大数组和,只不过



    D

    [

    i

    +

    1

    ]

    D[i+1]






    D


    [


    i




    +








    1


    ]





    的规模比



    D

    [

    i

    ]

    D[i]






    D


    [


    i


    ]





    小,所以大规模问题的最优解是依赖于小规模问题的最优解的,这就满足了动态规划

    最优子结构

    的性质。



5.2.2 构造递推公式





D

[

i

]

=

{

X

[

i

]

+

D

[

i

+

1

]

,

i

f

 

D

[

i

+

1

]

>

0

X

[

i

]

,

i

f

 

D

[

i

+

1

]

0

D[i]=\left\{ \begin{array}{rcl} X[i]+D[i+1], & & {if\ D[i+1] > 0}\\ X[i], & & {if\ D[i+1] \leq 0}\\ \end{array} \right.






D


[


i


]




=










{
















X


[


i


]




+




D


[


i




+




1


]


,








X


[


i


]


,































































i


f




D


[


i




+




1


]




>




0










i


f




D


[


i




+




1


]









0






























5.3 自底向上计算

  • 初始化:



    D

    [

    n

    ]

    =

    X

    [

    n

    ]

    D[n]=X[n]






    D


    [


    n


    ]




    =








    X


    [


    n


    ]




  • 递推公式:





    D

    [

    i

    ]

    =

    {

    X

    [

    i

    ]

    +

    D

    [

    i

    +

    1

    ]

    ,

    i

    f

     

    D

    [

    i

    +

    1

    ]

    >

    0

    X

    [

    i

    ]

    ,

    i

    f

     

    D

    [

    i

    +

    1

    ]

    0

    D[i]=\left\{ \begin{array}{rcl} X[i]+D[i+1], & & {if\ D[i+1] > 0}\\ X[i], & & {if\ D[i+1] \leq 0}\\ \end{array} \right.






    D


    [


    i


    ]




    =










    {
















    X


    [


    i


    ]




    +




    D


    [


    i




    +




    1


    ]


    ,








    X


    [


    i


    ]


    ,































































    i


    f




    D


    [


    i




    +




    1


    ]




    >




    0










    i


    f




    D


    [


    i




    +




    1


    ]









    0




























在这里插入图片描述



5.4 最优方案追踪



5.4.1 记录决策过程

  • 构造追踪数组



    R

    e

    c

    [

    1..

    n

    ]

    Rec[1..n]






    R


    e


    c


    [


    1


    .


    .


    n


    ]









    R

    e

    c

    [

    i

    ]

    Rec[i]






    R


    e


    c


    [


    i


    ]





    记录以



    X

    [

    i

    ]

    X[i]






    X


    [


    i


    ]





    开头的最大子数组的结尾是第几位

    • 情况1:结尾相同




      • R

        e

        c

        [

        i

        ]

        =

        R

        e

        c

        [

        i

        +

        1

        ]

        Rec[i]=Rec[i+1]






        R


        e


        c


        [


        i


        ]




        =








        R


        e


        c


        [


        i




        +








        1


        ]




    • 情况2:结尾不同




      • R

        e

        c

        [

        i

        ]

        =

        i

        Rec[i]=i






        R


        e


        c


        [


        i


        ]




        =








        i






5.4.2 输出最优方案

  • 从子问题中查找最优解
  • 最大子数组开头位置



    i

    i






    i





    ,结尾位置



    R

    e

    c

    [

    i

    ]

    Rec[i]






    R


    e


    c


    [


    i


    ]






6. 伪代码


Max-Continuous-Subarray-DP(X, n)

输入:数组X,数组长度n

输出:最大子数组和S_max,子数组起止位置l,r

// 初始化
D[n] ← X[n]
Rec[n] ← n
// 动态规划
for i ← n-1 to 1 do
	if D[i+1] > 0 then
		D[i] ← X[i] + D[i+1]
		Rec[i] ← Rec[i+1]
	end
	else
		D[i] ← X[i]
		Rec[i] ← i
	end
end
// 查找解
S_max ← D[1]
for i ← 2 to n do
	if S_max < D[i] then
		S_max ← D[i]
		l ← i
		r ← Rec[i]
	end
end
return S_max, l, r

​ 该算法的时间复杂度是



O

(

n

)

O(n)






O


(


n


)







版权声明:本文为NickHan_cs原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/NickHan_cs/article/details/111714424