当前位置: 首页 > news >正文

刷题 二叉树

二叉树的核心思想 - 递归 - 将问题分解为子问题

题型

  • 递归遍历
  • 迭代遍历
  • 层序遍历 bfs:队列
  • 各种递归题目:将问题分解为子问题
  • 二叉搜索树 - 中序遍历是递增序列 TreeNode* &prev 指针
  • 树形dp

面试经典 150 题 - 二叉树

104. 二叉树的最大深度

在这里插入图片描述

广度优先遍历

class Solution {
public:
    // 广度优先遍历
    int maxDepth(TreeNode* root) {
        if (root == nullptr) return 0;
        queue<TreeNode*> que;
        que.push(root);
        int result = 0;
        while (!que.empty()) {
            ++result;
            int num = que.size();
            while (num--) {
                TreeNode* cur = que.front();
                que.pop();
                if (cur->left) que.push(cur->left);
                if (cur->right) que.push(cur->right);
            }
        }
        return result;
    }
};

递归

最大深度 = 1 + max(左子树最大深度, 右子树最大深度)

class Solution {
public:
    // 递归:最大深度 = 1 + max(左子树最大深度, 右子树最大深度)
    int maxDepth(TreeNode* root) {
        if (root == nullptr) return 0;
        return 1 + max(maxDepth(root->left), maxDepth(root->right));
    }
};

100. 相同的树

在这里插入图片描述

递归

树相同 --> 根节点相同 + 左子树相同 + 右子树相同

class Solution {
public:
    // 递归
    // 树相同 --> 根节点相同 + 左子树相同 + 右子树相同
    bool isSameTree(TreeNode* p, TreeNode* q) {
        if (p == nullptr && q == nullptr) {
            return true;
        } else if (p == nullptr || q == nullptr) {
            return false;
        }
        if (p->val != q->val) {
            return false;
        }
        if (isSameTree(p->left, q->left) == false) {
            return false;
        }
        if (isSameTree(p->right, q->right) == false) {
            return false;
        }
        return true;
    }
};

226. 翻转二叉树

在这里插入图片描述

递归

class Solution {
public:
    // 翻转二叉树 --> 
    // 根节点的左子树 = 将右子树进行反转
    // 根节点的右子树 = 将左子树进行反转
    TreeNode *invertTree(TreeNode *root) {
        if (root == nullptr) return nullptr;
        auto left = invertTree(root->left); // 翻转左子树
        auto right = invertTree(root->right); // 翻转右子树
        root->left = right; // 交换左右儿子
        root->right = left;
        return root;
    }
};

⭐️⭐️112. 路径总和

在这里插入图片描述

回溯

class Solution {
public:
    // 回溯
    bool backtracking(TreeNode* root, int path_sum, int targetSum) { 
        if (root == nullptr) return false;
        if (root->right == nullptr && root->left == nullptr) {  // 到达叶子节点,终止回溯
            return (path_sum + root->val == targetSum);
        }
        return (backtracking(root->left, path_sum + root->val, targetSum) || \
                backtracking(root->right, path_sum + root->val, targetSum));
    }
    bool hasPathSum(TreeNode* root, int targetSum) {
        return backtracking(root, 0, targetSum);
    }
};

⭐️⭐️迭代

class Solution {
public:
    // 递归: 树 存在和为 targetSum
    // 也即左子树存在和为 targetSum - root->val 或者 右子树存在和为 targetSum - root->val
    bool hasPathSum(TreeNode* root, int targetSum) {
        if (root == nullptr) return false;
        if (root->left == nullptr && root->right == nullptr) {
            return (targetSum == root->val); 
        } 
        return (hasPathSum(root->left, targetSum - root->val) || \
                hasPathSum(root->right, targetSum - root->val));
    }
};

层序遍历

比较简单,不做讨论

面试经典 150 题 - 二叉树层次遍历

199. 二叉树的右视图

class Solution {
public:
    vector<int> rightSideView(TreeNode* root) {
        if (root == nullptr) return vector<int>{};
        queue<TreeNode*> que;
        que.push(root);
        vector<int> result;
        while (!que.empty()) {
            size_t n = que.size();
            for (size_t i = 0; i < n; ++i) {
                TreeNode* cur = que.front();
                que.pop();
                if (cur->left) que.push(cur->left);
                if (cur->right) que.push(cur->right);
                if (i ==  n - 1) result.push_back(cur->val);
            }
        }
        return result;
    }
};

637. 二叉树的层平均值

class Solution {
public:
    vector<double> averageOfLevels(TreeNode* root) {
        if (root == nullptr) return vector<double>{};
        queue<TreeNode*> que;
        que.push(root);
        vector<double> result;
        while (!que.empty()) {
            size_t n = que.size();
            double sum = 0.0;
            for (size_t i = 0; i < n; ++i) {
                TreeNode* cur = que.front();
                que.pop();
                if (cur->left) que.push(cur->left);
                if (cur->right) que.push(cur->right);
                sum += cur->val;
            }
            result.push_back(sum / n);
        }
        return result;
    }
};

[102. 二叉树的层序遍历

](https://leetcode.cn/problems/binary-tree-level-order-traversal/?envType=study-plan-v2&envId=top-interview-150)

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        if (root == nullptr) return vector<vector<int>>{};
        queue<TreeNode*> que;
        que.push(root);
        vector<vector<int>> result;
        while (!que.empty()) {
            size_t n = que.size();
            vector<int> layer(n, 0);
            for (size_t i = 0; i < n; ++i) {
                TreeNode* cur = que.front();
                que.pop();
                if (cur->left) que.push(cur->left);
                if (cur->right) que.push(cur->right);
                layer[i] = cur->val;
            }
            result.push_back(layer);
        }
        return result;
    }
};

103. 二叉树的锯齿形层序遍历 - 写入的时候改一下索引即可

在这里插入图片描述

class Solution {
public:
    vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
        if (root == nullptr) return vector<vector<int>>{};
        queue<TreeNode*> que;
        que.push(root);
        vector<vector<int>> result;
        bool to_right = false;
        while (!que.empty()) {
            to_right = !to_right;
            size_t n = que.size();
            vector<int> layer(n, 0);
            for (size_t i = 0; i < n; ++i) {
                TreeNode* cur = que.front();
                que.pop();
                if (cur->left) que.push(cur->left);
                if (cur->right) que.push(cur->right);
                if (to_right) {
                    layer[i] = cur->val;
                } else {
                    layer[n - 1 - i] = cur->val;
                }
            }
            result.push_back(layer);
        }
        return result;
    }
};

面试经典 150 题 - 二叉搜索树 - ⭐️TreeNode*& prev⭐️ - 中序遍历有序

98. 验证二叉搜索树

class Solution {
public:
    bool traversal(TreeNode* root, TreeNode*& prev) {
        if (root == nullptr) return true;
        if (!traversal(root->left, prev)) return false;
        if (prev != nullptr && prev->val >= root->val) return false;
        prev = root;
        return traversal(root->right, prev);
    }

    bool isValidBST(TreeNode* root) {
        TreeNode* prev = nullptr;
        return traversal(root, prev);
    }
};

530. 二叉搜索树的最小绝对差

在这里插入图片描述

使用数组暂存

class Solution {
public:
    // 二叉搜索树的特征:左子树 < 根节点 < 右子树
    // 中序遍历即可获得最小差值
    void traversal(TreeNode* root, vector<int>& vals, int& min_diff) {
        if (root == nullptr) return;
        traversal(root->left, vals, min_diff);
        if (!vals.empty()) min_diff = min(min_diff, root->val - vals.back()); 
        vals.push_back(root->val);
        traversal(root->right, vals, min_diff);
    }
    int getMinimumDifference(TreeNode* root) {
        vector<int> vals;
        int min_diff = INT_MAX;
        traversal(root, vals, min_diff);
        return min_diff;
    }
};

⭐️优化 - 使用一个 prev_val 即可

class Solution {
public:
    // 二叉搜索树的特征:左子树 < 根节点 < 右子树
    // 中序遍历即可获得最小差值
    // 如果不想使用数组暂存的话就需要存储一个 prev 指针
    void traversal(TreeNode* root, TreeNode*& prev, int& min_diff) {
        if (root == nullptr) return;
        traversal(root->left, prev, min_diff);
        if (prev != nullptr) min_diff = min(min_diff, root->val - prev->val); 
        prev = root;
        traversal(root->right, prev, min_diff);
    }
    int getMinimumDifference(TreeNode* root) {
        int min_diff = INT_MAX;
        TreeNode* prev = nullptr;
        traversal(root, prev, min_diff);
        return min_diff;
    }
};

230. 二叉搜索树中第 K 小的元素 - 想象用数组存储元素 - 实际只使用索引即可 - 注意终止条件

class Solution {
public:
    void traversal(TreeNode* root, int& val, int& count, int k) {
        if (root == nullptr || count >= k) return;  // 递归终止条件
        traversal(root->left, val, count, k);
        ++count;    // 如果用数组存储元素,想象这里是数组的第 count 个数字(从0开始)
        if (count == k) {
            val = root->val;
            return;
        }
        traversal(root->right, val, count, k);
    }
    int kthSmallest(TreeNode* root, int k) {
        int val, count = 0;
        traversal(root, val, count, k);
        return val;
    }
};

相关文章:

  • 行盒的截断样式 box-decoration-break
  • 计算机网络思维导图
  • Python绘制--绘制心形曲线
  • 无人机之飞行算法篇
  • Linux dlsym和直接调用函数地址解析分析
  • 相机基础概念
  • 电源管理芯片PMIC
  • 网站集群批量管理-Ansible(playbook)
  • Hive数仓操作(七)
  • 昇思学习打卡营第31天|深度解密 CycleGAN 图像风格迁移:从草图到线稿的无缝转化
  • 考研笔记之操作系统(三)- 存储管理
  • 探索Spring Boot:教学资源大全
  • 国庆作业
  • RDD的介绍、RDD的特点、创建RDD数据
  • 序列化与反序列化基础及反序列化漏洞(附案例)
  • SQL第14课挑战题
  • 如何用python抓取豆瓣电影TOP250
  • linux系统不同用户登录vnc
  • 逼近理论及应用精解【12】
  • (11)(2.1.4) DroneCAN ESCs
  • “不为一时一事所惑,不为风高浪急所扰”——习近平主席对俄罗斯进行国事访问并出席纪念苏联伟大卫国战争胜利80周年庆典纪实
  • 陈宝良 高寿仙 彭勇︱明清社会的皇权、商帮与市井百态
  • 国常会:研究深化国家级经济技术开发区改革创新有关举措等
  • 江西暴雨强对流明显,专家:落雨区高度重叠,地质灾害风险高
  • 玉渊谭天丨一艘航母看中国稀土出口管制为何有效
  • 美众议院通过法案将“墨西哥湾”更名为“美国湾”