【算法训练 day21 找树左下角的值、路径总和、从中序与后序遍历序列构造二叉树】


一、找树左下角的值-LeetCode 513

Leecode链接: leetcode 513
文章链接: 代码随想录

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

假设二叉树中至少有一个节点。

示例:

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

思路

递归:题目需要找最左下角的值,那么这个值肯定时叶子节点的值,其次他还得是最左边的,叶子节点利用变量depth递归来计数,每递归一次加1,回退就减1,当遍历到叶子节点时就保存这个值。但要求是最左边的,可以利用depth来判断,当depth首次最大时且该节点是叶子节点时,他一定是最左边的。迭代:每次遍历时,保存队列第一个出队得元素,直到循环推出,最后保存的数一定是最左边的。

实现代码

1.递归

//cpp
class Solution{
public:
	int maxdepth = INT32_MIN;
	int res;
	void dfs(TreeNode* root,int depth){
		if(root->left == nullptr && root->right == nullptr){
			if(depth > maxdepth){
				depth = maxdepth;
				res = root->val;
			}
			return;
		}
		if(root->left){
			depth++;
			dfs(root->left,depth);
			depth--;
		}
		if(root->right){
			depth++;
			dfs(root->right,depth);
			depht--;
		}
		return;
	}
	int findBottomLeftValue(TreeNode* root) {
        dfs(root,1);//这里写1或者0都可以,因为具体多少不重要,只要是最大值就行,写1符合逻辑
        return res;
    }

2.迭代

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

个人问题

递归法没有写出来,深度递归写的不熟练。

总结

整体运用了二叉树深度的求法,以及回溯的思想。


二、路径总和-LeetCode 112

Leecode链接: LeetCode 112
文章链接: 代码随想录

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

叶子节点 是指没有子节点的节点。

示例:

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

思路

思路很简单,使用后续遍历+回溯,因为需要不断来回判断状态,当找到符合结果的就返回true,否则返回false。

实现代码

//cpp
class Solution {
public:
    bool get(TreeNode* root,int sum,int target){
        //sum = sum + root->val;
        if(root->left == nullptr && root->right == nullptr){
            if(sum == target){
                return true;
            }
            else{
                return false;
            }
        }

        if(root->left){
            sum += root->left->val;
            bool a = get(root->left,sum,target);
            if(a) return true;
            sum -= root->left->val;
        }
        if(root->right){
            sum += root->right->val;
            bool b = get(root->right,sum,target);
            if(b) return true;
            sum -= root->right->val;
        }

        return false;
    }

    bool hasPathSum(TreeNode* root, int targetSum) {
        if(root == nullptr) return false;

        bool res = get(root,root->val,targetSum);
        return res;
    }
};

leetcode113题

//cpp
class Solution {
public:
    vector<vector<int>> res;
    void get(TreeNode* root,int target,vector<int>& path){
        if(root->left == nullptr && root->right == nullptr && target == 0){
            res.push_back(path);
            return;
        }

        if(root->left){
            target -= root->left->val;
            path.push_back(root->left->val);
            get(root->left,target,path);
            path.pop_back();
            target += root->left->val;
        }

        if(root->right){
            target -= root->right->val;
            path.push_back(root->right->val);
            get(root->right,target,path);
            path.pop_back();
            target += root->right->val;
        }
        return;
    }

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

个人问题

个人使用依次递增来判断是否符合条件,其实可以递减,减到0时必定符合条件,这样可以避免多传递一个参数。

总结

还是回溯加递归,不过函数返回值为bool类型,当不要返回具体路径时,函数返回值一般为bool类型,因为主要判断是否存在这么一条路径,给出是或者否即可。类似于113题需要你给出具体路径时,就不要返回bool,而是返回void,符合条件的路径保存在一个全局变量res中即可。


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

Leecode链接: LeetCode 106
文章链接: 代码随想录

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

示例:

输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]

思路

思路很简单,难的是代码复现。题目切入点为后续遍历数组的末尾元素,该元素一定是中间节点,这是遍历顺序决定的。然后根据该节点在中序遍历中寻找下标,接着以这个下标为分界点,切割中序遍历数组与后序遍历数组,将其分成左右子树数组,最后递归处理即可。

实现代码

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

        int postnum = postorder[postorder.size()-1];
        TreeNode* root = new TreeNode(postnum);
        if(postorder.size() == 1) return root;

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

        vector<int>leftorder(inorder.begin(),inorder.begin() + i);
        vector<int>rightorder(inorder.begin() + i + 1,inorder.end());

        postorder.pop_back();

        vector<int>leftpost(postorder.begin(),postorder.begin() + leftorder.size());
        vector<int>rightpost(postorder.begin() + leftorder.size(),postorder.end());

        root->left = build(leftorder,leftpost);
        root->right = build(rightorder,rightpost);

        return root;
    }

    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if(postorder.size() == 0) return nullptr;

        return build(inorder,postorder);
    }
};

leetcode105

///cpp
class Solution {
public:
    TreeNode* build(vector<int>& preorder,int preorderbegin,int preorderend,vector<int>& inorder,int inorderbegin,int inorderend){
        if(preorderbegin == preorderend) return nullptr;

        int num = preorder[preorderbegin];
        TreeNode* root = new TreeNode(num);
        if(preorderbegin - preorderend == 1){
            return root;
        }

        int i;
        for(i = inorderbegin;i<inorderend;i++){
            if(inorder[i] == num){
                break;
            }
        }

        int leftinorderbegin = inorderbegin;
        int leftinorderend = i;
        int rightinorderbegin = i + 1;
        int rightinorderend = inorderend;

        int leftpreorderbegin = preorderbegin + 1;
        int leftpreorderend = preorderbegin + 1 + i - inorderbegin;
        int rightpreorderbegin = preorderbegin + 1 + i - inorderbegin;
        int rightpreorderend = preorderend;

        root->left = build(preorder,leftpreorderbegin,leftpreorderend,inorder,leftinorderbegin,leftinorderend);
        root->right = build(preorder,rightpreorderbegin,rightpreorderend,inorder,rightinorderbegin,rightinorderend);

        return root;
    }

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

        return build(preorder,0,preorder.size(),inorder,0,inorder.size());
    }
};

个人问题

代码没有自己写出来。

总结

题目也可以不用每递归一次创建四个数组,在函数参数处添加数组首尾下标即可。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值