编程题——关于树

 

目录

 

平衡二叉树(剑指欧肥儿)

二叉树的深度(剑指欧肥儿)

二叉树的下一个结点(剑指欧肥儿)

二叉树的镜像(剑指欧肥儿)

对称的二叉树(剑指欧肥儿)

把二叉树打印成多行(剑指欧肥儿)

按之字形顺序打印二叉树(剑指欧肥儿)

序列化二叉树(剑指欧肥儿)

二叉搜索树的第k个结点

数据流中的中位数(剑指欧肥儿)

重建二叉树(剑指欧肥儿)


  • 平衡二叉树(剑指欧肥儿)

题目描述:输入一棵二叉树,判断该二叉树是否是平衡二叉树。

解题代码一:

class Solution {
public:
    bool IsBalanced_Solution(TreeNode* pRoot) {
        //排除特殊情况
        if(pRoot == NULL) return true;
        
        int leftTreeDep = getDepth(pRoot -> left);
        int rightTreeDep = getDepth(pRoot -> right);
        
        if(leftTreeDep - rightTreeDep > 1 || rightTreeDep - leftTreeDep > 1){
            return false;
        }
        return IsBalanced_Solution(pRoot -> left) && IsBalanced_Solution(pRoot -> right);
    }
    
    int getDepth(TreeNode* pRoot){
        //排除特殊情况
        if(pRoot == NULL) return 0;
        
        //递归算高度
        int leftDepth = getDepth(pRoot -> left);
        int rightDepth = getDepth(pRoot -> right);
        
        return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
        //return max(leftDepth + 1,rightDepth + 1); 这句和上面一句的return完全等效

    }
};

解题关键:

  1. 平衡二叉树的特点,它可以是一颗空树或它的左右两个子树的高度差的绝对值不超过1,并且它的左右两个子树都是一颗平衡二叉树。
  2. 单独写出一个计算树的高度的函数getDepth()
  3. 运用了两个递归,一个计算树的高度,一个判断每个子树是否满足平衡二叉树的特征。

解题代码二:

class Solution {
public:
    bool IsBalanced_Solution(TreeNode* pRoot) {
        //排除特殊情况
        return getDepth(pRoot) != -1;
        
    }
    
    int getDepth(TreeNode* pRoot){
        //排除特殊情况
        if(pRoot == NULL) return 0;
        
        //递归算高度
        int leftDepth = getDepth(pRoot -> left);
        if(leftDepth == -1) return -1;
        int rightDepth = getDepth(pRoot -> right);
        if(rightDepth == -1) return -1;
        return abs(leftDepth - rightDepth) > 1 ? -1 : 1 + max(leftDepth, rightDepth);
    }
};

解题关键:

  1. 代码一是对树从上到下,对每层的左右节点进行计算树高度,每一次计算高度,都会重复计算下面的节点的高度,其实是没必要的。
  2. 代码二是对树从下到上(递归是从下开始递归的),计算每一个节点的高度,但没有重复计算任何一个节点的高度。
  3. 代码二是对代码一的改进,避免的不必要的计算,但思考量和难度更大。

题外话:

  1. C++中取绝对值的函数,int abs(int x),在这里不用引入库,可能牛客这个剑指的编译器引入了cmath库。
  2. C++取两个数的最大值的函数是 int max(int x,int y)
  3. 上面两个函数都要在,include<cmath> 的前提下

  • 二叉树的深度(剑指欧肥儿)

题目描述:输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

解题代码:

class Solution {
public:
    int TreeDepth(TreeNode* pRoot)
    {
        if(pRoot == NULL) return 0;
        
        int left = TreeDepth(pRoot -> left);
        int right = TreeDepth(pRoot -> right);
        
        return max(left + 1,right + 1);
        //return left > right ? left + 1 : right + 1;
    }
};

解题思路:

  1. 这个代码其实是上一道题的代码一的第二个函数getDepth,而return max(left + 1, right + 1)和上一道题的代码一getDepth的return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;是一个道理,两者完全可以相互替换。
  2. 这里要说一次,树的深度,结点的层数是从根开始定义起,根为第一层,根的孩子是第二层,以此类推。树中结点的最大层次称为树的深度(Depth)。

题外话:

要被if的判断条件判断为false的语句有,if(NULL)    if(0)      if(false)


  • 二叉树的下一个结点(剑指欧肥儿)

题目描述:给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

解题代码:

/*
struct TreeLinkNode {
    int val;
    struct TreeLinkNode *left;
    struct TreeLinkNode *right;
    struct TreeLinkNode *next;
    TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
        
    }
};
*/
class Solution {
public:
    TreeLinkNode* GetNext(TreeLinkNode* pNode)
    {
        //排除不可能
        if(pNode == NULL) return NULL;
        
        //如果该节点有右子节点
        TreeLinkNode* p = NULL;
        if(pNode -> right != NULL){
            p = pNode -> right;
            while(p -> left != NULL){
                p = p -> left;
            }
        }
        //如果该节点没有右节点
        else if(pNode -> next != NULL){
            //该节点还是父亲节点的右节点
            TreeLinkNode* pp;
            p = pNode;
            pp = p -> next;
            while(p == pp -> right && pp != NULL){
                p = pp;
                pp = pp -> next;
            }
            p = pp;
        }
        return p; 
            
    } 
}; 

解题思路:

  1. 这道题思路比较难,看了 答案也会想很久。
  2. 对于一个节点,对它进行分了三个类。

a:该节点有右节点,则它的下一个节点是它的右子树的最左节点。

b:该节点没有右节点,该节点还是它父节点的右节点,则我们沿着该节点的父亲节点一路往上遍历,直到找到一个节点x,x是它父亲节点的左节点。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值