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

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

513. 找树左下角的值

题目

在这里插入图片描述

解法

  1. 递归:前序遍历
class Solution {
public:
    int maxDepth = INT_MIN;
    int result; 
    void traversal(TreeNode* root, int depth) {
        // 终止条件
        if(root->left == nullptr && root->right == nullptr) {
            if(depth > maxDepth) {
                maxDepth = depth;
                result = root->val;
            }
        }
        //单层递归逻辑
        if(root->left) {
            depth++;
            traversal(root->left, depth);
            depth--;//回溯
        }
        if(root->right) {
            depth++;
            traversal(root->right, depth);
            depth--;//回溯
        }
        return ;
    }
    int findBottomLeftValue(TreeNode* root) {
        traversal(root, 0);
        return result;
    }
};

112. 路径总和

题目

在这里插入图片描述

解法

1.递归:前序遍历

class Solution {
public:
    bool traversal(TreeNode* root, int count) {
        //终止条件
        if(!root->left && !root->right && count == 0) return true;
        if(!root->left && !root->right) return false;
        // 单层递归逻辑
        if(root->left) {
            count -= root->left->val;
            if(traversal(root->left, count)) return true;
            count += root->left->val; //回溯值
        }
        if(root->right) {
            count -= root->right->val;
            if(traversal(root->right, count)) return true;
            count += root->right->val; //回溯值
        }
        return false;
    }
    bool hasPathSum(TreeNode* root, int targetSum) {
        if(root == nullptr) return false;
        return traversal(root, targetSum - root->val);
    }
};

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

题目

在这里插入图片描述

解法

  1. 递归
class Solution {
public:
    TreeNode* traversal(vector<int> inorder, vector<int> postorder) {
        // 序列为空返回NULL
        if(postorder.size() == 0) return nullptr;
        TreeNode* root = new TreeNode(postorder[postorder.size()-1]);
        if(postorder.size() == 1) return root;
        // 找出后序序列最后一个值作为切割点
        int fenGe ;
        for (fenGe = 0; fenGe < inorder.size(); fenGe++) {
            if(inorder[fenGe] == root->val) break;
        }
        // 分割中序序列
        vector<int> leftinorder(inorder.begin(), inorder.begin()+fenGe);
        vector<int> rightinorder(inorder.begin()+fenGe+1, inorder.end());// 需要加1,因为原来分割值是小1的
        // 以分割的中序序列来分割后序序列
        vector<int> leftpostorder(postorder.begin(), postorder.begin()+leftinorder.size());
        vector<int> rightpostorder(postorder.begin()+leftinorder.size(), postorder.end()-1); 
        // 单层递归
        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 nullptr;
        return traversal(inorder, postorder);
    }
};

基础知识补充

vector的建立

在C++中,std::vector是一个动态数组,它可以随时改变大小。以下是几种创建std::vector的常见方法,并带有相应的例子:

1. 默认构造函数
创建一个空的vector:

cpp
#include <iostream>  
#include <vector>  
  
int main() {  
    std::vector<int> vec; // 创建一个空的int类型的vector  
      
    // 输出vector的大小  
    std::cout << "Size of vector: " << vec.size() << std::endl; // 输出: Size of vector: 0  
      
    return 0;  
}
2. 带有初始大小的构造函数
创建一个具有特定大小的vector,所有元素都初始化为该类型的默认值:

cpp
#include <iostream>  
#include <vector>  
  
int main() {  
    std::vector<int> vec(10); // 创建一个大小为10的int类型的vector,所有元素初始化为0  
      
    // 输出vector的大小  
    std::cout << "Size of vector: " << vec.size() << std::endl; // 输出: Size of vector: 10  
      
    return 0;  
}
3. 带有初始大小和初始值的构造函数
创建一个具有特定大小的vector,并用指定的值初始化所有元素:

cpp
#include <iostream>  
#include <vector>  
  
int main() {  
    std::vector<int> vec(10, 5); // 创建一个大小为10的int类型的vector,所有元素初始化为5  
      
    // 输出vector的大小  
    std::cout << "Size of vector: " << vec.size() << std::endl; // 输出: Size of vector: 10  
      
    return 0;  
}
4. 使用列表初始化
使用花括号{}初始化vector:

cpp
#include <iostream>  
#include <vector>  
  
int main() {  
    std::vector<int> vec = {1, 2, 3, 4, 5}; // 使用列表初始化一个int类型的vector  
      
    // 输出vector的大小  
    std::cout << "Size of vector: " << vec.size() << std::endl; // 输出: Size of vector: 5  
      
    return 0;  
}
5. 复制另一个vector
可以使用另一个vector来初始化一个新的vector:

cpp
#include <iostream>  
#include <vector>  
  
int main() {  
    std::vector<int> vec1 = {1, 2, 3, 4, 5};  
    std::vector<int> vec2(vec1); // 使用vec1来初始化vec2  
      
    // 输出vec2的大小  
    std::cout << "Size of vec2: " << vec2.size() << std::endl; // 输出: Size of vec2: 5  
      
    return 0;  
}

6.从别的vector的部分中建立
从另一个std::vector中取部分元素来创建一个新的std::vector,可以使用多种方法。下面是一个例子,演示了如何从一个vector中取出一个子范围来初始化一个新的vector:

cpp
#include <iostream>  
#include <vector>  
  
int main() {  
    // 创建一个原始的vector  
    std::vector<int> original_vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};  
      
    // 定义子范围的起始和结束迭代器  
    auto start_it = original_vec.begin() + 2; // 从第3个元素开始(索引为2)  
    auto end_it = original_vec.begin() + 5;   // 到第6个元素结束(不包括,索引为5)  
      
    // 使用子范围的迭代器来初始化新的vector  
    std::vector<int> new_vec(start_it, end_it);  
      
    // 输出新vector的内容  
    for (int num : new_vec) {  
        std::cout << num << " ";  
    }  
    std::cout << std::endl; // 输出: 3 4 5   
      
    // 输出新vector的大小  
    std::cout << "Size of new_vec: " << new_vec.size() << std::endl; // 输出: Size of new_vec: 3  
      
    return 0;  
}

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

题目

在这里插入图片描述

解法

  1. 递归
class Solution {
public:
    TreeNode* traversal(vector<int>& preorder,  int preBegin, int preEnd, vector<int>& inorder, int inBegin, int inEnd) {
        // 终止条件
        if(preBegin == preEnd) return nullptr;
        
        //前序序列第一个值
        TreeNode*  root = new TreeNode(preorder[preBegin]);
        if (preBegin - preEnd == 1) return root;
        
        //中序序列分割
        int sgementIdx ;
        for(sgementIdx = inBegin; sgementIdx < inEnd; sgementIdx++) {
            if(inorder[sgementIdx] == root->val) break;
        }
        // 中序左侧序列
        int leftInBegin = inBegin; 
        int leftInEnd = sgementIdx;
        // 中序右侧序列
        int rightInBegin = sgementIdx + 1; 
        int rightInEnd = inEnd;

        //前序序列分割
        // 前序左侧序列
        int leftPreBegin = preBegin + 1 ; 
        int leftPreEnd = preBegin + 1 + sgementIdx - inBegin; // preBgein 不是0,需要注意
        // 前序右侧序列
        int rightPreBegin = leftPreEnd; 
        int rightPreEnd = preEnd;

        //单层递归
        root->left = traversal(preorder,leftPreBegin, leftPreEnd, inorder, leftInBegin,leftInEnd);
        root->right = traversal(preorder,rightPreBegin, rightPreEnd, inorder, rightInBegin,rightInEnd);
        return root;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if(preorder.size() == 0 || inorder.size() == 0) return NULL;
        return traversal(preorder, 0, preorder.size(), inorder, 0 , inorder.size());
    }
};

总结

注意不变量

  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值