python动态规划
动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法百度百科。
动态规划要点:最优子结构,边界,状态转移函数。
最优子结构:在每个阶段最优状态可以从之前某个阶段的状态直接得到
边界:最小子集的解
状态转移函数:从一个阶段向另一个阶段过渡的具体形式,描述两个相邻子问题之间关系
几个简单例子:
1.爬楼梯源于LeetCode:
假设你正在爬楼梯,需要n阶才能到达楼顶
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
如:
示例1:
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶
示例2:
输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶
-
解析:
如果给的两个示例看的不是特别清楚,你可以当阶梯为0,那么上楼梯方法0种这是必然,当阶梯只有1那么上楼梯方法只有1种: 当4个台阶: 输入:4 输出:4 1. 1阶 + 1阶 + 1阶 + 1阶 2. 2阶 + 2阶 3. 1阶 + 2阶 + 1阶 4. 2阶 + 1阶 + 1阶 5. 1阶 + 1阶 + 2阶 那么得到: 阶梯数 爬楼梯方法 0 0 1 1 2 2 3 3 4 5 ... 如果感觉看的不明显可以推理一下5阶,6阶... 可以得到当我们想爬n阶楼梯,我们可以得到: p(n-1) + p(n-2) p为爬楼梯方法
-
代码
class Solution: def climbStairs(self, n: int) -> int: num_list = [0,1,2] if n==1: return num_list[1] elif n==2: return num_list[2] else: for i in range(3,n+1): num_list.append(num_list[i-1]+num_list[i-2]) print(num_list) return num_list[n] obj = Solution() result = obj.climbStairs(10) print(result)
-
提交LeetCode只击败了12.72%的人。通过优化
class Solution: def climbStairs(self, n: int) -> int: a,b,c = 0,1,2 if n == 1: return b if n == 2: return c while n>0: c = a + b a,b = b,c n -= 1 return c obj = Solution() result = obj.climbStairs(8)
2.最子序列求和LeetCode
53. 最大子序和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
- 解析:
对于上述序列:
nums = [-2,1,-3,4,-1,2,1,-5,4],当i从0~len(nums).其对应子序列和可以得到:
dp = [-2, 1, -2, 4, 3, 5, 6, 1, 5] # dp[i]代表从0~i区间,所包含i元素的连续子数组,最大之和。
- 代码:
class Solution(object):
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
# 判断边界
if len(nums) == 0:
return 0
# 定义一个表格进行存储上一个子问题的最优解
d = []
d.append(nums[0]) # 第一个最优解为第一个元素
max_ = nums[0] # 返回的最大值
for i in range(1, len(nums)):
if nums[i] > nums[i] + d[i - 1]:
d.append(nums[i])
else:
d.append(nums[i] + d[i - 1])
if max_ < d[i]:
max_ = d[i]
print(d)
obj = Solution()
result = obj.maxSubArray([-2,1,-3,4,-1,2,1,-5,4])
print(result)
3.买卖股票的最佳时机;ettCode
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。
注意你不能在买入股票前卖出股票。
示例 1:
输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
示例 2:
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
- 解析:
定义一个变量记录买入最小金额。定义一个数组存放每天最大利润。若当天利润大于前一天利润加入数组中,若当天利润小于前一天利润,则让当天利润等于前一天利润,并加入数组中。
- 代码:
class Solution:
def maxProfit(self, prices: List[int]) -> int:
if len(prices) <= 1:
return 0
profit = [0,]
# 买入最低价格
min_v = prices[0]
for i in range(1,len(prices)):
max_profit = max(profit[i-1],prices[i]-min_v)
profit.append(max_profit)
if prices[i] < min_v:
min_v = prices[i]
return profit[-1]
obj = Solution()
res = obj.maxProfit([7,1,5,3,6,4])
print(res)