递归与动态规划

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了递归与动态规划相关的知识,希望对你有一定的参考价值。

参考技术A 递归很简单,但是需要的时间和空间非常大。

递归的时间复杂度:解决一个子问题的时间 * 子问题的个数。

而子问题的个数可以先画递归判定树,树的节点个数也就是子问题的个数,一般是2^n。

是指数级,往往增长的很快,很容易超时。

递归可以画树,当然是自顶向下进行求解。

动态规划相比于递归更加高效。

动态规划与递归不同的是,动态规划是自底向上求解,并且保存每一个子结果。

这样就可以很大程度地对递归判定树进行剪枝,极大地减少了时空的消耗。

动态规划某种程度上可以看做是有备忘录的递归算法。

动态规划的核心思想就是 拆分子问题,记住过往,减少重复计算。

参考资料: 看一遍就理解:动态规划详解 - 云+社区 - 腾讯云

递归 动态规划

递归与动态规划

  1 # python
  2 # -*- coding: utf-8 -*-
  3 """
  4 __title__ = ‘‘
  5 __author__ = ‘wlc‘
  6 __mtime__ = ‘2017/10/14‘
  7 """
  8 import turtle
  9 
 10 """
 11 递归三定律
 12     递归算法必须有基本情况
 13     递归算法必须改变其状态向基本情况靠近
 14     递归算法必须以递归方式调用自身
 15 """
 16 
 17 
 18 def sumList(list):
 19     """
 20     program:递归求列表和
 21     :param list: list
 22     :return: sum
 23     """
 24     if len(list) == 1:
 25         return list[0]
 26     else:
 27         return list[0] + sumList(list[1:])
 28 
 29 
 30 def sysConversion(n, base):
 31     """
 32     program:递归进制转换
 33     :param n:十进制
 34     :param base:转换的进制
 35     :return: 目的进制
 36     """
 37     str = "0123456789ABCDEF"
 38     if n < base:
 39         return str[n]
 40     else:
 41         return sysConversion(n // base, base) + str[n % base]
 42 
 43 
 44 import turtle
 45 
 46 
 47 def tree(branchLen, t):
 48     """
 49     #program:递归建树
 50     :param branchLen:
 51     :param t:
 52     :return:
 53     """
 54     if branchLen > 5:
 55         t.forward(branchLen)
 56         t.right(20)
 57         tree(branchLen - 15, t)
 58         t.left(40)
 59         tree(branchLen - 15, t)
 60         t.right(20)
 61         t.backward(branchLen)
 62 
 63 
 64 def main():
 65     t = turtle.Turtle()
 66     myWin = turtle.Screen()
 67     t.left(90)
 68     t.up()
 69     t.backward(100)
 70     t.down()
 71     t.color("green")
 72     tree(75, t)
 73     myWin.exitonclick()
 74 
 75 
 76 def changeMoney(coinList, change):
 77     """
 78     program:找零钱问题(低效版本)
 79     在递归过程中计算所有出现的结果进行比较但是里面存在 太多的相同步骤
 80     26元(20 10 5 1)
 81     (1 25(XXXXX)),(5 21)(10(重复计算) 16((1 15)(5 11)(10(重复计算) 6))(20 6)
 82     因此要加入一个列表用来保存
 83 
 84     :param coinList:
 85     :param change:
 86     :return:
 87     """
 88     minNum = change
 89     # 最小的基本情况
 90     if change in coinList:
 91         return 1
 92     else:
 93         # 筛选出比change大的硬币值
 94         for x in [y for y in coinList if y <= change]:
 95             numCoin = 1 + changeMoney(coinList, change - x)
 96             if numCoin < minNum:
 97                 minNum = numCoin
 98     return minNum
 99 
100 
101 def changeMoneyUpgrade(coinList, change, memoryList):
102     """
103 
104     :param coinList: 货币表
105     :param change: 需要找的零钱
106     :param memoryList: 递归记录表(可以称之为缓存或者记忆化)
107     :return:
108     """
109     minNum = change
110     # 最小的基本情况
111     if change in coinList:
112         memoryList[change] = 1
113         return 1
114     elif memoryList[change] > 0:
115         return memoryList[change]
116     else:
117         # 筛选出比change大的硬币值
118         for x in [y for y in coinList if y <= change]:
119             numCoin = 1 + changeMoneyUpgrade(coinList, change - x, memoryList)
120             if numCoin < minNum:
121                 minNum = numCoin
122                 memoryList[change] = minNum
123     return minNum
124 
125 
126 def dynamicProgramingChangeMoney(memoryList, moneyList, change):
127     """
128     动态规划解决找零钱问题
129     :param memoryList: 记录所有小于change的最小找零数
130     :param moneyList:人民币1,2,5,10 20,50,100
131     :param change:需要找的零钱
132         change:1 2 3 4 5 6 7 8 9 10 11
133      moneyList:1 2 3 4 1 2 3 4 5 1  2
134     :return:moneyList
135     """
136     for i in range(change + 1):
137         minNum = i
138         for j in [x for x in moneyList if x <= i]:
139             if memoryList[i - j] + 1 < minNum:
140                 minNum = memoryList[i - j] + 1
141         memoryList[i] = minNum
142     return memoryList
143 
144 
145 def dynamicProgramingChangeMoneyTrace(memoryList, moneyUsedList, moneyList, change):
146     """
147     动态规划解决找零钱问题 跟踪每一个找回的零钱的币种
148     :param memoryList: 记录所有小于change的最小找零数
149     :param moneyList:人民币1,2,5,10 20,50,100
150     :param change:需要找的零钱
151     :param moneyUsedList:需要找的第一个零钱的位置 用来跟踪位置 依次追踪到所有的位置
152         change:1 2 3 4 5 6 7 8 9 10 11
153     memoryList:1 2 3 4 1 2 3 4 5 1  2
154  moneyUsedList:
155     :return:moneyList moneyUsedList
156     """
157     for i in range(change + 1):
158         minNum = i
159         newMoney = 1
160         for j in [x for x in moneyList if x <= i]:
161             if memoryList[i - j] + 1 < minNum:
162                 minNum = memoryList[i - j] + 1
163                 newMoney = j
164         memoryList[i] = minNum
165         moneyUsedList[i] = newMoney
166     return memoryList, moneyUsedList
167 
168 
169 def printChangeMoney(moneyUsedList, memoryList):
170     """
171     用来打印找零钱的具体零钱列表
172     :param moneyUsedList:
173     :param memoryList:
174     :return:
175     """
176     money = len(memoryList) - 1
177     while money > 0:
178         printValue = moneyUsedList[money]
179         print(printValue)
180         money = money - printValue
181 
182 
183 if __name__ == __main__:
184     # sum = sumList([1, 2, 3, 4])
185     # print(sum)
186     # print(sysConversion(18, 10))
187     # # main()
188     # a = [0] * 64
189     # print(len(a))
190     print(changeMoneyUpgrade([1, 5, 10,21, 25], 63, [0] * 64))
191     print(dynamicProgramingChangeMoney([0] * 64, [1, 5, 10,21, 25], 63))
192     memoryList, moneyUsedList = dynamicProgramingChangeMoneyTrace([0] * 64, [0] * 64, [1, 5, 10,21, 25], 63)
193     print(str(memoryList)+ \n, str(moneyUsedList))
194     printChangeMoney(moneyUsedList, memoryList)

 

以上是关于递归与动态规划的主要内容,如果未能解决你的问题,请参考以下文章

动态规划与递归区别

通过动画轻松理解递归与动态规划

看动画轻松理解“递归”与“动态规划”

看动画轻松理解「递归」与「动态规划」

动画:看动画轻松理解「递归」与「动态规划」

「递归」与「动态规划」看这篇就够了!