代码随想录算法训练营第十八天 | 513.找树左下角的值、112. 路径总和、113. 路径总和Ⅱ、106.从中序与后序遍历序列构造二叉树、105.从前序与中序遍历序列构造二叉树

题目链接:leetcode 513.找树左下角的值

文章讲解:代码随想录 513.找树左下角的值讲解

视频讲解:怎么找二叉树的左下角? 递归中又带回溯了,怎么办?| LeetCode:513.找二叉树左下角的值

思路和解法

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

假设二叉树中至少有一个节点。
想法:
递归+回溯的方法,遵循递归函数的思考规则。记录深度,深度要回溯。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int maxDepth = INT_MIN;
    int result;
    //递归函数 输入参数:节点指针 当前层深度 无返回值
    void traversal(TreeNode* node, int depth) {
        //终止条件 遍历到了叶子节点 判断是否是最大深度,如果是最大深度要更新结果值,一定要大于才更新,等于不用更新
        //因为采用先左后右的方式深度遍历,这样在遇到新的一层最左边的叶子节点时才会更新结果,保证是最左边节点的值
        if (!node -> left && !node -> right) {
            if (depth > maxDepth) {
                maxDepth = depth;
                result = node -> val;
                return ;
            }
        }
        if (node -> left) {
            //隐藏回溯
            traversal(node -> left, depth + 1);
        }
        if (node -> right) {
            //隐藏回溯
            traversal(node -> right, depth + 1);
        }
        return ;
    }

    int findBottomLeftValue(TreeNode* root) {
        //迭代法层序遍历更简单,这里复习递归法和回溯
        traversal(root, 1);
        return result;
    }
};

题目链接:leetcode 112. 路径总和

文章讲解:代码随想录 112. 路径总和讲解

视频讲解:拿不准的遍历顺序,搞不清的回溯过程,我太难了! | LeetCode:112. 路径总和

思路和解法

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

叶子节点 是指没有子节点的节点。
想法:
技巧:用目标值减当前节点值向下递归。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    //递归+回溯 直接利用原函数作为递归函数 定义递归函数的意义为:返回当前节点是否为满足目标和的路径
    bool hasPathSum(TreeNode* root, int targetSum) {
        if (root == nullptr) return false;
        //终止条件 遇到叶子节点 判断路径值和是否等于目标和
        if (!root -> left && !root -> right && targetSum == root -> val) return true;
        if (!root -> left && !root -> right) return false;
        if (root -> left) {
            if (hasPathSum(root -> left, targetSum - root -> val)) return true;
        }
        if (root -> right) {
            if (hasPathSum(root -> right, targetSum - root -> val)) return true;
        }
        return false;
    }
};

题目链接:leetcode 113. 路径总和Ⅱ

思路和解法

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

叶子节点 是指没有子节点的节点。
想法:
这个是自己写的,有了上一道题的经验,加入path记录路径,注意回溯就行了。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    //存结果
    vector<vector<int>> result;
    //递归函数 递归+回溯 path记录路径节点值 引用需要回溯
    void traversal(TreeNode* node, int targetSum, vector<int>& path) {
        if (node == nullptr) return ;
        path.push_back(node -> val);
        //终止条件
        if (!node -> left && !node -> right && targetSum == node -> val) {
            result.push_back(path);
        }
        if (node -> left) {
            traversal(node -> left, targetSum - node -> val, path);
            //回溯
            path.pop_back();
        }
        if (node -> right) {
            traversal(node -> right, targetSum - node -> val, path);
            //回溯
            path.pop_back();
        }
        return ;
    }
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        vector<int> path;
        traversal(root, targetSum, path);
        return result;
    }
};

题目链接:leetcode 106.从中序与后序遍历序列构造二叉树

文章讲解:代码随想录 106.从中序与后序遍历序列构造二叉树讲解

视频讲解:拿不准的遍历顺序,搞不清的回溯过程,我太难了! | LeetCode:112. 路径总和

思路和解法

题目:
给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
想法:
二叉树序列化,之前学习过,这次加深印象。==注意理清逻辑,脑子里要一直想着两个表会好写一些。==统一不变量,即左闭右开区间。可以用下标简化表示,这里我就直接用下标去写的,中间犯了一个错误,终止条件少考虑了一种。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    //用索引表示分割出的区间 统一规定采用左闭右开
    //递归函数 返回以下标表示的区间内的中序 后序遍历形成的二叉树根节点
    TreeNode* traversal(vector<int>& inorder, int inorderBegin, int inorderEnd, vector<int>& postorder, int postorderBegin, int postorderEnd) {
        //这里犯了错误 少写这个导致bug
        if (postorderBegin == postorderEnd) return nullptr;
        //终止条件 只剩一个值
        if (inorderEnd - 1 == inorderBegin) {
            TreeNode* node = new TreeNode(inorder[inorderBegin]);
            return node;
        }
        //通过后序遍历确认当前构成树的根节点的值
        int val = postorder[postorderEnd - 1];
        TreeNode* node = new TreeNode(val);
        //递归遍历填上左右子树的节点地址
        //确认中序遍历的分隔区间
        int delimiterIndex;
        for (delimiterIndex = inorderBegin; delimiterIndex < inorderEnd; delimiterIndex++) {
            if (inorder[delimiterIndex] == val) break;
        }
        int leftInorderBegin = inorderBegin;
        int leftInorderEnd = delimiterIndex;
        int rightInorderBegin = delimiterIndex + 1;
        int rightInorderEnd = inorderEnd;
        //确认后序遍历的分隔区间
        int leftPostorderBegin = postorderBegin;
        int leftPostorderEnd = postorderBegin + (delimiterIndex - inorderBegin);
        int rightPostorderBegin = leftPostorderEnd;
        int rightPostorderEnd = postorderEnd - 1;
        node -> left = traversal(inorder, leftInorderBegin, leftInorderEnd, postorder, leftPostorderBegin, leftPostorderEnd);
        node -> right = traversal(inorder, rightInorderBegin, rightInorderEnd, postorder, rightPostorderBegin, rightPostorderEnd);
        return node;
    }
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if (inorder.size() == 0 || postorder.size() == 0) return nullptr;
        int size = inorder.size();
        return traversal(inorder, 0, size, postorder, 0, size);
    }
};

题目链接:leetcode 105.从前序与中序遍历序列构造二叉树

思路和解法

题目:
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。
想法:
一样的思路,稍稍改一下就出来了。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    //用索引表示分割出的区间 统一规定采用左闭右开
    //递归函数 返回以下标表示的区间内的中序 后序遍历形成的二叉树根节点
    TreeNode* traversal(vector<int>& preorder, int preorderBegin, int preorderEnd, vector<int>& inorder, int inorderBegin, int inorderEnd) {
        if (preorderBegin == preorderEnd) return nullptr;
        //终止条件 只剩一个值
        if (inorderEnd - 1 == inorderBegin) {
            TreeNode* node = new TreeNode(inorder[inorderBegin]);
            return node;
        }
        //通过前序遍历确认当前构成树的根节点的值
        int val = preorder[preorderBegin];
        TreeNode* node = new TreeNode(val);
        //递归遍历填上左右子树的节点地址
        //确认中序遍历的分隔区间
        int delimiterIndex;
        for (delimiterIndex = inorderBegin; delimiterIndex < inorderEnd; delimiterIndex++) {
            if (inorder[delimiterIndex] == val) break;
        }
        int leftInorderBegin = inorderBegin;
        int leftInorderEnd = delimiterIndex;
        int rightInorderBegin = delimiterIndex + 1;
        int rightInorderEnd = inorderEnd;
        //确认后序遍历的分隔区间
        int leftPreorderBegin = preorderBegin + 1;
        int leftPreorderEnd = leftPreorderBegin + (delimiterIndex - inorderBegin);
        int rightPreorderBegin = leftPreorderEnd;
        int rightPreorderEnd = preorderEnd;
        node -> left = traversal(preorder, leftPreorderBegin, leftPreorderEnd, inorder, leftInorderBegin, leftInorderEnd);
        node -> right = traversal(preorder, rightPreorderBegin, rightPreorderEnd, inorder, rightInorderBegin, rightInorderEnd);
        return node;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if (preorder.size() == 0 || inorder.size() == 0) return nullptr;
        int size = preorder.size();
        return traversal(preorder, 0, size, inorder, 0, size);
    }
};
  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值