动态规划法-n台阶问题

问题

有n节台阶,一次能走1步或者2步,共有多少种走法。


思路

一次只能走1步或者2步。且先走1和先走2是两种不同的走法。
我们可以发现:不管走1步还是走2步,后面的问题是一样的:走1步还是走2步?又有多少种走法?
这样,我们很容易想到递归。


递归法

思路:问题的结果 = 先走1步之后所有可能的走法数量 + 先走2步之后所有可能的走法数量
走了1步之后又是同样的解法(同上)。所以可以用递归解决。

Python代码:

def func1(n):
    n=int(n)        #将n转化为数字
    if n<=2:
        return n
    else:
        return func1(n-1)+func1(n-2)

递归产生的问题:

  1. 堆栈溢出。如果n的值非常大,那么递归的深度就会非常深,堆栈溢出,内存根本扛不住!
  2. 有冗余计算。比如n=8,走1、2和走2、1之后的计算重复了。计算了两遍func1(5)

动态规划法

动态规划法概念:

动态规划算法是通过拆分问题,定义问题状态和状态之间的关系,使得问题能够以递推(或者说分治)的方式去解决。动态规划算法的基本思想与分治法类似,也是将待求解的问题分解为若干个子问题(阶段),按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了有用的信息。在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解。依次解决各子问题,最后一个子问题就是初始问题的解。

由于动态规划解决的问题多数有重叠子问题这个特点,为减少重复计算,对每一个子问题只解一次,将其不同阶段的不同状态保存在一个二维数组中。

思路:

1.分析最优解的性质,并刻画其结构特征。
2.递归的定义最优解。
3.以自底向上或自顶向下的记忆化方式(备忘录法)计算出最优值。
4.根据计算最优值时得到的信息,构造问题的最优解。

特性:

最优化原理:如果问题的最优解所包含的子问题的解也是最优的,就称该问题具有最优子结构,即满足最优化原理。

无后效性:即某阶段状态一旦确定,就不受这个状态以后决策的影响。也就是说,某状态以后的过程不会影响以前的状态,只与当前状态有关。

有重叠子问题:即子问题之间是不独立的,一个子问题在下一阶段决策中可能被多次使用到。(该性质并不是动态规划适用的必要条件,但是如果没有这条性质,动态规划算法同其他算法相比就不具备优势)

动态规划法求解思路:

对于这个问题我们可以这样解:将所有的可能的走法记下来,后面的问题可以由前面的结果得出。
问题的结果 = 先走1步之后所有可能的走法数量 + 先走2步之后所有可能的走法数量。而且n=1和n=2的走法我们都知道,所以后面的解都可以通过这两个结果推出。

Python代码:

def func2(n):
    n=int(n)        #将n转化为数字
    if n<=2:
        return n
    list1=[0,1,2]
    for i in range(3,n+1):
        list1.append(list1[i-1]+list1[i-2])
    return list1[n]

代码分析:

我们发现没有用到了递归,而是使用列表保存下之前的结果,当前的结果是由前面的结果推出。
这样就解决了递归太深会堆栈溢出的问题。
我们还可以发现,计算n时,只用到了n-1和n-2的结果,在它们之前的结果都没有用到,所以,我们完全可以不使用数组。

不使用数组的动态规划法解决n台阶问题:

def func3(n):
    n = int(n)  # 将n转化为数字
    if n<=2:
        return n
    first=1
    second=2
    third=0
    for i in range(3,n+1):
        third=first+second
        first=second
        second=third
    return third

发布了99 篇原创文章 · 获赞 44 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/NetRookieX/article/details/102541848