二叉树Part02

226.翻转二叉树

初印象: 感觉层序遍历一遍再倒过来就好了...

思路

实际上只要遍历每个节点并反转其左右孩子就可以了,因此用其他遍历方法都能做,除了递归法的中序遍历做不了,因为递归法的中序遍历会将某些节点的左右孩子翻转两次(按照左中右的顺序的话,先判断左,翻转,在判断右,这样的话此时的右就是刚刚被翻转过来的左)。

递归法

class Solution {
public:
  TreeNode *invertTree(TreeNode *root) {
    if (root == NULL) {
      return root;
    }
    swap(root->left, root->right);
    invertTree(root->left);
    invertTree(root->right);
    return root;
  }
};

迭代法

class Solution {
public:
  TreeNode *invertTree(TreeNode *root) {
    stack<TreeNode *> st;
    if (root) {
      st.push(root);
    }
    while (!st.empty()) {
      TreeNode *cur = st.top();
      st.pop();
      swap(cur->left, cur->right);
      if (cur->right) {
        st.push(cur->right);
      }
      if (cur->left) {
        st.push(cur->left);
      }
    }
    return root;
  }
};

101.对称二叉树

递归法

  • 参数和返回值:
    比较的是左右子树,返回值是布尔类型

  • 终止条件

    • 左右一个为空一个不为空->false
    • 左右都不为空但是值不相等->false
    • 左右都为空->true
  • 每层逻辑:
    比较outside和inside,只要出现了左右不相等的情况,递归立马停止,返回值。如果递归到左右子树都是空的时候,那也就是遍历完了,就返回true。

  • 后序遍历(不是严格的后序遍历)

class Solution {
public:
  bool isEqual(TreeNode *left, TreeNode *right) {
    if (left == NULL && right != NULL) {
      return false;
    } else if (left != NULL && right == NULL) {
      return false;
    } else if (left == NULL && right == NULL) {
      return true;
    } else if (left->val != right->val) {
      return false;
    }

    bool outSide = isEqual(left->left, right->right);
    bool inSide = isEqual(left->right, right->left);
    bool equal = outSide && inSide;
    return equal;
  }
  bool isSymmetric(TreeNode *root) {
    if (root == NULL) {
      return false;
    }
    return isEqual(root->left, root->right);
  }
};
  • 简化的代码
class Solution {
public:
    bool compare(TreeNode* left, TreeNode* right) {
        if (left == NULL && right != NULL) return false;
        else if (left != NULL && right == NULL) return false;
        else if (left == NULL && right == NULL) return true;
        else if (left->val != right->val) return false;
        else return compare(left->left, right->right) && compare(left->right, right->left);

    }
    bool isSymmetric(TreeNode* root) {
        if (root == NULL) return true;
        return compare(root->left, root->right);
    }
};

迭代法

思路

将左右节点的左右孩子同时压入栈,由外层至内层的比较。

  • 遍历方法:并不属于前中后序遍历,也不是层序遍历
class Solution {
public:
  bool isEqual(TreeNode *cur) {
	//初始化
    stack<TreeNode *> st;
    st.push(cur->right);
    st.push(cur->left);
    while (!st.empty()) {
	//更新逻辑
      TreeNode *leftNode = st.top();
      st.pop();
      TreeNode *rightNode = st.top();
      st.pop();
	//判断逻辑
      if (!leftNode && !rightNode) {
        continue;
      }
      if ((!leftNode || !rightNode || (leftNode->val != rightNode->val))) {
        return false;
      }
	//单层处理逻辑
      st.push(rightNode->right);
      st.push(leftNode->left);
      st.push(rightNode->left);
      st.push(leftNode->right);
      
    }
    return true;
  }
  bool isSymmetric(TreeNode *root) {
    if (root == NULL) {
      return false;
    }
    return isEqual(root);
  }
};

104.二叉树的最大深度

递归法

本题可以使用前序(中左右),也可以使用后序遍历(左右中),使用前序求的就是深度,使用后序求的是高度。因为前序是先处理的是深度,所以进入下一个节点的时候首先加深度,也就是从上往下。而后序是先遍历完左右子树,到了底部达成递归终止条件,再通过递归增加高度,是从下往上的增加高度。

高度和深度是相反的表示,深度是从上到下数的,而高度是从下往上数。所以树的深度和高度是相等的,而对其他节点来说深度和高度不一定相等。

  • 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数或者节点数(取决于深度从0开始还是从1开始)

  • 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数或者节点数(取决于高度从0开始还是从1开始)

  • 后序遍历
    实际上就是先让左边搜索到最底层,再让右边搜索到最底层,然后再再递归函数栈归的过程中不断的增加高度。比较哪个高度高。

class Solution {
public:
  int maxDepth(TreeNode *root) {
    if (!root) {
      return 0;
    }
    int left = maxDepth(root->left);
    int right = maxDepth(root->right);
    int depth = 1+max(left, right);
    return depth;
  }
};
  • 前序遍历(深度回溯)
    先遍历左子树到最深,然后再回溯遍历上一个节点的右子树,如果没有就接着回溯。

    这里更新节点到上一个回溯点(实际上并没有主动更新,而是通过函数调用自动更新的)是通过递归栈归来实现的,可以想像递归是一系列盒子,当前盒子里就保存着当前节点,当最下面的盒子被释放的时候(递归达到终止),就返回到上一个盒子里了,而上一个盒子里装的是之前存放在盒子里的节点。也就是stack frame里面的东西。

  • 来自claude3.5的解释
    "盒子"实际上就是我们在计算机科学中称为"栈帧"(Stack Frame)的概念。每次函数调用都会在调用栈上创建一个新的栈帧。我们可以把这个过程想象成这样:

    1. 盒子(栈帧)的内容:
      每个"盒子"(栈帧)里不仅存放当前节点的信息,还包括:

      • 局部变量(如当前的 depth 值)
      • 函数参数
      • 返回地址(告诉程序当前函数执行完毕后应该返回到哪里)
    2. 递归过程:

      • 每次递归调用 getdepth 函数时,都会在调用栈上放置一个新的"盒子"(创建新的栈帧)。
      • 这个新"盒子"位于前一个"盒子"的上面。
      • 每个"盒子"都保存了其对应节点的信息和当前的 depth 值。
    3. 回溯过程:

      • 当递归达到终止条件(如遇到叶节点),最上面的"盒子"完成其任务。
      • 这个"盒子"被移除(栈帧被弹出),控制权返回到下面的"盒子"。
      • 返回过程中,程序自动恢复到下面"盒子"所保存的状态,包括节点信息和其他局部变量。
    4. 深度调整:

      • 代码中的 depth-- 操作确保了当我们回到上一层"盒子"时,深度值与当前节点位置保持一致。
      • 这不改变节点,而是调整与节点关联的深度计数。
    5. 整体视角:

      • 整个递归过程可以看作是在调用栈上"盒子"的不断堆叠和移除。
      • 每个"盒子"代表树中的一个节点和其状态。
      • "盒子"的堆叠对应树的深度优先遍历。
      • "盒子"的移除对应从深层节点回溯到浅层节点。
    6. 优势:

      • 这种机制允许程序在遍历树时保持每个节点的上下文信息。
      • 回溯变得简单,因为前一个节点的所有信息都保存在它的"盒子"(栈帧)中。
class Solution {
public:
    int result;
    void getdepth(TreeNode* node, int depth) {
        result = depth > result ? depth : result; // 中

        if (node->left == NULL && node->right == NULL) return ;

        if (node->left) { // 左
            depth++;    // 深度+1
            getdepth(node->left, depth);
            depth--;    // 回溯,深度-1
        }
        if (node->right) { // 右
            depth++;    // 深度+1
            getdepth(node->right, depth);
            depth--;    // 回溯,深度-1
        }
        return ;
    }
    int maxDepth(TreeNode* root) {
        result = 0;
        if (root == NULL) return result;
        getdepth(root, 1);
        return result;
    }
};

迭代法

层序遍历在之前二叉树Part01写过了,这里不放代码了

111.二叉树的最小深度

递归法

  • 后序遍历(高度)
class Solution {
public:
    int getDepth(TreeNode* node) {
        if (node == NULL) return 0;
        int leftDepth = getDepth(node->left);           // 左
        int rightDepth = getDepth(node->right);         // 右
                                                        // 中
        // 当一个左子树为空,右不为空,这时并不是最低点
        if (node->left == NULL && node->right != NULL) { 
            return 1 + rightDepth;
        }   
        // 当一个右子树为空,左不为空,这时并不是最低点
        if (node->left != NULL && node->right == NULL) { 
            return 1 + leftDepth;
        }
        int result = 1 + min(leftDepth, rightDepth);
        return result;
    }

    int minDepth(TreeNode* root) {
        return getDepth(root);
    }
};
  • 前序遍历(深度)
class Solution {
private:
    int result;
    void getdepth(TreeNode* node, int depth) {
        // 函数递归终止条件
        if (node == nullptr) {
            return;
        }
        // 中,处理逻辑:判断是不是叶子结点
        if (node -> left == nullptr && node->right == nullptr) {
            result = min(result, depth);
        }
        if (node->left) { // 左
            getdepth(node->left, depth + 1);
        }
        if (node->right) { // 右
            getdepth(node->right, depth + 1);
        }
        return ;
    }

public:
    int minDepth(TreeNode* root) {
        if (root == nullptr) {
            return 0;
        }
        result = INT_MAX;
        getdepth(root, 1);
        return result;
    }
};

迭代法

二叉树Part01写过了,不再赘述

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇