「这是我参与2022首次更文挑战的第32天,活动详情查看:2022首次更文挑战」。
题目:给定一个正整数n, 求由1-n这n个节点组成的不同的二叉搜索树有多少种,返回符合题意的二叉搜索树的数量。
解题思路
所谓的二叉搜索树,是指如果一棵树的左右子树不空,则有左子树上所有节点都小于根节点,右子树上的所有树节点的值都大于根节点,并且该树上的所有子树都满足该条件。根据本题题意,一棵树由n个节点组成, 并且这些节点的内容为1-n,可以分开进行考虑,因为每个节点都可以做根节点,那么假设以i节点为根节点的不同的二叉搜索树有,最终n个节点的不同二叉搜索树总量为,则可得:
而对于节点i,如果节点i为根节点,则其所有的左子树节点为[1,i-1], 其右子树所有节点为[i+1, n],因此左子树节点总数为i-1个,右子树节点总数为n-i个。而分开的左子树和右子树的节点也可以单独进行如上分析, 因此以节点i为根节点的不同的二叉搜索树的总量为:
则最终总量为:
在代码实现中, 可以直接看作是一个动态规划数组,最终求得的数组最后一个位置的值即为最终的结果。代码如下:
public int numTrees(int n) {
int[] dp = new int[n + 1];
dp[0] = 1;
dp[1] = 1;
for(int i=2;i<=n;i++){
for(int j=1;j<=i;j++){
dp[i] += dp[j-1]*dp[i-j];
}
}
return dp[n];
}
上述代码的时间复杂度为, 空间复杂度为。上述代码需要注意的是两层for循环中内层循环的j起始点,通过dp[2]模拟一下很容易直到j是从1开始的。实际上,上述总量公式即为卡特兰数公式,可通过求卡特兰数得到最终的答案。
验证二叉搜索树
再来看看LeetCode 98的验证二叉搜索树, 给定一个二叉树的根节点root,要求判断该树是不是一个有效的二叉搜索树。
思路
根据二叉搜索树的定义,树的节点大小关系为左<中<右。符合中序遍历的结果,只需将二叉树进行中序遍历,之后判断每次的值是否为升序即可,代码如下:
public boolean isValidBST(TreeNode root) {
Deque<TreeNode> stack = new ArrayDeque<>();
double value = -Double.MAX_VALUE;
while(!stack.isEmpty()||root!=null){
if(root!=null){
stack.push(root);
root = root.left;
}else {
root = stack.pop();
if(value<root.val){
value = root.val;
}else {
return false;
}
root = root.right;
}
}
return true;
}
此处需要注意的是在设置value值的时候,需要设定为-Double.MAX_VALUE而不能设置为Integer.MIN_VALUE,这样测试用例不会出现问题。