一维动态规划中的一些思考

动态规划的主要解题步骤分为三步:

  1. a.定义子问题(将固定值改成随意值)
  2. b. 定义状态数组(数组中的每一个位置代表的意义,数组中的值代表的意义)
    
  3. c. 定义状态转移方程(确定当前值与前面值的关系)
    

个人感觉能不能想到用动态规划解题,真的是随缘 哈哈哈哈

这篇文章主要看三个问题:

  1. 排列数 ——假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
    解:这个题一看,动态规划很简单。

    边界问题:

		dp[0] = 1
		dp[1] = 1
	状态转移方程:
		dp[i] = dp[i-1] + dp[i-2]
	结果:
	
	def climbStairs(self, n: int) -> int:
	    dp = [0] * (n + 1)
	    dp[0] = dp[1] = 1
	    for i in range(2, n + 1):
	        dp[i] = dp[i - 1] + dp[i - 2]
	    return dp[-1]

	简单优化
	def climbStairs(self, n: int) -> int:
	    dp = [0] * (n + 1)
	    dp[0] = dp[1] = 1
	    for i in range(2, n + 1):
	    	# 不只有1 2 还有其他值,给的是一个list时
	        for j in range(1,3):
	            dp[i] += dp[i - j]
	    return dp[-1]
  1. 组合数
    一维动态规划中的一些思考
    同理,使用动态规划:
    边界问题:
	dp[0] = 1
	状态转移方程:
		dp[i] = dp[i] + dp[i-x]
	结果:
	def change(self, amount: int, coins: list[int]) -> int:
        dp = [0] * (amount + 1)
        dp[0] = 1
        for x in coins:
            for j in range(x, amount + 1):
                dp[j] = dp[j] + dp[j - x]
        return dp[-1]
  1. 等于x的个数
    在数组nums 中选取若干元素,使得这些元素之和等于neg,计算选取元素的方案数。
    例:nums = [1,2,3,4,5] neg = 10 则选择方案一共有3种(1,2,3,4;1,4,5;2,3,5)
    使用动态规划求解:
    边界问题:
	dp[0] = 1
	状态转移方程:
		dp[i] = dp[i] + dp[i-x]
	结果:
	def change(self, amount: int, coins: list[int]) -> int:
        dp = [0] * (amount + 1)
        dp[0] = 1
        for x in coins:
            for j in range(x, amount + 1):
                dp[j] = dp[j] + dp[j - x]
        return dp[-1]

不难发现,上面三份代码,只存在微小的差别,第一份和第二份相比,双重循环的关系相反,导致结果一个是排列,一个是组合;第二份和第三份相比,内循环一个是正序,一个是倒序,导致的结果是每个数可使用n次每个数最多可使用一次的区别。

所以
要求是排列时:正序,nums位于内循环
要求是组合时:正序,nums位于外循环
要求是数字最多可使用一次时:倒序,nums位于外循环

上一篇:01背包类算法题


下一篇:如何在组件内部提交数据给vuex