1. topic
2. answers
A binary search tree is constructed with $1, 2, cdots, n $, where any number can be used as the root node to build a binary search tree. When we take a number as the root node, the left data will be constructed as the left subtree and the right data as the right subtree. So this is a recursive problem.
If the first $I $data is taken as the root node, the left data is $i-1 $, the left subtree may be left_num, the right subtree may be $n-i $, and the right subtree may be right_num. therefore, taking the current data as the root node, the left_num * right_num binary search tree can be constructed.
So, what we need to do is to traverse $i = 1\cdots n $, and count the total number of binary search trees that can be constructed by each data as root node.
- Recursive method
class Solution { public: int numTrees(int n) { int sum = 0; if (n <= 1) return 1; // Take the current number as the root node, and construct the subtree with the numbers on the left and right sides respectively for (int i = 1; i <= n; i++) { int left_num = numTrees(i - 1); // How many binary search trees can the number on the left build int right_num = numTrees(n - i); // How many binary search trees can the number on the right build sum += left_num * right_num; } return sum; } };
But the above program ran out of time, in fact, we only need to count half of the data, because both sides are symmetrical.
For example, we have five numbers: 1,2,3,4,5, with 2 as the root node, one on the left and three on the right. With 4 as the root node, there are 3 numbers on the left and 1 number on the right. The two cases are the same, so if the number of data is even, we only need to count half of the data, and if it is odd, we need to count another intermediate data.
class Solution { public: int numTrees(int n) { int sum = 0; if (n <= 1) return 1; int is_odd = n % 2; int mid = n / 2; // Take the current number as the root node, and construct the subtree with the numbers on the left and right sides respectively for (int i = 1; i <= mid; i++) { int left_num = numTrees(i - 1); // How many binary search trees can the number on the left build int right_num = numTrees(n - i); // How many binary search trees can the number on the right build sum += left_num * right_num; } sum = sum * 2; if (is_odd) sum = sum + numTrees(mid) * numTrees(n - mid - 1); return sum; } };
In addition, we can also define a global variable to store the calculated values and avoid a large number of repeated calculations in the recursive process.
class Solution { public: #define MAX 1000 int nums[MAX]; // Store calculated values int numTrees(int n) { int sum = 0; //if (n <= 0) return 1; if (n <= 1) return 1; // Take the current number as the root node, and construct the subtree with the numbers on the left and right sides respectively for (int i = 1; i <= n; i++) { if (nums[i-1] == 0) nums[i-1] = numTrees(i - 1); // How many binary search trees can the number on the left build int left_num = nums[i-1]; if (nums[n-i] == 0) nums[n-i] = numTrees(n - i); // How many binary search trees can the number on the right build int right_num = nums[n-i]; sum += left_num * right_num; } return sum; } };
- Iteration method
Recursion can also be rewritten as a loop to avoid the low efficiency of multiple function calls.
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++) { // Count how many different binary search trees can be built from n=2 for (int j = 1; j <= i; j++) { nums[i] += nums[j-1] * nums[i-j]; } } return nums[n]; } };
For more highlights, please pay attention to "seniusen"!