Leetcode刷题笔记Day7:二叉树Ⅱ

98 阅读4分钟

对称二叉树

  • 力扣题目链接

  • 这道题目的本质是要比较两个树(这两个树是根节点的左右子树),遍历两棵树而且要比较内侧和外侧节点,所以准确的来说是一个树的遍历顺序是左右中,一个树的遍历顺序是右左中。

  • 而本题的迭代法中我们使用了队列,需要注意的是这不是层序遍历,而且仅仅通过一个容器来成对的存放我们要比较的元素,认识到这一点之后就发现:用队列,用栈,甚至用数组,都是可以的。

  • 递归法:

bool compare(TreeNode* left, TreeNode* right){
    // 情况1:叶子节点
    if(!left && !right) return true;
    // 情况2:左右节点值相等,继续向下比较(递归)
    else if(left && right && left->val==right->val)
        return compare(left->left, right->right) 
        	&& compare(left->right, right->left);
    else return false;
}
bool isSymmetric(TreeNode* root) {
    if(!root) return true;
    return compare(root->left, root->right);
}
  • 迭代法:
bool isSymmetric(TreeNode* root) {
    if(!root) return true;
    stack<TreeNode*> q;	//这里使用栈或队列都可以
    q.push(root->left);
    q.push(root->right);

    while(!q.empty()){
        TreeNode* left=q.top(); q.pop();
        TreeNode* right=q.top(); q.pop();
        // 左节点为空、右节点为空,此时说明是对称的
        if(!left && !right) continue;
        // 左右一个节点不为空,或者都不为空但数值不相同,返回false
        if ((!left || !right || (left->val!=right->val)))
            return false;
        // 注意成对放入栈(队列)中
        q.push(left->left);
        q.push(right->right);
        q.push(left->right);
        q.push(right->left);
    }
    return true;
}
bool compare(TreeNode* left, TreeNode* right){
    // 情况1:叶子节点
    if(!left && !right) return true;
    // 情况2:左右节点值相等,继续向下比较(递归)
    else if(left && right && left->val==right->val)
        return compare(left->left, right->left) 
        	&& compare(left->right, right->right);
    else return false;
}
bool isSameTree(TreeNode* p, TreeNode* q) {
    return compare(p,q);
}
bool isSameTree(TreeNode* p, TreeNode* q) {
    if (!p && !q) return true;
    if (p && q && p->val == q->val)
        return isSameTree(p->left, q->left) 
        	&& isSameTree(p->right, q->right);
    else return false;
}
bool isSubtree(TreeNode* root, TreeNode* subRoot) {
    if(!root) return false;
    if(isSameTree(root, subRoot)) return true;
    return isSubtree(root->left, subRoot) 
        || isSubtree(root->right, subRoot);
}

二叉树的最大深度

int maxDepth(TreeNode* root) {
    queue<TreeNode*> q;
    int dep=0;
    if(root) q.push(root);
    while(!q.empty()){
        dep++;
        int size=q.size();
        for(int i=0; i<size; i++){
            TreeNode* node=q.front();
            q.pop();
            if(node->left) q.push(node->left);
            if(node->right) q.push(node->right);
        }
    }
    return dep;
}
  • 递归法:
int maxDepth(TreeNode* root) {
    if(!root) return 0;
    return 1+max(maxDepth(root->left), maxDepth(root->right));
}
int maxDepth(Node* root) {
    if(!root) return 0;
    int depth=0;
    for(auto node : root->children)
        depth=max(depth, maxDepth(node));
    return depth+1;
}

二叉树的最小深度

  • 力扣题目链接
  • 最小深度是从根节点到最近叶子节点的最短路径上的节点数量
  • 层序遍历法:
int minDepth(TreeNode* root) {
    queue<TreeNode*> q;
    int dep=0;
    if(root) q.push(root);
    while(!q.empty()){
        dep++;
        int size=q.size();
        for(int i=0; i<size; i++){
            TreeNode* node=q.front();
            q.pop();
            // 如遇到第一个叶子节点,所在层即为最小深度
            if(!node->left && !node->right) return dep;
            if(node->left) q.push(node->left);
            if(node->right) q.push(node->right);
        }
    }
    return dep;
}
  • 递归法:
int getDepth(TreeNode* root){
    if(!root) return 0;
    int leftDepth=getDepth(root->left);
    int rightDepth=getDepth(root->right);
    // 注意仔细分类!
    if(!root->left && root->right) return 1+rightDepth;
    else if(root->left && !root->right) return 1+leftDepth;
    else return 1+min(leftDepth, rightDepth);
}
int minDepth(TreeNode* root) {
    return getDepth(root);
}

完全二叉树的节点个数

int countNodes(TreeNode* root) {
    if(!root) return 0;
    TreeNode* left=root->left;
    TreeNode* right=root->right;
    int leftDepth=0, rightDepth=0;
    while(left){
        left=left->left;
        leftDepth++;
    }
    while(right){
        right=right->right;
        rightDepth++;
    }
    // 注意(2<<1) 相当于2^2,所以leftDepth初始为0
    if(leftDepth==rightDepth) return (2<<leftDepth)-1;
    return countNodes(root->left)+countNodes(root->right)+1;
}
  • 时间复杂度:O(log n × log n)
  • 空间复杂度:O(log n)

平衡二叉树

  • 力扣题目链接
  • 通过本题可以了解求二叉树深度二叉树高度的差异,求深度适合用前序遍历,而求高度适合用后序遍历
  • 前序和后序遍历本质:前序遍历意思是先访问根结点,再访问左右孩子,是一种自顶向下的处理方式;而后序遍历是先处理左右孩子,再一步一步把信息传递到根结点,是一种自底向上的方式!
int getHeight(TreeNode* root){
    if(!root) return 0;
    int leftHeight=getHeight(root->left);
    if(leftHeight==-1) return -1;
    int rightHeight=getHeight(root->right);
    if(rightHeight==-1) return -1;
    return abs(leftHeight-rightHeight)>1
        ? -1 : (1+max(leftHeight, rightHeight));
}
bool isBalanced(TreeNode* root) {
    return getHeight(root)==-1 ? false : true;
}

二叉树的所有路径

  • 力扣题目链接
  • 回溯和递归是一一对应的,有一个递归,就要有一个回溯
void traversal(TreeNode* cur, vector<int>& path, vector<string>& result){
    path.push_back(cur->val);
    if(!cur->left && !cur->right){
        string s;
        for(int i=0; i<path.size()-1; i++){
            s+=to_string(path[i]);
            s+="->";
        }
        s+=to_string(path[path.size()-1]);
        result.push_back(s);
        return;
    }
    if(cur->left){
        traversal(cur->left, path, result);
        path.pop_back();	// 回溯
    }
    if(cur->right){
        traversal(cur->right,path,result);
        path.pop_back();	// 回溯
    }
}
vector<string> binaryTreePaths(TreeNode* root) {
    vector<int> path;
    vector<string> result;
    if(!root) return result;
    traversal(root, path, result);
    return result;
}
  • 精简代码:
void traversal(TreeNode* cur, string path, vector<string>& result){
    // 注意path参数类型变为string
    path+=to_string(cur->val);	// 中
    if (!cur->left && !cur->right) {
        result.push_back(path);
        return;
    }
    // 体会path隐含的回溯
    if (cur->left)
        traversal(cur->left, path+"->", result);	// 左
    if (cur->right)
        traversal(cur->right, path+"->", result);	// 右
}
vector<string> binaryTreePaths(TreeNode* root) {
    string path;
    vector<string> result;
    if(!root) return result;
    traversal(root, path, result);
    return result;
}

参考资料

[1] 代码随想录

[2] Leetcode题解