二叉搜索树
LC.96 不同的二叉搜索树
class Solution {
public int numTrees(int n) {
int[] G = new int[n+1];
G[0] = 1;
G[1] = 1;
for(int i = 2;i < n + 1;++i){
for(int j = 1;j <= i;++j){
G[i] += G[j - 1]*G[i - j];
}
}
return G[n];
}
}
动态规划:遍历数组的每一个数字 i,将其作为树的根。则 i 左边的序列构成其左子树,右边的序列构成右子树。然后我们可以递归地构建左右子树。
设G(n):长度为n的序列能构成的不同二叉搜索树的个数。
F(i,n):以 i 为根节点,长度为n的序列能构成的不同二叉搜索树的个数。
则:
G
(
n
)
=
∑
i
=
1
n
F
(
i
,
n
)
G(n) = \sum_{i =1}^{n}F(i,n)
G(n)=i=1∑nF(i,n)
即以 i 为根节点的BST个数等于 i 左边序列构成的BST个数乘以 i 右边序列构成的BST个数。将 i 从1遍历到n即为结果。
LC.95 不同的二叉搜索树(2)
class Solution {
public List<TreeNode> generateTrees(int n) {
if(n == 0){
return new LinkedList<TreeNode>();
}
return getTree(1,n);
}
public List<TreeNode> getTree(int start,int end){
List<TreeNode> ans = new LinkedList<TreeNode>();
if(start > end){
ans.add(null);
return ans;
}
for(int i = start;i <= end;i++){
List<TreeNode> leftTrees = getTree(start,i-1);
List<TreeNode> rightTrees = getTree(i+1,end);
for(TreeNode left : leftTrees){
for(TreeNode right : rightTrees){
TreeNode cur = new TreeNode(i);
cur.left = left;
cur.right = right;
ans.add(cur);
}
}
}
return ans;
}
}
用递归的思想解题,一定要明确递归函数的定义,并相信这个定义,不要过多地考虑递归实现的细节。这里递归函数的作用是得到从1到n的序列组成的所有BST。那么我继续调用这个函数分别得到 i 的左边序列和右边序列构成的BST并进行拼接和储存即可。最后不要忘记考虑base case!
LC.99 恢复二叉搜索树
class Solution {
TreeNode t1,t2,pre;
public void recoverTree(TreeNode root) {
inorder(root);
int tem = t1.val;
t1.val = t2.val;
t2.val = tem;
}
public void inorder(TreeNode root){
if(root == null){
return;
}
inorder(root.left);
if(pre != null && pre.val > root.val){
if(t1 == null) t1 = pre;//确保t1只被标记一次
t2 = root;
}
pre = root;
inorder(root.right);
}
}
关键在于找到两个错位的节点,最后再进行交换即可。BST的一个重要性质是它的中序遍历结果是有序(从小到大)的,我们可以利用这一性质找到错位的节点。在出现下降趋势的时候(也就是有错误点的时候),同时记录 pre 和当前点。如果两个错误点相邻,那么就完成了;如果不相邻,在后面再出现错误点时就会覆盖掉原来记录的第二个点。