二叉树Part03

110.平衡二叉树

题目描述:给定一颗二叉树,判断它是否是平衡二叉树。

递归法

后序遍历

本题适合采用后序遍历,先遍历完左右子树,从底部开始累加高度。

  • 后序遍历
class Solution {
public:
  int getHight(TreeNode *node) {
    // 终止条件
    if (!node) {
      return 0;
    }
    // 计算左右子树高度
    int left = getHight(node->left);
    if (left == -1) {
      return -1;
    }
    int right = getHight(node->right);
    if (right == -1) {
      return -1;
    }
    // 中,处理刚刚左右节点的父节点,也就是中
    return abs(left - right) > 1 ? -1 : 1 + max(left, right);
  }

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

257.二叉树的所有路径

题目描述:给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。叶子节点 是指没有子节点的节点。

递归法

  • 参数和返回类型:当前节点,当前路径,结果
  • 终止条件:走到了叶子结点,处理收集到的节点
  • 单层逻辑:先走当前节点左边的节点,收集结果,再回溯到当前节点,再收集结果

思路

先向下找到最深的一条路,然后返回(回溯)到上一级,走另一条路,如果没有另一条路也是直接再回溯到上一个节点。

关于回溯的理解

当一条路遍历到了最底层的时候,回溯到上一个节点,如果这时候path不是一个引用的话(见下方另一个版本),相当于直接回溯了一次,因为递归返回一次到达上一个stack frame的时候,path也应该回到上一个stack frame中的状态,但是下面的代码用的是引用,所以path相对于每一次递归而言并不是局部变量,所以递归返回的时候path并没有做回溯,所以需要手动的pop一次来达成回溯的目的。

  • 直接体现回溯的代码(前序遍历)
class Solution {
private:
  void traversal(TreeNode *node, vector<int>& path, vector<string>& res) {
    path.push_back(node->val); // 中
    //终止条件,以及处理收集到的节点的逻辑
    if (node->left == NULL && node->right == NULL) {
      string sPath;
      for (int i = 0 ;i < path.size() - 1;i++) {
        sPath += to_string(path[i]);
        sPath += "->";
      }
      sPath += to_string(path[path.size() - 1]);
      res.push_back(sPath);
      return;
    }

    if (node->left) {
      traversal(node->left, path, res);
      path.pop_back();//回溯
    }

    if (node->right) {
      traversal(node->right, path, res);
      path.pop_back();//回溯
    }
  }

public:
  vector<string> binaryTreePaths(TreeNode *root) {
    vector<string> res;
    vector<int> path;
    traversal(root, path, res);
    return res;
  }
};
  • 更加简洁的代码(前序遍历)
class Solution {
private:

    void traversal(TreeNode* cur, string path, vector<string>& result) {
        path += to_string(cur->val); // 中
        if (cur->left == NULL && cur->right == NULL) {
            result.push_back(path);
            return;
        }
        if (cur->left) traversal(cur->left, path + "->", result); // 左 回溯
        if (cur->right) traversal(cur->right, path + "->", result); // 右 回溯
    }

public:
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> result;
        string path;
        if (root == NULL) return result;
        traversal(root, path, result);
        return result;

    }
};

404.左叶子之和

题目描述:给定二叉树的根节点 root ,返回所有左叶子之和。

递归法

我自己的解法

思路
  • 终止条件是当前节点没有左右节点
  • 左子树按照以往的方式正常处理,而右子树需要判断右节点是否含有左右子树,如果有就处理,没有就不处理。
  • 遍历方法:一种特殊的遍历
class Solution {
public:
  void getLeft(TreeNode *node, vector<int> &res) {

    // 终止条件
    if (node->left == NULL && node->right == NULL) {
      res.push_back(node->val);
      return;
    }

    //左
    if (node->left) {
      getLeft(node->left, res);
    }

    //右
    if (node->right && (node->right->left || node->right->right)) {
      getLeft(node->right, res);
    }
  }
  int sumOfLeftLeaves(TreeNode *root) {
    int sum = 0;
    vector<int> res;
    if (!root->left && !root->right) {
      return 0;
    }
    getLeft(root, res);
    for (int i : res) {
      sum += i;
    }
    return sum;
  }
};

官方题解

思路

将右子树的处理逻辑和左子树统一化,处理左子树的时候,遍历到左右节点都为空的时候返回,将左节点的值拿到,回溯,然后遍历右子树,将右节点传入递归函数时,走的还是左子树的处理逻辑。总之要好好理解递归,当栈帧没有完全被释放的时候,return的值总会是传递到上一个栈帧中,比如说前一个的sum作为返回值传递到上一个的leftValue中,这一点要好好理解。

  • 后序遍历
class Solution {
public:
    int sumOfLeftLeaves(TreeNode* root) {
        if (root == NULL) return 0;
        if (root->left == NULL && root->right== NULL) return 0;

        int leftValue = sumOfLeftLeaves(root->left);    // 左
        if (root->left && !root->left->left && !root->left->right) { // 左子树就是一个左叶子的情况
            leftValue = root->left->val;
        }
        int rightValue = sumOfLeftLeaves(root->right);  // 右

        int sum = leftValue + rightValue;               // 中
        return sum;
    }
};

222.完全二叉树的节点个数

题目描述:给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。

按照普通二叉树来解题

思路

简单的遍历并累加

迭代法

使用层序遍历能很方便的得到答案,所以不赘述。

  • 层序遍历
class Solution {
public:
    int countNodes(TreeNode* root) {
        queue<TreeNode*> que;
        if (root != NULL) que.push(root);
        int result = 0;
        while (!que.empty()) {
            int size = que.size();
            for (int i = 0; i < size; i++) {
                TreeNode* node = que.front();
                que.pop();
                result++;   // 记录节点数量
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
        }
        return result;
    }
};

递归法

  • 后序遍历
class Solution {
private:
    int getNodesNum(TreeNode* cur) {
        if (cur == NULL) return 0;
        int leftNum = getNodesNum(cur->left);      // 左
        int rightNum = getNodesNum(cur->right);    // 右
        int treeNum = leftNum + rightNum + 1;      // 中
        return treeNum;
    }
public:
    int countNodes(TreeNode* root) {
        return getNodesNum(root);
    }
};

利用完全二叉树特性

满二叉树节点数=2^h - 1

思路

将完全二叉树划分为几个满二叉树,利用公式计算

Pasted image 20240728144712.png

Pasted image 20240728144720.png

  • 判断子树是否为满二叉树的逻辑
    向左遍历深度等于向右遍历深度的时候,就说明为满二叉树

Pasted image 20240728144901.png

  • 后序遍历
class Solution {
public:
    int countNodes(TreeNode* root) {
        if (root == nullptr) return 0;
        TreeNode* left = root->left;
        TreeNode* right = root->right;
        int leftDepth = 0, rightDepth = 0; // 这里初始为0是有目的的,为了下面求指数方便
        while (left) {  // 求左子树深度
            left = left->left;
            leftDepth++;
        }
        while (right) { // 求右子树深度
            right = right->right;
            rightDepth++;
        }
        if (leftDepth == rightDepth) {
            return (2 << leftDepth) - 1; // 注意(2<<1) 相当于2^2,所以leftDepth初始为0
        }
        return countNodes(root->left) + countNodes(root->right) + 1;
    }
};
暂无评论

发送评论 编辑评论


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