算法系列-动态规划问题

一. 动态规划问题
1.1 斐波那契数列问题

1.递归解法

"""
斐波那契数列问题实现,队列如上 1 1 2 3 5 8 13........
"""

# 递归版


class Fib:

    def __init__(self):
        pass

    def fib_n(self, p):
        if p == 0:
            return 1
        elif p == 1:
            return 1
        else:
            return self.fib_n(p-1) + self.fib_n(p-2)


if __name__ == '__main__':
    obj = Fib()
    t = obj.fib_n(5)
    print(t)

2.备忘录解法
备忘录解法的就是记录之前计算过的值,保存起来,然后下一次直接拿来用

def Fib(n):
    num_list = [0] * (n+1)

    def fib(n, num_list):
        if num_list[n] > 0:
            return num_list[n]
        if n <= 1:
            num_list[n] = 1
        else:
            num_list[n] = fib(n-1, num_list) + fib(n-2, num_list)
        return num_list[n]

    return fib(n, num_list)


print(Fib(5))
1.2 钢管切割问题

钢管切割动态规划问题的核心是 n长的钢管,先分成i米以及n-i两部分 p[i],即有 r[n] = max(p[i] + r[n-i]),依次遍历求最大值, 那么最大收益s为,
s = max(s, p[i] + func(p, n-i)), 其中当n为0时, r[0] = 0

def max_value(p, n, r):
    for i in range(1, n + 1):
        if n == 0:
            return 0
        if n <= 10:
            q = 0
            for j in range(1, i + 1):
                q = max(q, p[j-1] + r[i - j])
                r[i] = q
        else:
            q = 0
            for j in range(1, i + 1):
                q = max(q, p[(j - 1) % 10] + r[i - j])
                r[i] = q
    print(r)
    return r[n]


def main():
    p = [1, 5, 8, 9, 10, 17, 17, 20, 24, 30]
    n = 8
    r_obj = {}
    for i in range(n):
        r_obj[i] = 0
    r_obj[1] = 1
    t = max_value(p, n, r_obj)
    print("最大收益为:", t)


if __name__ == '__main__':
    main()
1.3 矩阵中字母搜索问题

给定一个二维网格和一个单词,找出该单词是否存在于网格中。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
示例:
board =
[
[‘A’,‘B’,‘C’,‘E’],
[‘S’,‘F’,‘C’,‘S’],
[‘A’,‘D’,‘E’,‘E’]
]

给定 word = “ABCCED”, 返回 true.
给定 word = “SEE”, 返回 true.
给定 word = “ABCB”, 返回 false.


s = [
        ['A', 'B', 'C', 'E'],
        ['S', 'F', 'C', 'S'],
        ['A', 'D', 'E', 'E']
]

t = [
    [False, False, False, False],
    [False, False, False, False],
    [False, False, False, False]
]

word = 'ABCCED'


class Solution:
    def __init__(self):
        self.pos = list()  #
        self.n = self.m = 0  # 用来储存行和列的数目
        self.flag = False  # 用来标志最终结果
        self.l = 0  # 单词长度
        self.target = ""  # 目标要构建的单词
        self.direction = [[1, 0], [-1, 0], [0, 1], [0, -1]]  # 可以选的方向

    def search(self, board, x, y, s):
        if s == self.target:
            self.flag = True
            return  # 如果构建中的字符串达到目标要构建的单词
        if len(s) >= self.l:
            return  # 如果构建的字符的长度大了,就返回,防止无限增加
        self.pos[x][y] = True  # 把当前位置标记为已搜索,防止再次搜索。
        for d in self.direction:  # 遍历所有方向,上下左右
            if 0 <= x + d[0] <= self.n - 1 and 0 <= y + d[1] <= self.m - 1 and not self.pos[x + d[0]][y + d[1]] and \
                    board[x + d[0]][y + d[1]] == self.target[len(s)]:  # 只有当下个节点没有超过边界并且没有被访问过并且是下一个必须的组成单词的下一个字母时,我们才调用递归
                self.search(board, x + d[0], y + d[1], s + board[x + d[0]][y + d[1]])  # 构建中的单词需要加上下一个字母,同时更新位置
                if self.flag:
                    return  # 如果找到了该单词,直接返回
        self.pos[x][y] = False  # 把当前标为未访问

    def exist(self, board, word):
        self.n = len(board)  # 储存行数
        if self.n == 0:
            return False
        self.m = len(board[0])  # 储存列数
        if self.m == 0:
            return False
        self.l = len(word)  # 储存单词长度
        if self.l == 0 or self.l > self.n * self.m:
            return False  # 如果当前单词比所有字母连一起还长
        self.target = word  # 储存目标单词
        self.pos = [[False for col in range(self.m)] for row in range(self.n)]  # 构建一个检测有没有被访问的表
        for i in range(self.n):
            for j in range(self.m):
                if board[i][j] == word[0]:  # 如果当前字母等于第一个字母,开始递归
                    self.search(board, i, j, board[i][j])

        return self.flag  # 返回最终结果


if __name__ == '__main__':
    s = [
            ['A', 'B', 'C', 'E'],
            ['S', 'F', 'C', 'S'],
            ['A', 'D', 'E', 'E']
    ]
    word = 'ABCCEE'
    s_obj = Solution()
    k = s_obj.exist(s, word)
    print(k)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值