动态规划三要素:

最优子结构:子问题 会影响 父问题的最优解

  // 注意子问题影响,而不是子问题的解影响,

  // 当然有些问题是子问题的解影响父问题的解,我想说的是不全是解和解得关系,子问题的最优解和父问题的最优解可能毫无关系

状态转移:根据子问题 如何推出 父问题的解,递推关系式

边界问题:最小子问题的解是否已知

 

爬楼梯

'''
假设你正在爬楼梯。需要 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 阶

分析:
假定n=10,首先考虑最后一步的情况,要么从第九级台阶再走一级到第十级,要么从第八级台阶走两级到第十级,因而,要想到达第十级台阶,最后一步一定是从第八级或者第九级台阶开始.也就是说已知从地面到第八级台阶一共有X种走法,从地面到第九级台阶一共有Y种走法,那么从地面到第十级台阶一共有X+Y种走法.
即F(10)=F(9)+F(8)
     分析到这里,动态规划的三要素出来了.
        边界:F(1)=1,F(2)=2
        最优子结构:F(10)的最优子结构即F(9)和F(8)
        状态转移函数:F(n)=F(n-1)+F(n-2)
'''


class Solution(object):
    def climbStairs(self, n):
        """
        :type n: int
        :rtype: int
        """

        if n<=2:
            return n
        a=1 #边界
        b=2 #边界
        temp=0
        for i in range(3,n+1):
            temp=a+b    #状态转移
            a=b #最优子结构
            b=temp  #最优子结构
        return temp


print(Solution().climbStairs(10))

 

小偷偷东西

'''
一个小偷准备挨家挨户进行偷窃,每一家都有一些能偷到的金额值,但是不能连续进入相邻的两间房屋,否则会被发现。
将这个设定抽象成一个数组,每家拥有的金额组成一个非负的整型数组,在不被发现的情况下,计算小偷能偷到的最大数额。
例如[1,2,5,3,4,8,2],那么最大值就是:第一家(1)+第三家(5)+第六家(8)=14.

最优子结构:最后一家偷不偷,偷则加上前两位的最大值,不偷则是前一位的最大值
边界:d[0]=nums[0], d[1]=max(nums[0], nums[1])
状态转移函数:d[i]=max(d[i-1], d[i-2]+nums[i])
'''


class Solution(object):
    def rob(self, nums):
        if len(nums)==0:
            return 0
        if len(nums)<=2:
            return max(nums)
        dp = []
        dp.append(nums[0])
        dp.append(max(nums[0], nums[1]))
        for i in range(2, len(nums)):
            dp.append(max(dp[i-1], dp[i-2]+nums[i]))
        return dp[-1]


if __name__ == '__main__':
    nums = [1,2,5,3,4,8,2]
    print(Solution().rob(nums))

 

最小花费爬楼梯

'''
数组的每个下标作为一个阶梯,第 i 个阶梯对应着一个非负数的体力花费值 cost[i](下标从 0 开始)。
每当你爬上一个阶梯你都要花费对应的体力值,一旦支付了相应的体力值,你就可以选择向上爬一个阶梯或者爬两个阶梯。
请你找出达到楼层顶部的最低花费。在开始时,你可以选择从下标为 0 或 1 的元素作为初始阶梯。

最优子结构:f(9)和f(8)
边界:f(0)=1, f(1)=100
递推式:f(10)=min(f(9)+cost(9), f(8)+cost(8))
'''


class Solution(object):
    def minCostClimbingStairs(self, cost):
        if len(cost) <= 1:
            return min(cost)
        dp = []
        dp.append(cost[0])
        dp.append(cost[1])
        for i in range(2, len(cost)+1):
            if i==len(cost):
                dp.append(min(dp[i-1], dp[i-2]))
            else:
                dp.append(min(dp[i-1]+cost[i], dp[i-2]+cost[i]))
        return dp[-1]

 

最大和子序列

这个问题还是挺难的,很多教程并没有 彻彻底底 讲清楚逻辑,我思考了很久才得出下图

'''
给定一个整数数组 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]
nums = [-2, -1, -3, 4, -1, 2, 1, -5, 4]
dp = [-2, 1, -2, 4, 3, 5, 6, 1, 5]
# nums = [-2, 1, -3]
# nums = [1, -5, 2]


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])
            print(d)
            if max_ < d[i]:
                max_ = d[i]
        return max_


print(Solution().maxSubArray(nums))

下面是我一个学生写的,也挺巧妙

def max_arr(a):
    max_v = 0
    for i in range(1, len(a)):
        if a[i - 1] > 0:
            a[i] += a[i-1]
        max_v = max(max_v, a[i])
    return max_v

 

 

 

 

参考资料: