一、力扣题343. 整数拆分
给定一个正整数 n
,将其拆分为 k
个 正整数 的和( k >= 2
),并使这些整数的乘积最大化。
返回 你可以获得的最大乘积 。
示例 1:
输入: n = 2 输出: 1 解释: 2 = 1 + 1, 1 × 1 = 1。
示例 2:
输入: n = 10 输出: 36 解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
提示:
2 <= n <= 58
这道题的规律实在很难想到,我列举了1到15每个数拆分的乘积,却无法梳理出来写成代码。最后去看了题解,但题解的解法对我来说有点晦涩,最后折中写了个变化了一些的,自己能理解的解法。
题解是按把整数拆分成m个近似相同的子数相乘的思路来的,而我是按拆分成两个整数相乘的思路。
如上所示,拆分到最后,有双引号的数字不是指它原本的数值,而是指它的最大乘积。
一开始前几个数的拆分还有规律可言,到后面就没有规律了,那就直接遍历。固定把整数拆分为两个数,例如 整数为 n,将整数拆成 j 和 n - j,j 从 1 遍历到 n / 2 ,从中找到最大乘积。在遍历求出乘积时,先判断 j 和 dp[ j ] 哪个的值更大,取更大的那个,n - j 同理,最后把取出的两个更大值相乘。
1、dp数组及下标含义:数值为 i 的整数的最大乘积为 dp [ i ]。
2、递推公式:dp [ i ] = max ( dp[ i ] , max( n - j , dp [ n - j ] ) * max( j , dp [ j ] )。
3、dp数组初始化:需要初始化 dp [ 2 ] = 1,而 dp[ 1 ] 是不存在的就不设置,不影响代码结果。
4、遍历顺序:从小到大。
function integerBreak($n) {
$dp[2] = 1;
for($i = 3; $i <= $n; $i++) {
for($j = 1; $j <= intval($i / 2); $j++) {
$dp[$i] = max($dp[$i],max($dp[$i - $j], ($i - $j)) * max($dp[$j], $j));
}
}
return $dp[$n];
}
二、力扣题96. 不同的二叉搜索树
给你一个整数 n
,求恰由 n
个节点组成且节点值从 1
到 n
互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。
示例 1:
输入:n = 3 输出:5
示例 2:
输入:n = 1 输出:1
提示:
1 <= n <= 19
二叉搜索树的规律是比当前节点小的在该节点左边,比当前节点大的在该节点右边。而通过上面的例子可知,n 个节点的二叉树的种类中,从 1 到 n 的节点都当过头结点。所以我们就依次遍历 1 到 n 作为头结点的情况。例子如下所示:
由图可知,通过头结点的数值,我们就知道该头结点的左右子树的节点数分别是多少。然后左右子树的种类可以通过查询之前的dp数组得到。例如上面的图,圈中的区域就类似 2 个节点的二叉树,可以直接得出1 节点的右子树的种类为 dp[ 2 ]。
function numTrees($n) {
$dp[0] = 1;
for($i = 1; $i <= $n; $i++) {
for($j = 1; $j <= $i; $j++) {
$dp[$i] += $dp[$j - 1] * $dp[$i - $j];
}
}
return $dp[$n];
}