python-动态规划
题目1. 最长递增序列-动态规划(即,找出一个给定序列中最长的递增序列?)
# 动态规划 ''' 一般思路: 1. 穷举法/暴力搜索; 2. 记忆化搜索,剪枝 ''' # TODO 1. 暴力破解 def find_max_len1(nums, i): ''' 暴力破解:找出最长递增序列: L(i) 从i开始的子序列长度: L(0) -> L(1) -> L(2) -> L(3) -> L(4) # 最坏 L(1) -> L(2) -> L(3) -> L(4) L(2) -> L(3) -> L(4) L(3) -> L(4) L(4) :param nums: :param i: 当前从第i个开始找 :return: 从i开始找的最大长度 ''' if i == len(nums) - 1: return 1 max_len = 1 for j in range(i + 1, len(nums)): if nums[i] < nums[j]: # 最大长度 = max(当前最大长度, 后续最大长度(find_max_len(nums, j))和自身(1)) max_len = max(max_len, find_max_len1(nums, j) + 1) return max_len def length_of1(nums): ''' 遍历数组,找出从锁有i开始后的递增序列长度 :param nums: :return: ''' return max([find_max_len1(nums, i) for i in range(len(nums))]) # TODO 2. 暴力破解+剪枝 def find_max_len2(nums, i): ''' 避免重复节点的计算:找出最长递增序列: 动态规划就是通过避免重复节点的计算,加速计算的过程,用到字典或者哈希表保留计算的中间结果,也称为记忆化搜索。即空间换时间,带备忘录的递归,递归树的剪枝 :param nums: :param i: 当前从第i个开始找 :return: 从i开始找的最大长度 ''' if i in memo: return memo[i] if i == len(nums) - 1: return 1 max_len = 1 for j in range(i + 1, len(nums)): if nums[i] < nums[j]: # 最大长度 = max(当前最大长度, 后续最大长度(find_max_len(nums, j))和自身(1)) max_len = max(max_len, find_max_len2(nums, j) + 1) memo[i] = max_len return max_len def length_of2(nums): ''' 遍历数组,找出从锁有i开始后的递增序列长度 :param nums: :return: ''' return max([find_max_len2(nums, i) for i in range(len(nums))]) # TODO 3. 动态规划 def length_of3(nums): ''' 动态规划: 从后往前算(这里的L是find_max_len函数) L(0) = max(L(1), L(2), L(3), L(4)) + 1 L(1) = max(L(2), L(3), L(4)) + 1 L(2) = max(L(3), L(4)) + 1 L(3) = max(L(4)) + 1 L(4) = 1 :param nums: :param i: 当前从第i个开始找 :return: 从i开始找的最大长度 ''' n = len(nums) l = [1] * n for i in reversed(range(n - 1)): # 3, 2, 1, 0 for j in range(i + 1, n): # print(i, j) if nums[j] > nums[i]: l[i] = max(l[i], l[j] + 1) # print(l) return max(l) if __name__ == '__main__': x = [1, 5, 2, 4, 3] memo = {} print(length_of1(x)) print(length_of2(x)) print(length_of3(x))
题目2. 青蛙跳(可以跳1 2 级),问有多少跳的方案?
# 青蛙跳 ''' 青蛙跳台阶: 首先,当只有一级台阶时,毫无疑问,只有一种跳法。其次,当有两级台阶时,就是两种跳法 那么,三级台阶时,应该两种情况 1、若青蛙先跳一级台阶,接下来就有两种跳法,要么一级一级地跳,要么直接就跳上两级 2. 若青蛙先跳两级台阶,接下来只能在再跳一级台阶(也可以先1后2) 所以当有三级台阶时,一共有3种跳法 那么,一共有4级台阶时,一共有多少种跳法呢?我们不妨列举一下 1.青蛙先跳一级台阶,接下来他就会还有3级台阶要去跳,而这3级台阶不就是上面3级台阶的重复吗!所以此时一共有3种跳法 2.青蛙先跳2级台阶,接下来他还有2级台阶要跳,此处也可以使用之前得出的2级台阶的结果,所以此时一共有2种跳法 所以当青蛙要跳4级台阶时,其实就是跳3级台阶的跳法加上跳2级台阶的跳法 总结:事实上,跳n级台阶的跳法就是跳n-1级台阶的跳法加上n跳-2级台阶的跳法,而这就可以使用递归的方法来解决 ———————————————— 版权声明:本文为CSDN博主「fiance111」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/m0_60354608/article/details/123964767 ''' def jump_floor(n: int) -> int: ''' 递归做法 :param n: :return: ''' if n == 1: return 1 elif n == 2: return 2 else: return jump_floor(n - 1) + jump_floor(n - 2) def jump_floor_v1(n: int) -> int: ''' 动态规划版本: eg: F(5) = F(4) + F(3) F(4) = F(3) + F(2) F(3) = F(2) + F(1) # 发现F(2)重复计算; 我们直接从后往前来 :param n: :return: ''' if n == 1: return 1 elif n == 2: return 2 dp = [1, 2] # n = 1, n = 2 for i in range(2, n): dp.append(dp[i - 1] + dp[i - 2]) return dp[-1] if __name__ == '__main__': print(jump_floor(3)) print(jump_floor_v1(3))