导语
leetcode刷题笔记记录,本篇博客是贪心部分的第二期,主要记录题目包括:
Leetcode 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
解法
使用动规五部曲:
- dp[i]:代表了i拆分后得到的最大乘积;
- 递推公式:,这里j是所有小于i的数字循环,其中j*(i-j)是拆分为两个数的情形,j*dp[i-j]则是拆分为3个及以上的情形;
- 初始化:dp[2]=1,dp[0],dp[1]没有意义;
- 遍历顺序:从n等于3开始遍历;
- 打印输出。
class Solution:
def integerBreak(self, n: int) -> int:
# 初始化一个长度为 n+1 的数组,其中 dp[i] 表示数字 i 拆分成多个正整数之后,这些正整数的最大乘积。
dp = [0] * (n+1)
# 对于数字 2,只有一种拆分方式,即 1+1,所以乘积为1。
dp[2] = 1
# 从数字 3 开始,逐个计算其拆分后的最大乘积。
for i in range(3, n+1):
# 拆分数字 i,可以从 1 开始拆分到 i//2(因为超过 i//2 后,另一部分也会超过 i//2,产生重复)。
for j in range(1, i//2 + 1):
# 对于每种拆分方式,有两种选择:直接使用拆分出的两个数字 j 和 i-j;
# 或者使用数字 j 和数字 i-j 拆分后得到的最大乘积 dp[i-j]。
# 我们要选择两者中的较大值,并更新 dp[i]。
dp[i] = max(j*(i-j), j*dp[i-j], dp[i])
# 返回数字 n 拆分后得到的最大乘积。
return dp[n]
Leetcode 96. 不同的二叉搜索树
题目描述
给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。
示例 1:
输入: n = 3
输出: 5
示例 2:
输入: n = 1
输出: 1
提示:
1 <= n <= 19
解法
动规五部曲:
- dp[i]:表示由 i 个节点组成的独特BST的数量。
- 递推公式:观察n=3的情况,一共分为3种情况:
- 头结点为1:左边0个节点,右边2个节点;
- 头结点为2:左边1个节点,右边1个节点;
- 头结点为3:左边2个节点,右边0个节点;
对于每一种情况,该种情况下的可能数量为左子树可能的情况乘以右子树可能的情况,然后循环处理每种情况,为此,最终的递推公式为:
- 初始化,这里的关键在于dp[0],由于要计算乘积,所以可设置为dp[0]=1,这也符合直觉,即一个空节点也算是二叉搜索树,然后是dp[1]=1。
- 遍历顺序,从小往大;
- 打印dp数组。
class Solution:
def numTrees(self, n: int) -> int:
# 初始化一个长度为 n+1 的数组,dp[i] 表示由 i 个节点组成的独特BST的数量。
dp = [0] * (n+1)
# 基本情况:0个节点和1个节点的BST都只有1种。
dp[0] = 1
dp[1] = 1
# 从2到n计算每一个数可以构成的BST数量。
for i in range(2, n+1):
# 对于每一个数字 j (1 到 i),考虑 j 作为根的BST。
for j in range(1, i+1):
# j-1 是左子树的节点数,i-j 是右子树的节点数。
# dp[j-1] 是左子树的BST数量,dp[i-j] 是右子树的BST数量。
# 二者的乘积即为 j 作为根的BST的数量。
dp[i] += dp[j-1] * dp[i-j]
# 返回数字 n 可以构成的BST数量。
return dp[n]