代码随想录算法训练营Day40 | 343.整数拆分、96.不同的二叉搜索树

343.整数拆分

(初见甚至看不出为什么这题是动规)

本题大体思路是一个数可以被拆成两个或更多的数,而该数的最大乘积能由其拆成的数递推得到

注意点主要在于理解dp数组的定义

1、DP数组定义:一维数组,dp[i]表示 n = i 时,经过拆分能得到的最大乘积,注意dp[i]表示的乘积必定是“经过拆分”得到的,所以使用dp[i]进行递推时就默认i被拆成了两个或更多的数

2、DP数组初始化:0与1无法被拆分,所以仅初始化dp[2] = 1

3、递推公式:递推计算dp[i]。对于每一个i,遍历一个j,则:
        · j * (i - j) 表示将i拆成两个值的乘积
        · j * dp[i - j] 表示将i拆成三个及以上值的乘积(注意dp数组的定义)

        对于每个j,取以上两者的较大值,dp[i]取整个遍历过程中的最大值

int integerBreak(int n) {
	// dp[i]表示 n = i 时,经过拆分能得到的最大乘积
	vector<int> dp(n + 1, 0);
	dp[2] = 1;

	for (int i = 3; i < n + 1; ++i) {
		for (int j = 1; j <= i/2; ++j) {
			// 在遍历过程中,dp[i]不断更新为最大值
			dp[i] = std::max(dp[i], std::max(j * (i - j), j * dp[i - j]));
		}
	}
	return dp[n];
}

96.不同的二叉搜索树

这题自己有一点思路,想的是在 i - 1 个节点的基础上再插入一个节点,得到 i 个节点的答案。写起来有些繁琐了,主要麻烦在递推公式方面

1、DP数组定义:一维数组,dp[i]由i个节点能构成的二叉搜索树种类

2、DP数组初始化:只需要初始化dp[0] = 1,空节点只能构成一种二叉搜索树(即空树)

3、递推公式

思路:将最新的一个节点插入 i - 1 个节点的二叉搜索树中,由于新节点的数值最大,所以只能插入在根节点或右子树上
        · 插在根节点上:右子树是由i - 1个节点构成的二叉搜索树

                设定dp[i]的初始值为dp[i - 1],即dp[i] = dp[i - 1]
        · 插在右子树上:插入后总共i个节点,右子树有j+1个节点,左子树有i - 2 - j个节点

                遍历一个 j ,对于每个j,右子树有dp[j + 1]种可能,左子树有dp[i - 2-  j]种可能,所以对于每个j,dp[i] += dp[j + 1] * dp[i - j - 2]

int numTrees(int n) {
	// dp[i]表示由i个节点能构成的二叉搜索树种类
	vector<int> dp(n + 1, 0);
	// 只需要初始化dp[0],空节点只能构成一种二叉搜索树
	dp[0] = 1;

	for (int i = 1; i <= n; ++i) {
		// 插在根节点上
		dp[i] = dp[i - 1];
		// 插在右子树上
		for (int j = 0; j < i - 1; ++j) {
			dp[i] += dp[j + 1] * dp[i - j - 2];
		}
	}
	return dp[n];
}

 自己的思路其实想复杂了,实际只要分右子树j,左子树i - 1 - j即可。DP数组的定义与初始化与自己思路相同

递推公式:对于每个i,遍历一个j,j表示右子树节点数量,那么左子树节点数量为i - j - 1,则:dp[i] += dp[j] * dp[i - j - 1]

int numTrees(int n) {
	vector<int> dp(n + 1, 0);
	dp[0] = 1;

	for (int i = 1; i <= n; ++i) {
		for (int j = 0; j <= i - 1; ++j) {
			dp[i] += dp[j] * dp[i - j - 1];
		}
	}
	return dp[n];
}

总结

前几天的动规题感觉主要是“状态的转移”,考虑的是当前状态如何由之前的状态变化得到,如

        不同路径:当前节点由其上方或左方格子向下/右走得到

        爬楼梯:当前楼层由其前一层或两层跳跃得到

这类问题的遍历维度和题目维度一致,爬楼梯是一维的那么就遍历一维,走格子是二维的那么就遍历二维的。


而今天的题感觉主要是“拆”,考虑的是当前的状态如何拆分得到之前的状态,如

        整数拆分:一个数可以拆分为多个数使得其乘积最大

        不同的二叉树搜索树:一个树可以拆分为左右两个子树

这类问题除了遍历题目中的维度,还得多遍历一维来探索所有的拆分方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值