• 随想录一刷Day18——二叉树


    Day18_二叉树

    16. 找树左下角的值

    513. 找树左下角的值
    思路1:递归法(前序遍历)

    记录遍历到的最大深度,记录该深度下第一个遍历到的元素值,不断更新结果至遍历完所有的结点,即找到最大值。

    class Solution {
    public:
        int MaxDepth = -1;
        int result = INT_MAX;
        void tranversal(TreeNode* root, int Depth) {
            if (root->left == NULL && root->right == NULL) {
                if (Depth > MaxDepth) { // 大于是为了保证最深层的result是最左结点的值
                    MaxDepth = Depth;
                    result = root->val;
                }
                return ;
            }
            if (root->left) tranversal(root->left, Depth + 1);
            if (root->right) tranversal(root->right, Depth + 1);
            return ;
        }
    
        int findBottomLeftValue(TreeNode* root) {
            // 题目要求是至少有一个结点,即不存在第一节点为空的情况
            tranversal(root, 0);
            return result; 
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    思路2:迭代法(层序遍历)

    层序遍历记录每层的第一个元素,答案为最后一层的第一个元素

    class Solution {
    public:
        int findBottomLeftValue(TreeNode* root) {
            // 题目要求是至少有一个结点,即不存在第一节点为空的情况
            int result;
            queue<TreeNode*> que;
            que.push(root);
            while (!que.empty()) {
                int que_size = que.size();
                for (int i = 0; i < que_size; i++) {
                    TreeNode* node = que.front();
                    que.pop();
                    if (i == 0) result = node->val;
                    if (node->left) que.push(node->left);
                    if (node->right) que.push(node->right);
                }
            }
            return result;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    17. 路径总和

    112. 路径总和
    思路:

    先序遍历,在叶子节点处判断路径和是否满足条件

    class Solution {
    public:
        bool ans_flag = false;
        void tranversal(TreeNode* root, int sum) {
            if (ans_flag) return ;
            if (root->left == NULL && root->right == NULL) { // 到叶子节点再判断是否满足
                if (sum == 0) {
                    ans_flag = true;
                }
                return ;
            }
            if (root->left) tranversal(root->left, sum - root->left->val);
            if (root->right) tranversal(root->right, sum - root->right->val);
        }
    
        bool hasPathSum(TreeNode* root, int targetSum) {
            if (root == NULL) return false;
            tranversal(root, targetSum - root->val);
            return ans_flag;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    精简递归的写法

    class Solution {
    public:
        bool hasPathSum(TreeNode* root, int targetSum) {
            if (root == NULL) return false;
            if (!root->left && !root->right && targetSum == root->val) return true;
            return hasPathSum(root->left, targetSum - root->val) | hasPathSum(root->right, targetSum - root->val);
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    利用栈模拟递归回溯

    class Solution {
    public: 
        // 先序遍历
        bool hasPathSum(TreeNode* root, int targetSum) {
            if (root == NULL) return false;
            stack<pair<TreeNode*, int>> stk;
            stk.push(pair<TreeNode*, int>(root, root->val));
            while (!stk.empty()) {
                pair<TreeNode*, int> node = stk.top();
                stk.pop();
                if (!node.first->left && !node.first->right && node.second == targetSum) return true; // 中
                if (node.first->right) stk.push({node.first->right, node.second + node.first->right->val}); // 右
                if (node.first->left) stk.push({node.first->left, node.second + node.first->left->val}); // 左
    
            }
            return false;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    18. 从中序与后序遍历序列构造二叉树

    106. 从中序与后序遍历序列构造二叉树
    思路:

    根据中序和后续的遍历顺序特点,互相配合构造出二叉树
    后续遍历 左 右 中,最后一个元素作为当前子树的根节点
    中序遍历 左 中 右,子树的根结点左边为左子树值,右边为右子树值
    反复递归划分区间,直到区间大小全部划分为1,回溯构造二叉树

    class Solution {
    private:
        TreeNode* tranversal(vector<int> inorder, vector<int> postorder) {
            if (postorder.size() == 0) return NULL;
    
            // 后序遍历数组中的最后一个元素作为当前的子树的根
            int root_value = postorder[postorder.size() - 1];
            TreeNode* root = new TreeNode(root_value);
    
            // 左右递归至只有一个元素,子树的建立完成
            if (postorder.size() == 1) return root;
    
            // 找到中序遍历的切割点
            int divide_index;
            for (int i = 0; i < inorder.size(); i++) {
                if (inorder[i] == root_value) {
                    divide_index = i;
                    break;
                }
            }
    
            // 切割中序遍历数组,左闭右开
            vector<int> leftInorder(inorder.begin(), inorder.begin() + divide_index);
            vector<int> rightInorder(inorder.begin() + divide_index + 1, inorder.end());
    
            // posterorder 舍弃末尾元素
            postorder.resize(postorder.size() - 1);
    
            // 切割后续数组,左闭右开,由于遍历顺序导致中序和后续前一部分都是左子树的遍历结果,所以后续和中序划分方式相同
            vector<int> leftPosterorder(postorder.begin(), postorder.begin() + divide_index);
            vector<int> rightPosterorder(postorder.begin() + divide_index, postorder.end());
    
            root->left = tranversal(leftInorder, leftPosterorder);
            root->right = tranversal(rightInorder, rightPosterorder);
            
            return root;
        }
    
    public:
        TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
            if (inorder.size() == 0) return NULL;
            return tranversal(inorder, postorder);
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
  • 相关阅读:
    1.1数据结构的基本概念
    Leetcode刷题方法总结---链表全解
    基于ssm的疫情时期药物管理系统设计与实现-计算机毕业设计源码+LW文档
    C#线索二叉树的定义
    Windows 下 MSVC 编译器在 CMake 生成时提示 RC failed 或库文件缺失
    HTML5新特性
    Java IDEA feign调用上传文件MultipartFile以及实体对象亲测可行
    Java开发从入门到精通(五):JDK9-JDK16 新特性
    要写文档了,emmm,先写个文档工具吧——DocMarkdown
    基于RabbitMQ的模拟消息队列之四——内存管理
  • 原文地址:https://blog.csdn.net/zhiai_/article/details/127828011