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

LeetCode513

2025-02-12 16:44:54 星期三

题目描述:力扣513
文档讲解:代码随想录(programmercarl)513.找树左下角的值
视频讲解:《代码随想录》算法视频公开课 (opens new window):怎么找二叉树的左下角? 递归中又带回溯了,怎么办?| LeetCode:513.找二叉树左下角的值

代码随想录视频内容简记

这道题旗帜鲜明的一点是他没有中结点的处理过程

梳理

  1. 我们需要额外定义一个遍历的函数,一个参数使用根节点,另一个参数存放结点的深度。除此以外,还需要一个result来存放最后的最左下角的值

  2. 确定递归的终止条件,首先要确定是最下面一行的结点,那么就必须是叶子结点

  3. 确定单层递归的逻辑

大致代码内容

  1. void traversal(TreeNode* root, int depth),一旦发现

  2. 在终止条件中,首先判断是不是叶子结点,之后如果有深度大于当前最大深度,那么就更新深度,if (depth > maxDepth) maxDepth = depth

  3. 在单层递归中,分别对左和右进行遍历,在遍历中进行depth++操作,之后进入递归traversal(),一条路径递归结束之后,开始回溯,这是最核心的一点,要进行depth--操作

LeetCode测试

代码不算特别难写,但要注意把int result和int depth定义在函数的外部,避免定义在内部每次都要更新进行初始化

点击查看代码
class Solution {
public:
    int result;
    int maxDepth = INT_MIN;
    
    void traversal(TreeNode* root, int depth) {
        if (root->left == NULL && root->right == NULL) {
            if (depth > maxDepth) {
                maxDepth = depth;
                result = root->val;
                return;}
        }
        if (root->left) {
            depth++;
            traversal(root->left, depth);
            depth--;
        }
        if (root->right) {
            depth++;
            traversal(root->right, depth);
            depth--;
        }
    }

    int findBottomLeftValue(TreeNode* root) {
        int depth = 0;
        traversal(root, depth);
        return result;
    }
};

LeetCode112

题目描述:力扣112
文档讲解:代码随想录(programmercarl)112.路径总和
视频讲解:《代码随想录》算法视频公开课:拿不准的遍历顺序,搞不清的回溯过程,我太难了! | LeetCode:112. 路径总和

代码随想录视频内容简记

这道题目还是不处理中结点,即采用前中后序三种皆可。另外就是这道题k哥给出的是直接传入目标值,然后在遍历中做--操作

梳理

  1. 定义一个新的bool类型的traversal()函数,确定函数的参数有根节点rootcount计数器

  2. 确定递归的终止条件,就是在是叶子结点的前提下,如果计数器的值为0,那么返回True,否则是False

  3. 确定单层递归的逻辑,对左和右遍历即可

大致代码内容

  1. if (root->left == NULL && root->right == NULL && count == 0) return true这是第一个终止条件,之后还要确定第二个终止条件if (root->left == NULL && root->right == NULL && count != 0) return false

  2. 向左遍历,如果子树的遍历结果是true,那么就要层层向上返回,这样来确定该条路径if (traversal(root->left, count)) return true

  3. 向右遍历同理

LeetCode测试

这道题注意一点就是在主函数中,调用traversal()函数的,其count参数应该是target - root->val,应该把先前的root的减去。这个是卡在第61个用例上,比如[1]和1,该二叉树只有一个根节点,且要求和值为1,那么只有-1了才会符合count == 0的要求

点击查看代码
class Solution {
public:
    bool traversal(TreeNode* node, int count) {
        if (node->left == NULL && node->right == NULL && count == 0) return true;
        if (node->left == NULL && node->right == NULL && count != 0) return false;
        if (node->left) {
            count -= node->left->val;
            if (traversal(node->left, count)) return true;
            count += node->left->val;
        }
        if (node->right) {
            count -= node->right->val;
            if (traversal(node->right, count)) return true;
            count += node->right->val;
        }
        return false;
    }

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

LeetCode106

题目描述:力扣106
文档讲解:代码随想录(programmercarl)106.从中序与后序遍历序列构造二叉树
视频讲解:《代码随想录》算法视频公开课:坑很多!来看看你掉过几次坑 | LeetCode:106.从中序与后序遍历序列构造二叉树

代码随想录视频内容简记

梳理

  1. 如果数组大小为零的话,说明是空节点了。

  2. 如果不为空,那么取后序数组最后一个元素作为节点元素。

  3. 找到后序数组最后一个元素在中序数组的位置,作为切割点

  4. 切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)

  5. 切割后序数组,切成后序左数组和后序右数组

  6. 递归处理左区间和右区间

大致代码内容

  1. 首先是大致的代码框架

	if (postorder.size == 0) return NULL;
    int rootValue = postorder[postorder.size() - 1];
    TreeNode* root = new TreeNode(rootValue);
    
    // 叶子结点
    if (postorder.size() == 1) return root;
    
    // 找切割点
    int index;
    for (index = 0; index < inorder.size() - 1; index++) {
        if (inorder[index] == rootValue) break;
    }
	// 切割中序数组
	// 切割后序数组
	
	root->left = buildTree(leftInorder,);
    root->right = buildTree(中序右数组,后序右数组);
    
    return root;
  1. 切割中序数组

// [0, index)
vector<int> leftInorder(inorder.begin(), inorder.begin() + index);
// [index + 1, end)
vector<int> rightInorder(inorder.begin() + index + 1, inorder.end());
  1. 切割后序数组

// 切割后序数组
postorder.resize(postorder.size() - 1);
vector<int> leftPastorder(postorder.begin(), postorder.begin() + leftInorder.size());
vector<int> rightPostorder(pastorder.begin() + leftInorder.size(), postorder.end());
  1. 递归处理左区间和右区间

root->left = traversal(中序左数组, 后序右数组);
root->right = traversal(中序右数组, 后序右数组);

return root;

LeetCode测试

这个代码有一个地方一直有问题找不出来错,找了大半天,最后找到了

int index;
for (int index = 0; index < inorder.size(); index++) {
	if (inorder[index] == rootValue) break;
}

刚开始这里写的是int index, 但是这样就会有一个问题,局部的index,没有办法传给下面的区间做切割,相当于下面其实一直用的是index = 0

😵😵

左闭右闭

点击查看代码
class Solution {
private:
    TreeNode* traversal(vector<int>& inorder, vector<int>& postorder) {
        if (postorder.size() == 0) return NULL;
        
        int rootValue = postorder[postorder.size() - 1];
        TreeNode* root = new TreeNode(rootValue);

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

        int index;
        for (index = 0; index < inorder.size(); index++) {
            if (inorder[index] == rootValue) break;
        }

        // 分割中序数组
        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;
    }

public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if (inorder.size() == 0 || postorder.size() == 0) return NULL;
        return traversal(inorder, postorder);
    }
};
posted on   bnbncch  阅读(1247)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示