LeetCode 343. 整数拆分
题目链接:343. 整数拆分 - 力扣(LeetCode)
注意两个关键:1)要分成大于1个正整数来去乘积,2)分成3比2好,4可以看成为,5不如2和3,6就是两个3,后面同理,因此这道题其实第一直觉是一个贪心题,尽量地分为3,不够的话就把后面乘一下就好了
#python 贪心版本
class Solution:
def integerBreak(self, n):
if n == 2: # 当n等于2时,只有一种拆分方式:1+1=2,乘积为1
return 1
if n == 3: # 当n等于3时,只有一种拆分方式:1+1+1=3,乘积为1
return 2
if n == 4: # 当n等于4时,有两种拆分方式:2+2=4和1+1+1+1=4,乘积都为4
return 4
result = 1
while n > 4: //当大于4的时候,我们不断地减去3
result *= 3 # 每次乘以3,因为3的乘积比其他数字更大
n -= 3 # 每次减去3
result *= n # 将剩余的n乘以最后的结果
return result
同样可以考虑dp做法。
每道题都要考虑dp五步:
1)确定dp数组下标与值的关系:对于该题就是第n位的和
2)确定递推公式:题目已经给出
3)确定初始值:题目已给出
4)确定遍历的数:题目告诉了dp[0],dp[1],所以我们要从第2位一直到第n位
5)带入验证一下
代码:
#python dp做法
class Solution:
# 假设对正整数 i 拆分出的第一个正整数是 j(1 <= j < i),则有以下两种方案:
# 1) 将 i 拆分成 j 和 i−j 的和,且 i−j 不再拆分成多个正整数,此时的乘积是 j * (i-j)
# 2) 将 i 拆分成 j 和 i−j 的和,且 i−j 继续拆分成多个正整数,此时的乘积是 j * dp[i-j]
def integerBreak(self, n):
dp = [0] * (n + 1) # 创建一个大小为n+1的数组来存储计算结果
dp[2] = 1 # 初始化dp[2]为1,因为当n=2时,只有一个切割方式1+1=2,乘积为1
# 从3开始计算,直到n
for i in range(3, n + 1): //这个很好考虑
# 遍历所有可能的切割点
for j in range(1, i // 2 + 1): //在根号i中求乘积,不断地尝试得到当前最大值
# 计算切割点j和剩余部分(i-j)的乘积,并与之前的结果进行比较取较大值
dp[i] = max(dp[i], (i - j) * j, dp[i - j] * j)
return dp[n] # 返回最终的计算结果
/java
public class Solution {
public int integerBreak(int n) {
int[] dp = new int[n + 1]; // 创建一个大小为n+1的数组来存储计算结果
dp[2] = 1; // 初始化dp[2]为1,因为当n=2时,只有一个切割方式1+1=2,乘积为1
// 从3开始计算,直到n
for (int i = 3; i <= n; i++) {
for (int j = 1; j <= i / 2; j++) { // 在i/2中求乘积,不断地尝试得到当前最大值
// 计算切割点j和剩余部分(i-j)的乘积,并与之前的结果进行比较取较大值
dp[i] = Math.max(dp[i], Math.max((i - j) * j, dp[i - j] * j));
}
}
return dp[n]; // 返回最终的计算结果
}
}
LeetCode 96. 不同的二叉搜索树
题目链接:96. 不同的二叉搜索树 - 力扣(LeetCode)
这道题是真的不看解析看不懂,但是可以大概知道怎么做:我们先选好根节点,其他的点小的放左边,大的放右边,如何放呢?下一个子状态,可以开始考虑次根节点(明白该意思就好,似乎没有这个名词)。真是屌爆了这个思路。
每道题都要考虑dp五步:
1)确定dp数组下标与值的关系:对于该题就是数组n的最大乘积
2)确定递推公式:这道题难点在此,需要多看几次视频,把这道题理解了然后背下来
3)确定初始值:题目已给出
4)确定遍历的数:
5)带入验证一下
代码:
/java
class Solution {
public int numTrees(int n) {
//初始化 dp 数组
int[] dp = new int[n + 1];
//初始化0个节点和1个节点的情况
dp[0] = 1;
dp[1] = 1;
for (int i = 2; i <= n; i++) {
for (int j = 1; j <= i; j++) {
//对于第i个节点,需要考虑1作为根节点直到i作为根节点的情况,所以需要累加
//一共i个节点,对于根节点j时,左子树的节点个数为j-1,右子树的节点个数为i-j
dp[i] += dp[j - 1] * dp[i - j];
}
}
return dp[n];
}
}