漸入佳境
整數拆分
leetcode:343. 整數拆分
動態規劃
思路
-
意義:i拆分乘積的最大值為
dp[i
] -
遞推:
dp[i] = max{dp[i],j*(i-j),j*dp[i-j]}
-
初始化:從2開始可以拆,有意義,
dp[2] = 1
,其他為0 -
遍歷順序:
for(int i = 3;i <= n;i++) // 0、1沒意義,2已經賦值了,從3開始 for(int j = 1;j <= i/2;j++) // 拆出0沒有意義,從1開始。取到i/2就可以,再往後重複。
複雜度分析
時間複雜度:O(N^2)。
空間複雜度:O(N)。
注意點
略
程式碼實現
class Solution {
public:
/*
i拆分乘積最大為dp[i]
dp[i] = max{dp[i],j*(i-j),j*dp[i-j]}
dp[0] = 0;dp[1] = 0;dp[2] = 1;
i: 3~n j: 1~i/2
*/
int integerBreak(int n) {
vector<int> dp(n + 1,0); // 陣列大小比最大下標大1
dp[2] = 1;
for(int i = 3;i <= n;i++){
for(int j = 1;j <= i/2;j++){
dp[i] = max(dp[i],max(j * (i-j),j * dp[i-j]));
}
}
return dp[n];
}
};
TypeScript:
/*
i拆分乘積最大為dp[i]
dp[i] = max{dp[i],j*(i-j),j*dp[i-j]}
dp[0] = 0;dp[1] = 0;dp[2] = 1;
i: 3~n j: 1~i/2
*/
function integerBreak(n: number): number {
let dp:number[] = new Array(n + 1).fill(0);
dp[2] = 1;
for(let i = 3;i <= n;i++){
for(let j = 1;j <=i/2;j++){
dp[i] = Math.max(dp[i],j * (i-j),j * dp[i-j]);
}
}
return dp[n];
};
不同的二叉搜尋樹
leetcode:96. 不同的二叉搜尋樹
動態規劃
思路
透過畫圖找到了規律,i個節點就是一個節點的基礎上,分配i-1個節點在左右子樹的問題
-
意義:i個節點有
dp[i]
種不同的二叉搜尋樹 -
遍歷和遞推:
dp[i] = dp[j] + dp[i-1-j]
for(int i = 2;i <= n;i++){ for(int j = i-1;j >= i/2;j--){ // i-1拆成j和i-1-j if(j == i - 1 - j) // 拆出兩個相等數時不乘2(軸對稱) dp[i] += dp[j] * dp[i-1-j]; else // 拆出不對稱時,有對稱的兩個解 dp[i] += 2 * dp[j] * dp[i-1-j]; } }
-
初始化:
dp[0] = 1;dp[1] = 1;
dp[0]
沒有意義但是需要賦值為1以保持遞推公式的一致。
複雜度分析
時間複雜度:O(N^2)。
空間複雜度:O(N)。
注意點
- JS數字除法會變成小數,
程式碼實現
class Solution {
public:
/*
本質上就是求n個節點的二叉搜尋樹可能的形狀數
*/
int numTrees(int n) {
vector<int> dp(n + 1,0);
dp[0] = 1;dp[1] = 1;
for(int i = 2;i <= n;i++){
for(int j = i-1;j >= i/2;j--){
// i-1拆成j和i-1-j
if(j == i - 1 - j) // 拆出兩個相等數時不乘2(軸對稱)
dp[i] += dp[j] * dp[i-1-j];
else // 拆出不對稱時,有對稱的兩個解
dp[i] += 2 * dp[j] * dp[i-1-j];
}
}
return dp[n];
}
};
TypeScript:
function numTrees(n: number): number {
let dp:number[] = new Array(n + 1).fill(0);
dp[0] = 1; dp[1] = 1;
for(let i = 2;i <= n;i++){
for(let j = i-1;j >= Math.floor(i/2);j--){
// i-1拆成j和i-1-j
if(j === i-1-j){
dp[i] += dp[j] * dp[i-1-j]; // 拆出兩個相等數時不乘2(軸對稱)
}
else{ // 拆出不對稱時,有對稱的兩個解
dp[i] += 2 * dp[j] * dp[i-1-j];
}
}
}
return dp[n];
};