題目描述
記憶化搜索
對於每個節點而言都可以在區間1到n中取一個數作爲根節點,比如這裏取i,則左子樹能在根節點1 – i - 1中取值作爲根節點,右子樹能在i + 1 – n中取值作爲根節點。最後當前節點能取的可能就是左右子樹能取可能情況的乘積。對於子樹節點我們可以以同樣的方式遞歸地去求。由於這樣會有很多重複的計算,所以我們用一個map來記錄已經計算過的結果,避免重複計算,這就是記憶化搜索。
unordered_map<string,int> mp;
int numTrees(int n) {
return dfs(1, n);
}
int dfs(int s, int e)
{
string key = to_string(s)+"#"+to_string(e);
if(mp.find(key) != mp.end()) return mp[key];
if(s > e) return 1;
int rs = 0;
for(int i = s; i <= e; i++)
rs += dfs(s,i-1) * dfs(i+1,e);
mp.insert({key, rs});
return rs;
}
卡特蘭數列
卡特蘭數列百科
假設n個節點存在二叉排序樹的個數是G(n),令f(i)爲以i爲根的二叉搜索樹的個數,則
G(n) = f(1) + f(2) + f(3) + f(4) + … + f(n)
當i爲根節點時,其左子樹節點個數爲i-1個,右子樹節點爲n-i,則
f(i) = G(i-1)*G(n-i)
綜合兩個公式可以得到 卡特蘭數 公式
G(n) = G(0)G(n-1) + G(1)(n-2) +…+ G(n-1)*G(0)
int numTrees(int n)
{
vector<int> dp(n+1);
dp[0] = 1;
dp[1] = 1;
for(int i = 2; i < n + 1; i++)
for(int j = 1; j < i + 1; j++)
dp[i] += dp[j-1] * dp[i-j];
return dp[n];
}