如何解决动态规划问题

前言

最近在牛客上刷机试题,刚好去年考研复试刷了题,所以做起来还挺顺手的。大多数题都知道该怎么做,不会的看了题解也可以写出来。直到动态规划这部分内容,除了简单的斐波那契数列和爬楼梯外(这两道题还是用递归才AC的),其他题目是真的没有思路,能够看懂题解,但是下一道题还是不会做。于是,我上B站看视频学习,看到“代码随想录”的Carl老师讲得很详细,就在这里记录以下学习心得。

动态规划五部曲

即分析动态规划问题的五个步骤

  • 确定dp数组以及下标的含义

  • 确定递推公式

  • dp数组如何初始化

  • 确定遍历顺序

  • 打印dp数组(根据dp数组判断出错的地方)

例子

斐波那契数列、爬楼梯等简单的例子就不放这里了,放几个我觉得思路有点难想到的题目

整数拆分

给定一个正整数n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。返回可以获得的最大乘积。

示例1:

输入:2

输出:1

示例2:

输入:10

输出:36

下面开始用动态规划五部曲来分析这个问题

  • 确定dp数组及下标的含义

dp[i]表示正整数i拆分成多个正整数的最大乘积

  • 确定递推公式

dp[i]有两个来源:

  • j * (i - j),j为小于i - 1的正整数(因为后面初始化的下标为2,所以j的最大值为i - 2)

  • j * dp[i-j]

dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j]))

  • dp数组初始化

0和1不可以拆分成其他正整数,所以不管这两个

将dp[2]初始化为1,因为2只能拆为1和1,乘积为1

至于其他数,可以不初始化,递推公式会修改值

  • 确定遍历顺序

dp[i]的值一部分由下标比它小的值(dp[i - j])决定,所以遍历顺序从小到大,从i = 3开始,直到i等于输入值

  • 打印dp数组

这一步是根据dp结果来判断错误在哪儿,是递推公式有问题?初始化有问题?遍历顺序有问题?

不同的二叉搜索树

题目:96. 不同的二叉搜索树 - 力扣(LeetCode)

分析步骤:

  • dp数组及下标含义

dp[i]表示节点数为i的二叉搜索树的种数

  • 递推公式

一棵节点数为i的二叉搜索树可以看成一个根节点+左子树为(j - 1)个节点的二叉搜索树+右子树为(i - j - 1)个节点的二叉搜索树

dp[i] += dp[j - 1] * dp[i - j], j为<= i 的正整数

这里为什么是相乘,而不是相加?这就是一个排列组合问题。比如,第一组[1, 2]和第二组[3, 4]两两搭配有多少种搭配方式。第一组的“1”可以和第二组的“3”和“4”分别搭配为[1, 3]和[1, 4],第一组的“2”同理。所以是2 * 2 = 4种。

  • 初始化

j的最小值为1,根据递推公式,dp[j - 1]即dp[0]需要初始化。我们知道空节点是一种二叉搜索树,并且根据递推公式,左子树为空,二叉搜索树种数就应该等于右子树的种数,所以,dp[0]应该初始化为1

其他数可以不初始化,递推公式会修改其值

  • 遍历顺序

根据递推公式,dp[i]由下标比它小的值决定,所以从小到大,从i = 1开始遍历,直到i等于输入的n

总结

根据动态规划五部曲走,可以清楚明白地解决绝大部分的动态规划问题,有的问题的递推关系的确难以想到。下一篇文章将介绍动态规划的经典类型——背包问题,这个也是一大难点。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值