C++刷题笔记(21)——leetcode222、110、257

题目1:222.完全二叉树的节点个数

在这里插入图片描述

解法一:按照普通二叉树的解法

递归法

与之前求二叉树深度的解法类似,不过把深度换成了节点数

class Solution {
public:
    int getnodenum(TreeNode* node) {
        if (node == NULL) return 0;
        int leftnum = getnodenum(node->left);     //左
        int rightnum = getnodenum(node->right);   //右
        return 1 + leftnum + rightnum;            //中
    }
    int countNodes(TreeNode* root) {
        getnodenum(root);
        //也可以精简成:return 1 + countNodes(root->left) + countNodes(root->right);
    }
};

迭代法

迭代法也是一样,将层数改为节点数

class Solution {
public:
    int countNodes(TreeNode* root) {
        if (root == NULL) return 0;
        queue<TreeNode*> que;
        que.push(root);
        int num = 0;
        while (!que.empty()) {
            int size = que.size();
            for (int i = 0; i < size; i++) {
                TreeNode* node = que.front();
                que.pop();
                num++;
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
        }
        return num;
    }
};

解法二:按照完全二叉树的解法

根据完全二叉树的定义,有两种可能,即要么是满二叉树、要么是最后一层节点不满

对于满二叉树可以利用其性质2h-1计算,对于非满二叉树,可变遍历其左右孩子,直到某一深度的左右孩子为满二叉树
在这里插入图片描述

class Solution {
public:
    int countNodes(TreeNode* root) {
        if (root == nullptr) return 0;
        TreeNode* left = root->left;
        TreeNode* right = root->right;
        int leftHeight = 0, rightHeight = 0; // 初始为0为了下面求指数方便
        while (left) {               // 求左子树深度
            left = left->left;
            leftHeight++;
        }
        while (right) {              // 求右子树深度
            right = right->right;
            rightHeight++;
        }
        if (leftHeight == rightHeight) {
            return (2 << leftHeight) - 1; // 注意(2<<1) 相当于2^2,所以leftHeight初始为0
        }
        return countNodes(root->left) + countNodes(root->right) + 1;
    }
};

题目2:110.平衡二叉树

在这里插入图片描述
在这里插入图片描述
要注意二叉树高度和深度的定义
二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数
二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数。
在这里插入图片描述
在leetcode上根节点的深度为1

根据定义,如果一棵树是平衡二叉树,那么它的所有子树都是平衡二叉树。

求深度一般用前序遍历(中左右);
求高度一般用后序遍历(左右中)。

解法一:递归法

自顶向下的递归(前序遍历):
对于当前遍历到的节点,首先计算左右子树的高度;
如果高度差不大于1,再分别递归的遍历左右子节点,判断左右子树是否平衡。

class Solution {
public:
    int getheight(TreeNode* node) {
        if (node == NULL) return 0;    //遇到空节点终止,当前节点为根节点的树高度为0
        else return 1 + max(getheight(node->left), getheight(node->right));  //获取一个节点的最大高度
    }
    bool isBalanced(TreeNode* root) {
        if (root == NULL) return true;   //如果根节点为0,则高度差不超过1,为平衡二叉树
        //当一个节点的左右子树高度差不超过1 且 该节点的左子树的左右子树高度差不超过1 且 该节点的右子树的左右子树高度差不超多1 返回真,否则返回假
        else return abs(getheight(root->left) - getheight(root->right)) <= 1 && isBalanced(root->left) && isBalanced(root->right);
    }
};

这种写法,时间复杂度很高,从最后返回的结果就能看出来

自低向上的递归(后续遍历)
对于当前遍历到的节点,先递归的判断其左右子树是否平衡,再判断以当前节点为根节点的子树是否平衡。

class Solution {
public:
    int getheight(TreeNode* node) {
        if (node == NULL) return 0;                  //遇到空节点终止,当前节点为根节点的树高度为0
        int leftheight = getheight(node->left);      //求左子树的高度
        if (leftheight == -1) return -1;             //迭代发现某一节点的左右子树不平衡
        int rightheight = getheight(node->right);    //求右子树的高度
        if (rightheight == -1) return -1;
        int result;                                          //如果差值小于等于1,则返回当前二叉树的高度,否则返回-1,表示已经不是二叉平衡树了。
        if (abs(leftheight - rightheight) > 1) result = -1;  //abs求数据的绝对值,判断左右子树是否平衡
        else result = 1 + max(leftheight, rightheight);      //以当前节点为根节点的树的高度
        return result;
    }

    bool isBalanced(TreeNode* root) {
        return getheight(root) == -1 ? false : true;
    }
};

化简后:

class SOlution {
public:
    int getheight(TreeNode* node) {
        if (node == NULL) return 0;           
        int leftheight = getheight(node->left);   
        int rightheight = getheight(node->right); 
        if (leftheight == -1 || rightheight == -1 || abs(leftheight - rightheight) > 1) return -1;
        else return max(leftheight, rightheight);
    }
    bool isBalanced(TreeNode* root) {
        return getheight(root) >= 0;
    }
};

题目3:257.二叉树的所有路径

在这里插入图片描述

解法一:递归法

在这里插入图片描述
通过前序遍历让父节点指向孩子节点,然后把路径记录下来,通过回溯来退回当前路径进入另一条路径,寻找叶子节点

class Solution {
private:
    void traversal(TreeNode* node, vector<int>& path, vector<string>& result) {  //传入根节点、path记录每一条路径、result存放结果集
        path.push_back(node->val);                         //前序遍历,先处理中间节点
        if (node->left == NULL && node->right == NULL) {   //左右节点都为空,遇到了叶子节点,需要回溯
            string sPath;
            for (int i = 0; i < path.size() - 1; i++) {    //注意这里i<path.size()-1,意味着最后一个节点不放
                sPath += to_string(path[i]);               //将path里记录的路径转换成string格式
                sPath += "->";                             
            }                                              
            sPath += to_string(path[path.size() - 1]);     //记录最后一个节点(叶子节点)
            result.push_back(sPath);;                      //将记录的路径放入结果集里
            return;
        }
        if (node->left) {                                  //判空
            traversal(node->left, path, result);           //递归和回溯是一一对应的
            path.pop_back();                               //回溯,删除路径中最后一个元素
        }
        if (node->right) {
            traversal(node->right, path, result);
            path.pop_back();                               //回溯
        }
    }
public:
    vector<string>binaryTreePaths(TreeNode* root) {
        vector<string> result;
        vector<int> path;
        if (root == NULL) return result;
        traversal(root, path, result);
        return result;
    }
};

代码可以优化为:

class Solution {
public:
    void traversal(TreeNode* node, string path, vector<string>& result) {  //定义string path,每次都是复制赋值,不用使用引用,否则就无法做到回溯的效果
        if (node != NULL) {
            path += to_string(node->val);                      //判空,并将中间节点加入路径
            if (node->left == NULL && node->right == NULL) {   //当前节点为叶子节点
                result.push_back(path);
            }
            else {
                traversal(node->left, path + "->", result);   //回溯隐藏在 path + "->" 中
                traversal(node->right, path + "->", result);  //每次函数调用完,path如果没有加上"->",就回溯了
            }
        }
    };
public:
    vector<string>binaryTreePaths(TreeNode * root) {
        vector<string> result;
        string path;
        traversal(root, path, result);
        return result;
    }
};

解法二:迭代法

用栈:
两个栈,一个模拟递归,一个存放遍历路径

class Solution {
public:
    vector<string> binaryTreePaths(TreeNode* root) {
        stack<TreeNode*> tree;             //保存遍历的节点
        stack<string> pathST;              //保存遍历路径
        vector<string> result;
        if (root == NULL) return result;
        tree.push(root);
        pathST.push(to_string(root->val));
        while (!tree.empty()) {
            TreeNode* node = tree.top();  //取出节点
            tree.pop();
            string path = pathST.top();   //取出该节点对应的值
            pathST.pop();
            if (node->left == NULL && node->right == NULL) result.push_back(path);  //叶子节点
            if (node->right) {
                tree.push(node->right);
                pathST.push(path + "->" + to_string(node->right->val));
            }
            if (node->left) {
                tree.push(node->left);
                pathST.push(path + "->" + to_string(node->left->val));
            }
        }
        return result;
    }
};

用队列:
官方题解给出了队列的解法

class Solution {
public:
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> paths;
        if (root == nullptr) {
            return paths;
        }
        queue<TreeNode*> node_queue;
        queue<string> path_queue;

        node_queue.push(root);
        path_queue.push(to_string(root->val));

        while (!node_queue.empty()) {
            TreeNode* node = node_queue.front(); 
            string path = path_queue.front();
            node_queue.pop();
            path_queue.pop();

            if (node->left == nullptr && node->right == nullptr) {
                paths.push_back(path);
            } else {
                if (node->left != nullptr) {
                    node_queue.push(node->left);
                    path_queue.push(path + "->" + to_string(node->left->val));
                }

                if (node->right != nullptr) {
                    node_queue.push(node->right);
                    path_queue.push(path + "->" + to_string(node->right->val));
                }
            }
        }
        return paths;
    }
};

二叉树中递归带着回溯

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值