LeetCode 96——不同的二叉搜索樹
阿新 • • 發佈:2018-11-20
solution 執行 {0} 只需要 獲取 問題 需要 += 奇數
1. 題目
2. 解答
以 \(1, 2, \cdots, n\) 構建二叉搜索樹,其中,任意數字都可以作為根節點來構建二叉搜索樹。當我們將某一個數字作為根節點後,其左邊數據將構建為左子樹,右邊數據將構建為右子樹。因此,這是一個遞歸問題。
若以第 \(i\) 個數據為根節點,其左邊數據有 \(i-1\) 個,左子樹可能情況為 left_num,右邊數據有 \(n-i\) 個,右子樹可能情況為 right_num,因此以當前數據為根節點可以構建出 left_num * right_num 個二叉搜索樹。
所以,我們要做的就是遍歷 \(i = 1\cdots n\),統計出每個數據作為根節點可以構建出的二叉搜索樹總個數即可。
- 遞歸法
class Solution { public: int numTrees(int n) { int sum = 0; if (n <= 1) return 1; // 以當前的數為根節點,左右兩邊的數分別構建子樹 for (int i = 1; i <= n; i++) { int left_num = numTrees(i - 1); // 左邊的數可以構建多少個二叉搜索樹 int right_num = numTrees(n - i); // 右邊的數可以構建多少個二叉搜索樹 sum += left_num * right_num; } return sum; } };
但是上面的程序運行時超時了,其實我們只需要統計一半數據就可以了,因為兩邊是對稱的。
比如我們有 1,2,3,4,5 五個數,以 2 作為根節點,左邊有 1 個數,右邊有 3 個數。以 4 作為根節點,左邊有 3 個數,右邊有 1 個數。這兩種情況是一樣的,因此如果數據個數為偶數,我們只需要統計一半數據即可,而為奇數的話我們就要再多統計一個中間數據。
class Solution { public: int numTrees(int n) { int sum = 0; if (n <= 1) return 1; int is_odd = n % 2; int mid = n / 2; // 以當前的數為根節點,左右兩邊的數分別構建子樹 for (int i = 1; i <= mid; i++) { int left_num = numTrees(i - 1); // 左邊的數可以構建多少個二叉搜索樹 int right_num = numTrees(n - i); // 右邊的數可以構建多少個二叉搜索樹 sum += left_num * right_num; } sum = sum * 2; if (is_odd) sum = sum + numTrees(mid) * numTrees(n - mid - 1); return sum; } };
此外,我們還可以定義一個全局變量,來存放已經計算過的數值,避免在遞歸過程中大量地重復計算。
class Solution {
public:
#define MAX 1000
int nums[MAX]; // 存放已經計算過的數值
int numTrees(int n) {
int sum = 0;
//if (n <= 0) return 1;
if (n <= 1) return 1;
// 以當前的數為根節點,左右兩邊的數分別構建子樹
for (int i = 1; i <= n; i++)
{
if (nums[i-1] == 0) nums[i-1] = numTrees(i - 1); // 左邊的數可以構建多少個二叉搜索樹
int left_num = nums[i-1];
if (nums[n-i] == 0) nums[n-i] = numTrees(n - i); // 右邊的數可以構建多少個二叉搜索樹
int right_num = nums[n-i];
sum += left_num * right_num;
}
return sum;
}
};
- 叠代法
還可以將遞歸改寫為循環,避免函數多次調用執行效率較低。
class Solution {
public:
int numTrees(int n) {
int nums[n+1] = {0};
nums[0] = 1;
nums[1] = 1;
if (n <= 1) return 1;
for (int i = 2; i <= n; i++)
{
// 從 n=2 開始統計可以構建多少個不同的二叉搜索樹
for (int j = 1; j <= i; j++)
{
nums[i] += nums[j-1] * nums[i-j];
}
}
return nums[n];
}
};
獲取更多精彩,請關註「seniusen」!
LeetCode 96——不同的二叉搜索樹