Day 18 513.找树左下角的值 112. 路径总和 113.路径总和ii 106.从中序与后序遍历序列构造二叉树 105.从前序与中序遍历序列构造二叉树

找树左下角的值

给定一个二叉树,在树的最后一行找到最左边的值。

示例 1:

513.找树左下角的值

示例 2:

513.找树左下角的值1

​ 如果用层序遍历就很简单,直接查询最后一个数组的第一位值即可;

​ 由于题目要求得到的是最后一行的最左边的元素,则不能简单的一直向左遍历;两个要求,首先是最后一排,然后再是最左边;

​ 递归判断最后一行最简单的方法就是用最大深度得到最后一行;而且由于这道题的要求是返回左下角的值,所以只需要满足左子树优先遍历即可,那么前序中序后序都可以,保证优先左边搜索,然后记录深度最大的叶子节点,此时就是树的最后一行最左边的值;

	//确认函数参数和返回值:参数必须有要遍历的树的根节点,还有就是一个int型的变量用来记录最长深度
	int maxDepth = INT_MIN;   // 全局变量 记录最大深度
	int result;       // 全局变量 最大深度最左节点的数值
	void traversal(TreeNode* root, int depth){//为什么从此处不用int型而是用void型?
    //确定函数终止条件
        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){//右
            traversal(root->right , depth + 1);//隐藏回溯
        }
    }

​ 整体代码如下:

/**
 * 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型的变量用来记录最长深度
	int maxDepth = INT_MIN;   // 全局变量 记录最大深度
	int result;       // 全局变量 最大深度最左节点的数值
	void traversal(TreeNode* root, int depth){//为什么从此处不用int型而是用void型?
    //确定函数终止条件
        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){//右
            traversal(root->right , depth + 1);//隐藏回溯
        }
    }
    int findBottomLeftValue(TreeNode* root) {
        traversal(root,0);
        return result;
    }
};

路径总和

路径总和

给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。

说明: 叶子节点是指没有子节点的节点。

示例: 给定如下二叉树,以及目标和 sum = 22,

img

返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。

​ 这里讨论一个没有完全懂的点,即递归函数的返回值究竟应该是什么?

​ 如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值;(这种情况就是本文下半部分介绍的113.路径总和ii)

​ 如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值; (这种情况我们在236. 二叉树的最近公共祖先 (opens new window)中介绍)

​ 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回;(本题的情况)

​ 本题逻辑如图所示:

​ 和上道题一样,无须考虑中的处理逻辑,前中后序都行;

	//确定参数类型和返回值
	bool traversal(TreeNode* root, int count){
        if(root->left == NULL && root->right == NULL){
            if(count == 0)	return true;//确定终止条件
            else return false;
        }
        if(root->left){//左
            count -= root->left->val;
            if(traversal(root->left , count))	return true;//注意此时返回值是bool,所以if判断依层返回
            count += root->left->val;//回溯	因为要保证对其他路径的count值正常
        }	
        if(root->right){
            count -= root->right->val;
            if(traversal(root->right, count))	return true;
            count += root->right->val;
        }
        return 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 traversal(TreeNode* root, int count){
        if(root->left == NULL && root->right == NULL){
            if(count == 0)	return true;//确定终止条件
            else return false;
        }
        if(root->left){//左
            count -= root->left->val;
            if(traversal(root->left , count))	return true;//注意此时返回值是bool,所以if判断依层返回
            count += root->left->val;//回溯	因为要保证对其他路径的count值正常
        }	
        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)   return false;
        return traversal(root , targetSum - root->val);
    }
};

路径总和Ⅱ

给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。

说明: 叶子节点是指没有子节点的节点。

示例: 给定如下二叉树,以及目标和 sum = 22,

113.路径总和ii1.png

​ 很简单,层序遍历,返回含有路径数组元素的数组;

​ 由于题目要求遍历所有路径,所以此处迭代函数是没有返回值的;

​ 本体逻辑如图所示:

​ 则整体代码如下:

/**
 * 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 {
private:
    vector<vector<int>> result;
    vector<int> path;
    // 递归函数不需要返回值,因为我们要遍历整个树
    void traversal(TreeNode* cur, int count) {
        if (!cur->left && !cur->right && count == 0) { // 遇到了叶子节点且找到了和为sum的路径
            result.push_back(path);
            return;
        }

        if (!cur->left && !cur->right) return ; // 遇到叶子节点而没有找到合适的边,直接返回

        if (cur->left) { // 左 (空节点不遍历)
            path.push_back(cur->left->val);
            count -= cur->left->val;
            traversal(cur->left, count);    // 递归
            count += cur->left->val;        // 回溯
            path.pop_back();                // 回溯
        }
        if (cur->right) { // 右 (空节点不遍历)
            path.push_back(cur->right->val);
            traversal(cur->right, count - cur->right->val);
            path.pop_back();                // 回溯
        }
        return ;
    }

public:
    vector<vector<int>> pathSum(TreeNode* root, int sum) {
        result.clear();
        path.clear();
        if (root == NULL) return result;
        path.push_back(root->val); // 把根节点放进路径
        traversal(root, sum - root->val);
        return result;
    }
};

从中序和后序遍历序列构造二叉树

根据一棵树的中序遍历与后序遍历构造二叉树。

注意: 你可以假设树中没有重复的元素。

例如,给出

  • 中序遍历 inorder = [9,3,15,20,7]
  • 后序遍历 postorder = [9,15,7,20,3] 返回如下的二叉树:

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

​ 纸上写出来很简单,代码实现很繁琐:

​ 后序数组最后一个元素得到根节点(此处判空处理);

​ 在中序数组中寻找后序数组末尾值分割区间,切割中序数组;

​ 根据中序的左右区间切割后序的左右区间;

​ 递归;

	TreeNode* traversal(vector<int>& inorder , vector<int>& postorder){//函数参数和返回值
        //终止条件
        if(postorder.size() == 0)	return NULL:
        TreeNode* root = new TreeNode(postorder[postorder.size() - 1]);
        if(postorder.size() == 1)	return root;
        //单层递归
        int index;
        for(index = 0; index < inorder.size(); index++){
            if(inorder[index] == root->val)	break;
        }
        //切割数组
        //以inorder[index]为分界点切成左右中序
        //再以左中序数组得到左后序数组,切割出左右后序数组
        //root->left = traversal(左中序,左后序);
        //root->right = traversal(左后序,右后序);
        //循环不变量:统一左闭右开区间
        vector<int> LeftInorder(inorder.begin() , inorder.begin() + index);
        vector<int>	RightInorder(inorder.begin() + index + 1 , index.end());
        postorder.resize(postorder.size() - 1);
        vector<int> LeftPostorder(postorder.begin() , postorder.begin() + LeftInorder.size());
        vector<int> RightPostorder(postorder.begin() + LeftInorder.size() + 1 , postorder.end());
        
        // 以下为日志
        cout << "----------" << endl;

        cout << "leftInorder :";
        for (int i : leftInorder) {
            cout << i << " ";
        }
        cout << endl;

        cout << "rightInorder :";
        for (int i : rightInorder) {
            cout << i << " ";
        }
        cout << endl;

        cout << "leftPostorder :";
        for (int i : leftPostorder) {
            cout << i << " ";
        }
        cout << endl;
         cout << "rightPostorder :";
        for (int i : rightPostorder) {
            cout << i << " ";
        }
        cout << endl;
        
        root->left = traversal(LeftInorder , LeftPostorder);
        root->right = traversal(RightInoder , RightPostorder);
        return root;
    }

​ 化简vector数组过程,整体代码如下:(提交代码的时候不要打日志,只是要学会使用日志来帮助自己调试)

/**
 * 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 inorder_begin , int inorder_end, vector<int>& postorder , int postorder_begin , int postorder_end){//函数参数和返回值
        //终止条件
        if(postorder_begin == postorder_end)	return NULL;
        TreeNode* root = new TreeNode(postorder[postorder_end - 1]);
        if(postorder_end - 1 == postorder_begin)	return root;
        //单层递归
        int index;
        for(index = inorder_begin; index < inorder_end; index++){
            if(inorder[index] == root->val)	break;
        }
        //切割数组
        //以inorder[index]为分界点切成左右中序
        //再以左中序数组得到左后序数组,切割出左右后序数组
        //root->left = traversal(左中序,左后序);
        //root->right = traversal(左后序,右后序);
        //循环不变量:统一左闭右开区间
        // vector<int> LeftInorder(inorder.begin() , inorder.begin() + index);
        // vector<int>	RightInorder(inorder.begin() + index + 1 , index.end());
        // postorder.resize(postorder.size() - 1);
        // vector<int> LeftPostorder(postorder.begin(), postorder.begin() + LeftInorder.size());
        // vector<int> RightPostorder(postorder.begin() + LeftInorder.size() + 1, postorder.end());
        int left_inorder_begin = inorder_begin;
        int left_inorder_end = index;
        int right_inorder_begin = index + 1;
        int right_inorder_end = inorder_end;

        int left_postorder_begin = postorder_begin;
        int left_postorder_end = postorder_begin + left_inorder_end - left_inorder_begin;
        int right_postorder_begin = postorder_begin + left_inorder_end - left_inorder_begin;
        int right_postorder_end = postorder_end - 1;
       	
        //同理,日志如下
        cout << "----------" << endl;
        cout << "leftInorder :";
        for (int i = leftInorderBegin; i < leftInorderEnd; i++) {
            cout << inorder[i] << " ";
        }
        cout << endl;

        cout << "rightInorder :";
        for (int i = rightInorderBegin; i < rightInorderEnd; i++) {
            cout << inorder[i] << " ";
        }
        cout << endl;

        cout << "leftpostorder :";
        for (int i = leftPostorderBegin; i < leftPostorderEnd; i++) {
            cout << postorder[i] << " ";
        }
        cout << endl;

        cout << "rightpostorder :";
        for (int i = rightPostorderBegin; i < rightPostorderEnd; i++) {
            cout << postorder[i] << " ";
        }
        cout << endl;
        
        root->left = traversal(inorder, left_inorder_begin, left_inorder_end, postorder, left_postorder_begin, left_postorder_end );
        root->right = traversal(inorder, right_inorder_begin, right_inorder_end, postorder, right_postorder_begin, right_postorder_end);
        return root;
    }
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if(inorder.size() == 0 || postorder.size() == 0)  return NULL;
        //左闭右开
        return traversal(inorder, 0, inorder.size(), postorder, 0, postorder.size());
    }
};
  • 19
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
树的存储与遍历: 1.初始化二叉树 ```c++ #include <iostream> using namespace std; struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int x) : val(x), left(NULL), right(NULL) {} }; TreeNode* createTree() { int val; cin >> val; if (val == -1) { return NULL; } TreeNode* root = new TreeNode(val); root->left = createTree(); root->right = createTree(); return root; } ``` 2.先遍历二叉树 ```c++ void preOrder(TreeNode* root) { if (root == NULL) { return; } cout << root->val << " "; preOrder(root->left); preOrder(root->right); } ``` 3.中序遍历二叉树 ```c++ void inOrder(TreeNode* root) { if (root == NULL) { return; } inOrder(root->left); cout << root->val << " "; inOrder(root->right); } ``` 4.后序遍历二叉树 ```c++ void postOrder(TreeNode* root) { if (root == NULL) { return; } postOrder(root->left); postOrder(root->right); cout << root->val << " "; } ``` 5.销毁二叉树 ```c++ void destroyTree(TreeNode* root) { if (root == NULL) { return; } destroyTree(root->left); destroyTree(root->right); delete root; } ``` 二叉树的复原: 1.由前中序序列确定复原二叉树 ```c++ TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) { if (preorder.empty() || inorder.empty()) { return NULL; } int rootVal = preorder[0]; TreeNode* root = new TreeNode(rootVal); vector<int>::iterator it = find(inorder.begin(), inorder.end(), rootVal); int leftSize = it - inorder.begin(); vector<int> leftPreorder(preorder.begin() + 1, preorder.begin() + 1 + leftSize); vector<int> leftInorder(inorder.begin(), it); vector<int> rightPreorder(preorder.begin() + 1 + leftSize, preorder.end()); vector<int> rightInorder(it + 1, inorder.end()); root->left = buildTree(leftPreorder, leftInorder); root->right = buildTree(rightPreorder, rightInorder); return root; } ``` 2.由中序、后序列确定复原二叉树 ```c++ TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) { if (inorder.empty() || postorder.empty()) { return NULL; } int rootVal = postorder.back(); TreeNode* root = new TreeNode(rootVal); vector<int>::iterator it = find(inorder.begin(), inorder.end(), rootVal); int leftSize = it - inorder.begin(); vector<int> leftInorder(inorder.begin(), it); vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftSize); vector<int> rightInorder(it + 1, inorder.end()); vector<int> rightPostorder(postorder.begin() + leftSize, postorder.end() - 1); root->left = buildTree(leftInorder, leftPostorder); root->right = buildTree(rightInorder, rightPostorder); return root; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值