一.递归迷宫求解:
需要求解上图中的迷宫问题,可以使用使用递归的方式;需要考虑到的几个问题是,当乌龟依次的北南西东方向去尝试找到出口,若是遇到了墙,只能原路返回到前一个点时,要注意陷入无限递归;
这个递归问题可以由四个base case组成:
1.乌龟遇到了墙,所以无法继续向前探索了
2.乌龟又回到了原来经过的地方了,不希望它在这个位置继续探索,否则会陷入循环
3.找到了最终的出口
4.在4个方向都没能找到出口。
递归部分的代码如下:
def searchFrom(maze, startRow, startColumn):
maze.updatePosition(startRow, startColumn)
# Check for base cases:
# 1. We have run into an obstacle, return false
if maze[startRow][startColumn] == OBSTACLE :
return False
# 2. We have found a square that has already been explored
if maze[startRow][startColumn] == TRIED:
return False
# 3. Success, an outside edge not occupied by an obstacle
if maze.isExit(startRow,startColumn):
maze.updatePosition(startRow, startColumn, PART_OF_PATH)
return True
maze.updatePosition(startRow, startColumn, TRIED)
# Otherwise, use logical short circuiting to try each
# direction in turn (if needed)
found = searchFrom(maze, startRow-1, startColumn) or \
searchFrom(maze, startRow+1, startColumn) or \
searchFrom(maze, startRow, startColumn-1) or \
searchFrom(maze, startRow, startColumn+1)
if found:
maze.updatePosition(startRow, startColumn, PART_OF_PATH)
else:
maze.updatePosition(startRow, startColumn, DEAD_END)
return found
也包括了3个基本项:base case 、往base case 形式靠拢,改变了位置、调用了自身。
二、动态编程:
先使用递归实现换钱的问题,使用的贪心算法,让换出来的硬币尽可能的少:
def recMC(coinValueList,change):
minCoins = change
if change in coinValueList:
return 1
else:
for i in [c for c in coinValueList if c <= change]:
numCoins = 1 + recMC(coinValueList,change-i)
if numCoins < minCoins:
minCoins = numCoins
return minCoins
print(recMC([1,5,10,25],63))
上面的代码是实现完整的递归,存在很多的重复计算,为了简化重复计算,采用缓冲之前计算完的结果来供之后使用:
def recDC(coinValueList,change,knownResults):
minCoins = change
if change in coinValueList:
knownResults[change] = 1
return 1
elif knownResults[change] > 0:
return knownResults[change]
else:
for i in [c for c in coinValueList if c <= change]:
numCoins = 1 + recDC(coinValueList, change-i,
knownResults)
if numCoins < minCoins:
minCoins = numCoins
knownResults[change] = minCoins
return minCoins
print(recDC([1,5,10,25],63,[0]*64))
使用一个knownresult列表来缓冲计算好的结果,从而大大的降低了计算成本。
对于这个问题而言,可以使用动态编程来求解,并且时间复杂度降低了很多:
找出递推公式
假设需要换取11块钱,而有的面额是1、5、10,则最后需要换去钱的张数表为:
所以当换取11块钱时,需要的最少数量为两张。
def dpMakeChange(coinValueList,change,minCoins):
for cents in range(change+1):
coinCount = cents
for j in [c for c in coinValueList if c <= cents]:
if minCoins[cents-j] + 1 < coinCount:
coinCount = minCoins[cents-j]+1
minCoins[cents] = coinCount
return minCoins[change]
但是前面的代码中没有输出具体的每张钱的大小,需要一个列表来纪录下计算的过程。
def dpMakeChange(coinValueList,change,minCoins,coinsUsed):
for cents in range(change+1):
coinCount = cents
newCoin = 1
for j in [c for c in coinValueList if c <= cents]:
if minCoins[cents-j] + 1 < coinCount:
coinCount = minCoins[cents-j]+1
newCoin = j
minCoins[cents] = coinCount
coinsUsed[cents] = newCoin
return minCoins[change]
def printCoins(coinsUsed,change):
coin = change
while coin > 0:
thisCoin = coinsUsed[coin]
print(thisCoin)
coin = coin - thisCoin
def main():
amnt = 79
clist = [1,5,10,21,25]
coinsUsed = [0]*(amnt+1)
coinCount = [0]*(amnt+1)
print("Making change for",amnt,"requires")
print(dpMakeChange(clist,amnt,coinCount,coinsUsed),"coins")
print("They are:")
printCoins(coinsUsed,amnt)
print("The used list is as follows:")
print(coinsUsed)
main()
输出结果为:
Making change for 79 requires 6 coins They are: 1 1 10 21 21 25 The used list is as follows: [1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 10, 1, 1, 1, 1, 5, 1, 1, 1, 1, 10, 21, 1, 1, 1, 25, 1, 1, 1, 1, 5, 10, 1, 1, 1, 10, 1, 1, 1, 1, 5, 10, 21, 1, 1, 10, 21, 1, 1, 1, 25, 1, 10, 1, 1, 5, 10, 1, 1, 1, 10, 1, 10, 21, 1, 5, 10, 21, 1, 1, 10, 21, 1, 10, 1, 25, 1, 10, 1, 1]