动态规划Ⅰ
Posted oldby
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划Ⅰ相关的知识,希望对你有一定的参考价值。
动态规划 Dynamic Programming
• 拆分(Divide): 将一个复杂问题拆分成一系列的简单子问题,每一次解决一个子
问题并将其结果存储起来。理想情况下用基于内存的数据结构。
• 查找(lookup):在下一次遇到相同的子问题的时候,直接查找之前计算过的结果
而不是重新计算。理想情况下,使用这种方法可以以适当的增大内存占用为代价节
省计算时间。
• 存贮子问题的答案以避免从新计算的技术叫做 memorization(记忆化)
• 分治法:把问题拆分成若干独立子问题,解决每个子问题之后合并子问题的结果作
为原始问题的结果。
• Top-Down
• 动态规划:将问题拆分成一些列重复的子问题以得到越来越大的子问题的答案
• Bottom
经典DP问题:
• 斐波那契数列(Fibonacci):: f(n) = f(n-1)+f(n-2),
where f(1)=1, f(2)=1
• 汉诺塔(Hanoi Tower)
• 子序列的最大和
例一:问题描述:给定n,找到不同的将n写成1,3,4相加的方法
def coin(n): dp = [0] * (n + 1) dp[0] = dp[1] = dp[2] = 1 dp[3] = 2 for i in range(4, n + 1): dp[i] = dp[i - 1] + dp[i - 3] + dp[i - 4] return dp[n]
例二:入室抢劫
问题描述:
假设你是一个职业抢劫犯,你打算洗劫一个街道。每一个房子里有一
定数量的钱,限制你的唯一条件是相邻的房子的安保系统是相连的,
如果你抢劫相邻的房子那么安保系统就会惊动警察。
? 给定一个非负整数的列表代表每个房子当中的钱,计算在不惊动警察
的情况下你可以抢劫到的最多的钱
def rob(nums): n = len(nums) dp = [ [0] * 2 for _ in range(n + 1)] for i in range(1, n + 1): dp[i][0] = max(dp[i - 1][0], dp[i - 1][1]) # forget it dp[i][1] = nums[i - 1] + dp[i - 1][0] # let‘s do it return max(dp[n][0], dp[n][1])
优化空间到O(1)
def rob(nums): yes, no = 0, 0 for i in nums: no, yes = max(no, yes), i + no return max(no, yes)
例三:入室抢劫Ⅱ
进阶问题:
? 该街道的所有房子是圆形排列的。也就是说第一家和最后一家也是邻
居。安保系统的设置同上问题
def rob(nums): def rob(nums): yes, no = 0, 0 for i in nums: no, yes = max(no, yes), i + no return max(no, yes) return max(rob(nums[len(nums) != 1:]), rob(nums[:-1]))
例四:组织聚会
? 你的公司在组织一个公司的年会。你们公司的组织形式非常严格,如
:一个以主席为根的树状结构。现在这个聚会有一个限制:雇员和他
的直接领导不能同时受邀参加年会。你希望能够让更多的人来参与到
年会中。
进阶问题:
? 假设这是一个募款会,组织方会?前知道每个人的捐助意向,所以如
何使收到的款最大。
例五:瓷砖问题
• 假定给定一块n*2的地板,瓷砖的大小为1*2。计算需要使用的瓷砖数量。瓷
砖可以水平放置:1*2。也可以竖直放置:2*1。
def minCostClimbingStairs2(cost): dp0, dp1, dp2 = 0, 0, 0 for i in range(2, len(cost) + 1): dp2 = min(dp0 + cost[i - 2], dp1 + cost[i - 1]) dp0, dp1 = dp1, dp2 return dp2
另:
最小台阶问题
• 有一个楼梯,每次可以走1层或者2层,cost数组表示每一层所需
要花费的值。
• 你可以从第0节或者第1节台阶开始走,一旦你交了过路费,你可
以上一个台阶或者两个台阶。试计算登顶的最少花费
方法同例5
例六:解码方式
• 一段包含着A-Z的短信用一下方式进行编码:
• ‘A‘ -> 1
• ‘B‘ -> 2
• ...
• ‘Z‘ -> 26
• 给定一段编码的短信,计算解码的方式
def numDecodings(s): if s=="" or s[0]==‘0‘: return 0 dp=[1,1] for i in range(2,len(s)+1): # if it is 0, then dp[i] = 0 result = 0 if 10 <=int(s[i-2:i]) <=26: result = dp[i-2] if s[i-1] != ‘0‘: result += dp[i-1] dp.append(result) return dp[len(s)]
例七:独特二叉树搜索路径 (卡特兰数)
• 给定n,用1…n个数字来表达Binary Search Tree,问有多少种
表达方式
def numTress(n): if n <= 2: return n sol = [0] * (n + 1) sol[0] = sol[1] = 1 for i in range(2, n + 1): for left in range (0, i): sol[i] += sol[left] * sol[i - 1 - left] return sol[n]
例八:最大子序列乘积
• 找到array中的连续子序列,该子序列的乘积最大
解:需同时保存最大最小值
def maxProduct(nums): if len(nums) == 0: return 0 maximum = minimum = result = nums[0] for i in range(1, len(nums)): maximum, minimum = max(maximum * nums[i], minimum * nums[i], nums[i]), min(maximum * nums[i], minimum * nums[i], nums[i]) result = max(result, maximum) return result
以上是关于动态规划Ⅰ的主要内容,如果未能解决你的问题,请参考以下文章
详细实例说明+典型案例实现 对动态规划法进行全面分析 | C++