Fork me on GitHub

python算法动态规划

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)
posted @ 2020-03-29 13:19  是阿凯啊  阅读(645)  评论(0编辑  收藏  举报