有趣的二叉查找树

提到二叉查找树,我们就自然想到他的中序遍历的val值是一个递增。

而这一点特性就是我们能够验证一颗二叉树是否为二叉查找书的依据。

看这样一道题:

问题1:Given a binary tree, determine if it is a valid binary search tree (BST).

bool isValidBST(TreeNode* root) {
        if(root==NULL) return true;
        stack<TreeNode*> ss;
        vector<int> res;
        ss.push(root);
        bool back=false;
        while(ss.size()>0){//这一段就是中序遍历的迭代法
            if(ss.top()->left&&back==false){//定义了一个指示量back指示是否我们应该向上遍历(此时下面已经遍历完成)
                ss.push(ss.top()->left);
            }else{
                TreeNode* p=ss.top();
                ss.pop();
                res.push_back(p->val);
                if(p->right){
                    ss.push(p->right);
                    back=false;
                }else back=true;
            }
        }
        for(int i=0;i<res.size()-1;i++){
            if(res[i]>=res[i+1]) return false;
        }
        return true;
    }

对于中序遍历的迭代法,可以简化写成(不用指示量了);

 TreeNode *p=root;
        while(ss.size()>0||p!=NULL){
            if(p){
                ss.push(p);
                p=p->left;
            }else{
                p=ss.top();
                ss.pop();
                res.push_back(p->val);
                p=p->right;
            }
        }

好了,注意如果root为NULL的时候,也算成是二叉查找树了。

如果我这里给出的输入是一个含结点的数组呢,如果是中序遍历就好了。但是如果不是呢,是后序遍历或者前序呢?

这样我们不可能根据一种遍历重构出二叉树。所以应该换种思路了吧。过几天我贴出代码。


问题2:

Two elements of a binary search tree (BST) are swapped by mistake.

Recover the tree without changing its structure.

其实就是找出不对的两个结点值,进行交换。

Note:
A solution using O(n) space is pretty straight forward. Could you devise a constant space solution?

借用第一题的方法,但我们不需要完整的数组了。

我写的代码如下:

void recoverTree(TreeNode* root) {
        if(root==NULL) return;
        stack<TreeNode*> ss;
        TreeNode* p=root;
        TreeNode* first=NULL;
        TreeNode* second=NULL;
        TreeNode* last=NULL;
        bool error=false;
        while(ss.size()>0||p!=NULL){
            if(p){
                ss.push(p);
                p=p->left;
            }else{
                p=ss.top();
                ss.pop();
                if(last!=NULL&&last->val>p->val&&error==false){
                    error=true;
                    first=last;
                    second=p;
                }else if(last!=NULL&&last->val>p->val&&error){
                    second=p;
                    break;
                }
                last=p;
                p=p->right;
            }
        }
        int temp=first->val;
        first->val=second->val;
        second->val=temp;
        return;
    }


问题3,Given n, how many structurally unique BST's (binary search trees) that store values 1...n?

For example,
Given n = 3, there are a total of 5 unique BST's.题目来源(leetcode)

   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3
这个问题非常有趣,其实你如果能够以根结点对上面进行分类,你会发现:根结点为1的时候,左子树为空,右子树有两种。(相当于2和3能排出BST的种类)。 以此类推,当数组为 1, 2 , 3 , ..., n 时,基于以下原则的构建的 BST 树具有唯一性: 以 i 为根节点的树,其左子树由 [1, i-1] 构成,其右子树由 [i+1, n] 构成。每种类型对应的种类为左子树的种类*右子树的种类。

以n=3为例,f(3)=f(0)*f(2)    1为根

                +f(1)*f(1)   2为根

                +f(2)*f(0);  3为根


所以,由此观察,可以得出f 的递推公式。

这个问题就是一维的动态规划。(感谢戴同学关于这个问题的分析)

只需要建立一个长度为n+1(或者n)的数组cnt,已知cnt[0]=1,cnt[1]=1.利用两层循环就可以轻松得到答案。

代码实现(C++):

     int numTrees(int n) {//利用和之前的关系,按照谁为根分类
        if(n<=0) return 0;
        if(n==1) return 1;
        vector<int> cnt(n+1,0);//int* cnt=new int[n+1];delete[] cnt;
        cnt[0]=1;
        cnt[1]=1;
        for(int i=2;i<=n;i++){
            for(int j=0;j<i;j++){
                cnt[i]+=cnt[j]*cnt[i-j-1];
            }
        }
        return cnt[n];
    }

问题4:Givenn, generate all structurally unique BST’s (binary search trees) that store values 1...n.
把1题的所有种类都输出,该怎么办呢。
其实用递归就搞定。需要注意的就是边界条件。
代码如下(C++)
vector<TreeNode*> generateTrees(int n){
     return generateTrees(1,n);
}
ector<TreeNode*> generateTrees(int low,int high){
     vector<TreeNode*> res;
     if(low>high||low<0||high<0){
        res.push_back(NULL);
        return res;
     }
     if(low==high){
        TreeNode* p=new TreeNode(low);
        res.push_back(p);
        return res;
     }
     for(int i=low;i<=high;i++){
        vector<TreeNode*> vleft=generateTrees(low,i-1);
        vector<TreeNode*> vright=generateTrees(i+1,high);
        for(int j=0;j<vleft.size();j++){
            for(int k=0;k<vright.size();k++){
             TreeNode* proot=new TreeNode(i);
             proot->left=vleft[j];
             proot->right=vright[k];
             res.push_back(proot);
        }
        }
     }
     return res;
}
写了个测试小程序测试了一下:(贴的不是完整的程序)
void printTree(TreeNode* root){
   if(root==NULL){
    cout<<"# ";
    return;
   }
   cout<<root->val<<" ";
   printTree(root->left);
   printTree(root->right);
}
 int main(){
 solution* p;
 vector<TreeNode* > res=p->generateTrees(4);//输入4
 for(int i=0;i<res.size();i++){
    printTree(res[i]);
    cout<<endl;
 }
 return 0;
 }
输出的应该是按照先序遍历的输出,NULL输出'#'





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值