Python 数据结构与算法分析 二、递归

递归

递归三原则:

1)递归算法必须有基本情况
2)递归算法必须改变其状态并向基本情况靠近
3)递归算法必须递归地调用自己

数组求和函数的递归实现:

def listsum(numlist):
    if len(numlist) == 1:
        return numlist [0]
    else:
        return numlist[0] + listsum(numlist[1:])

将整数转换成2~16为进制基数的字符串。

def toStr(n, base):
    convertString = "0123456789"
    if n < base:
        return convertString[n]
    else:
        return toStr(n//base, base) + convertString[n%base]

使用栈帧实现递归

栈中的返回值取代了累加变量
栈帧限定了函数所用变量的作用域。尽管反复调用相同的函数,但是每次调用都会为函数的局部变量创建新的作用域。

from pythonds.basic import Stack
rStack = Stack()
def toStrnew(n, base):
    convertString = "0123456789ABCDEF"
    if n < base:
        rStack.push(convertString[n])
    else:
        rStack.push(convertString[n % base])
        toStrnew(n // base, base)

递归可视化:

用turtle模块递归地绘制螺旋线

from turtle import *
myTurtle = Turtle()
myWin = myTurtle.getscreen()

def drawSpiral(myTurtle, lineLen):
    if lineLen > 0:
        myTurtle.forward(lineLen)
        myTurtle.right(90)
        drawSpiral(myTurtle, lineLen-5)

drawSpiral(myTurtle, 200)
myWin.exitonclick()

在这里插入图片描述

绘制分形树

def tree(branchLen, t):
    if branchLen > 5:
        t.forward(branchLen)
        t.right(20)
        tree(branchLen-15, t)
        t.left(40)
        tree(branchLen-10, t)
        t.right(20)
        t.backward(branchLen)

from turtle import *
t = Turtle()
myWin = t.getscreen()
t.left(90)
t.up()
t.backward(300)
t.down()
t.color('green')
tree(110, t)
myWin.exitonclick()

在这里插入图片描述

找零问题

找零问题的暴力解决方案

首先确定基本情况: 如果要找的零钱金额与硬币面值相同,那么只需要找1枚硬币即可。
如果要找的零钱金额和硬币的面值不同,则有多种选择:
1)1枚1分硬币加上找零金额减去1分之后所需的硬币
2)1枚5分硬币加上找零金额减去5分之后所需的金币
3)1枚10分硬币加上找零金额减去10分之后所需的金币
4)1枚25分硬币加上找零金额减去25分之后所需的金币

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 - 1)
            if numCoins < minCoins:
                minCoins = numCoins
    return minCoins

这个方法执行了过多重复的步骤

添加查询表之后的找零算法

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-1, knownResults)
            if numCoins < minCoins:
                minCoins = numCoins
                knownResults[change] = minCoins
    return minCoins

动态规划算法

尽管我们一开始使用递归方法来解决找零问题,但是dpMakeChange并不是递归函数
能够用递归方法解决问题,并不代表递归方法是最好或最高效的方法。

def dpMakeChange(coinValuelist, change, minCoins):
    for cents in range(0, 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]

尽管找零算法在寻找最少硬币数时表现出色,但是由于没有记录所用的硬币,因此它并不能帮助我们进行世纪的找零工作。通过记录minCoins表中每一项所加的硬币,可以轻松扩展dpMakeChange,从而记录所用的硬币。
如果知道上一次加的硬币,便可以减去其面值,从而找到表中前一项,并通过它知晓之前所加的硬币。

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

c1 = [1,5,10,21,25]
coinsUsed = [0]*64
coinCount = [0]*64
print(dpMakeChange(c1, 63, coinCount, coinsUsed))
print(printCoins(coinsUsed, 30))
print(coinsUsed)
3
5
25
[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]

猜你喜欢

转载自blog.csdn.net/Winds_Up/article/details/113072994