leetcode:958. 判断二叉树是不是完全二叉树

题目来源

题目描述

在这里插入图片描述

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};


class Solution {
public:
    bool isCompleteTree(TreeNode* root){

    }
};

题目分析

实际上,完全二叉树,它是根据满二叉树来定义的

  • 那什么是满二叉树呢?就是节点个数N与层数k满足:N=2^k - 1的关系的树,说白了,最后一层节点全部要满。
  • 完全二叉树也就是没有满的满二叉树,它的节点在每一层一定是连续分布的。如果出现哪一层中两个非空节点间隔一个空节点,那一定不是完全二叉树。完全二叉树看起来就像是满二叉树右下角缺了一口。如下图所示:
    在这里插入图片描述
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};


class Solution {
public:
    bool isCompleteTree(TreeNode* root) {

    }
};

题目实现

层序遍历

判断一棵树是否是完全二叉树,主要有两点:

  • 按层遍历二叉树,从每层的左边向右边依次遍历所有的节点
  • 如果当前节点有右孩子,但是没有左孩子,那么它一定不是完全二叉树,直接返回false
  • 如果当前节点并不是左右还是都有,那么从该节点开始,之后的节点都是叶子节点
  • 遍历过程中如果不返回false,遍历结束后返回true
    在这里插入图片描述
bool isCompleteTree1(TreeNode* root){
    if(root == nullptr){
        return true;
    }

    std::queue<TreeNode *> queue;
    bool leaf = false; // 是否遇到过叶子节点或者有左无右的节点
    TreeNode *left = nullptr, *right = nullptr;
    queue.emplace(root);
    while (!queue.empty()){
        root = queue.front(); queue.pop();
        left = root->left, right = root->right;
        if((leaf && (left != nullptr || right != nullptr))   // 如果遇到过不双全的节点,又发现当前节点不是叶节点
           || (left == nullptr && right != nullptr)){  //有右无左
            return false;
        }


        if(left != nullptr){
            queue.emplace(left);
        }
        if(right != nullptr){
            queue.emplace(right);
        }

        if((left == nullptr && right == nullptr)
           || (left != nullptr && right == nullptr)){
            leaf = true;
        }
    }
    return true;
}

在这里插入图片描述

递归实现

从当前节点往下看,如果以当前节点为根节点的树是完全二叉树,那么有4中情况:

  • 左子树是满二叉树,右子树也是满二叉树,而且左子树的高度 = 右子树的高度
  • 左子树是满二叉树,右子树也是满二叉树,而且左子树高度 = 右子树高度 + 1
  • 左子树是完全二叉树,右子树是满二叉树,而且左子树的高度 =右子树高度 + 1
  • 左子树是满二叉树,右子树是完全二叉树,而且左子树高度 = 右子树高度

在这里插入图片描述

综上,对于当前节点来说,它需要问它的左右子树如下信息:

  • 你是完全二叉树吗?
  • 你是满二叉树吗?
  • 你的高度是多少?

代码实现如下:

class Solution {
    // 对每一棵子树,是否是满二叉树、是否是完全二叉树、高度
    class Info{
    public:
        bool isFull;
        bool isCBT;
        int height;

        explicit Info(bool full, bool cbt, int h) : isFull(full), isCBT(cbt), height(h){

        }
    };

    Info process(TreeNode *root){
        if(root == nullptr){
            return Info(true, true, 0);
        }

        Info leftInfo = process(root->left);
        Info rightInfo = process(root->right);

        int height = std::max(leftInfo.height, rightInfo.height) + 1;
        bool isFull = leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height;
        bool isCBT = false;
        // 左子树是满二叉树,右子树也是满二叉树,而且左子树的高度 = 右子树的高度
        if (leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height) {
            isCBT = true;
        }
        //  左子树是完全二叉树,右子树是满二叉树,而且左子树的高度 =右子树高度 + 1
        else if (leftInfo.isCBT && rightInfo.isFull && leftInfo.height == rightInfo.height + 1) {
            isCBT = true;
        }
        // 左子树是满二叉树,右子树也是满二叉树,而且左子树高度 = 右子树高度 + 1
        else if (leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height + 1) {
            isCBT = true;
        }
       // 左子树是满二叉树,右子树是完全二叉树,而且左子树高度 = 右子树高度
        else if (leftInfo.isFull && rightInfo.isCBT && leftInfo.height == rightInfo.height) {
            isCBT = true;
        }

        return Info(isFull, isCBT, height);
    }

public:
    bool isCompleteTree(TreeNode* root) {
        if (root == nullptr) {
            return true;
        }

        return process(root).isCBT;
    }
};

对数器测试(对数器不完全,待改写)

std::default_random_engine e;
std::uniform_real_distribution<float> random_float;

TreeNode* generate(int level, int maxLevel, int maxValue) {
    if (level > maxLevel || random_float(e) < 0.5) {
        return nullptr;
    }
    auto * head = new TreeNode((int) (random_float(e) * maxValue * 1.0));
    head->left = generate(level + 1, maxLevel, maxValue);
    head->right = generate(level + 1, maxLevel, maxValue);
    return head;
}

TreeNode * generateRandomBST(int maxLevel, int maxValue) {
    return generate(1, maxLevel, maxValue);
}


int main() {
    e.seed(time(NULL));

    int maxLevel = 5;
    int maxValue = 100;
    int testTimes = 1000;
    for (int i = 0; i < testTimes; i++) {
        TreeNode *root = generateRandomBST(maxLevel, maxValue);
        if (isCompleteTree1(root) != isCompleteTree(root)) {
            printf("Oops!");
            return -1;
        }
    }
    printf("ok!");

    return 0;
}

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值