刷题记录Day18-二叉树(找树左下角的值、路径总和、从中序与后序遍历序列构造二叉树)

刷题记录Day18-二叉树(找树左下角的值、路径总和、从中序与后序遍历序列构造二叉树)


文章目录

  • 刷题记录Day18-二叉树(找树左下角的值、路径总和、从中序与后序遍历序列构造二叉树)
  • 前言
  • 一、找树左下角的值
    • 1. 513找树左下角的值
  • 二、路径总和
    • 1. 112路经总和
    • 2. 113路径总和II
  • 三、 从中序与后序遍历序列构造二叉树
    • 1. 106从中序与后序遍历序列构造二叉树
    • 2. 105从前序与中序遍历序列构造二叉树
  • 总结


前言

题目来源:leetcode
刷题顺序:代码随想录
刷题工具:VSCode+leetcode插件
补充:延毕时间充裕,会结合LeetCode 101: A LeetCode Grinding Guide (C++ Version)相似题目一起做。


一、找树左下角的值

1. 513找树左下角的值

题目:
给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。
假设二叉树中至少有一个节点。

示例:
刷题记录Day18-二叉树(找树左下角的值、路径总和、从中序与后序遍历序列构造二叉树)_第1张图片

输入: root = [2,1,3]
输出: 1

代码:

方法一,前序遍历递归回溯

class Solution {
public:
    int maxDepth = INT_MIN;
    int res;
    void getLeftNum (TreeNode* cur, int depth){
        int left;
        if (cur->left == NULL && cur->right == NULL){  //中
            if (depth > maxDepth){
                maxDepth = depth;
                res = cur->val;
                return;
            }
        } 
        if (cur->left){   //左
            ++depth;
            getLeftNum(cur->left, depth);
            --depth;   //回溯
        }
        if (cur->right){   // 右
            ++depth;
            getLeftNum(cur->right, depth);
            --depth;    //回溯
        }
        return;
    }
    int findBottomLeftValue(TreeNode* root) {
        getLeftNum(root, 0);
        return res;
    }
};

方法二,层序遍历,记录最后一行第一个值

class Solution {
public:
    int findBottomLeftValue(TreeNode* root) {
        int res;
        queue<TreeNode*> que;
        if (root != NULL) que.push(root);
        while (!que.empty()){
            int size = que.size();
            for (int i = 0; i< size; ++i){
                TreeNode* node = que.front();
                que.pop();
                if (i == 0) res = node->val;  //记录最后一行第一个值
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
        }
        return res;
    }
};

二、路径总和

1. 112路经总和

题目:
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。
叶子节点 是指没有子节点的节点。

示例:
刷题记录Day18-二叉树(找树左下角的值、路径总和、从中序与后序遍历序列构造二叉树)_第2张图片

输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
输出:true
解释:等于目标和的根节点到叶节点路径如上图所示。

代码:

方法一,自己写的前序递归回溯

class Solution {
public:
    void getPathSum(TreeNode* cur, int& sum, vector<int>& pathSum){
        sum += cur->val;  //中
        if (cur->left == NULL && cur->right == NULL){  //中止条件
            pathSum.push_back(sum);
            return;
        }
        if (cur->left){     //左
            getPathSum(cur->left, sum, pathSum);
            sum -= cur->left->val;
        }
        if (cur->right){    //右
            getPathSum(cur->right, sum, pathSum);
            sum -= cur->right->val;
        }
        return;
    }
    bool hasPathSum(TreeNode* root, int targetSum) {
        int sum = 0;
        vector<int> pathSum;
        if (root == NULL) return false;
        getPathSum(root, sum, pathSum);
        for (auto i : pathSum){
            if (i == targetSum) return true;
        }
        return false;
    }
};

方法二,代码随想录上的方法
这个方法确实更快,不需要遍历找所有的路径和,用目标值减去当前节点,当目标值变成0且节点已经是叶子节点时,直接返回

class Solution {
private:
    bool traversal(TreeNode* cur, int count) {
        if (!cur->left && !cur->right && count == 0) return true; // 遇到叶子节点,并且计数为0
        if (!cur->left && !cur->right) return false; // 遇到叶子节点直接返回

        if (cur->left) { // 左
            count -= cur->left->val; // 递归,处理节点;
            if (traversal(cur->left, count)) return true;
            count += cur->left->val; // 回溯,撤销处理结果
        }
        if (cur->right) { // 右
            count -= cur->right->val; // 递归,处理节点;
            if (traversal(cur->right, count)) return true;
            count += cur->right->val; // 回溯,撤销处理结果
        }
        return false;
    }

public:
    bool hasPathSum(TreeNode* root, int sum) {
        if (root == NULL) return false;
        return traversal(root, sum - root->val);
    }
};

2. 113路径总和II

题目:
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
叶子节点 是指没有子节点的节点。

示例:
刷题记录Day18-二叉树(找树左下角的值、路径总和、从中序与后序遍历序列构造二叉树)_第3张图片

输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:[[5,4,11,2],[5,8,4,5]]

代码:

方法一,自己写的前序递归回溯

lass Solution {
public:
    void getPathSum(TreeNode* cur, vector<int>& path, vector<vector<int>>& pathAll){
        path.push_back(cur->val);
        if (cur->left == NULL && cur->right == NULL){  //中止条件
            pathAll.push_back(path);
            return;
        }
        if (cur->left){     //左
            getPathSum(cur->left, path, pathAll);
            path.pop_back();
        }
        if (cur->right){    //右
            getPathSum(cur->right, path, pathAll);
            path.pop_back();
        }
        return;
    }
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        vector<int> path;
        vector<vector<int>> pathAll;
        vector<vector<int>> res;
        if (root == NULL) return pathAll;
        getPathSum(root, path, pathAll);
        for (auto i : pathAll){
            if (accumulate(i.begin(),i.end(),0) == targetSum){
                res.push_back(i);
            }
        }
        return res;
    }
};

方法二,代码随想录的方法

class Solution {
public:
    vector<int> path;
    vector<vector<int>> res;
    void traversal(TreeNode* cur, int count){
        if (cur->left == NULL && cur->right == NULL && count == 0){  //中止条件
            res.push_back(path);
            return;
        }
        if (cur->left){     //左
            count -= cur->left->val;
            path.push_back(cur->left->val);
            traversal(cur->left, count);
            count += cur->left->val;
            path.pop_back();
        }
        if (cur->right){    //右
            count -= cur->right->val;
            path.push_back(cur->right->val);
            traversal(cur->right, count);
            count += cur->right->val;
            path.pop_back();
        }
        return;
    }

    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        if (root == NULL) return res;
        path.push_back(root->val);
        traversal(root, targetSum - root->val);
        return res;
    }
};

三、 从中序与后序遍历序列构造二叉树

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

题目:

给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。

示例:

刷题记录Day18-二叉树(找树左下角的值、路径总和、从中序与后序遍历序列构造二叉树)_第4张图片

输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
输出:[3,9,20,null,null,15,7]

代码:

class Solution {
public:
    TreeNode* traversal(vector<int>& inorder, vector<int>& postorder){
        if (postorder.size() == 0) return NULL;

        //第一步,我先在后序数组中的最后一位找到根节点(中)
        int rootval = postorder[postorder.size()-1];
        TreeNode* root = new TreeNode(rootval);

        if (postorder.size() == 1) return root;

        //第二步骤,根据节点值找到它在中序数组的位置index
        int index;
        for (index = 0; index < inorder.size(); ++index){
            if (inorder[index] == rootval) break;
        }

        //第三步,根据index切割中序数组--->得到左中序、右中序
        vector<int> leftInorder(inorder.begin(), inorder.begin() + index);
        vector<int> rightInorder(inorder.begin() + index + 1, inorder.end());

        //第四步,根据左中序大小切割后序数组
        postorder.resize(postorder.size()-1);
        vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size());
        vector<int> rightPostorder(postorder.begin() + leftInorder.size(), postorder.end());

        //迭代
        root->left = traversal(leftInorder, leftPostorder);
        root->right = traversal(rightInorder, rightPostorder);

        return root;
    }
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
       if (inorder.size() == 0 || postorder.size() == 0) return NULL;
       return traversal(inorder, postorder);
    }
};

2. 105从前序与中序遍历序列构造二叉树

题目:
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

示例:
刷题记录Day18-二叉树(找树左下角的值、路径总和、从中序与后序遍历序列构造二叉树)_第5张图片

输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]

代码:

class Solution {
public:
    TreeNode* traversal(vector<int>& preorder, vector<int>& inorder){
        if (preorder.size() == 0) return NULL;
        //第一步,找到根节点
        int rootval = preorder[0];
        TreeNode* root = new TreeNode(rootval);

        if (preorder.size() == 1) return root;

        //第二步,根据节点值找到中序遍历的index
        int index;
        for (index = 0; index < inorder.size(); ++index){
            if (inorder[index] == rootval) break;
        }

        //第三步,根据index切割中序数组--->得到左中序、右中序
        vector<int> leftInorder(inorder.begin(), inorder.begin() + index);
        vector<int> rightInorder(inorder.begin() + index +1, inorder.end());


        //第四步,根据左中序切割前序
        preorder.erase(preorder.begin());

        vector<int> leftPreorder(preorder.begin(), preorder.begin() + leftInorder.size());
        vector<int> rightPreorder(preorder.begin() + leftInorder.size(), preorder.end());

        //递归
        root->left = traversal(leftPreorder, leftInorder);
        root->right = traversal(rightPreorder, rightInorder);

        return root;


    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if (inorder.size() == 0 || preorder.size() == 0) return NULL;
        return traversal(preorder, inorder);
    }
};

总结

今天递归好像稍微好一点了。

你可能感兴趣的:(刷题记录,c++,c语言,leetcode,数据结构,算法)