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

513.找树左下角的值(简单

leetcode题目链接:513. 找树左下角的值 - 力扣(LeetCode)

文章讲解:代码随想录 (programmercarl.com) 

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

题目描述:


解题思路: 

        首先我们要明确题意:不是求最左边的叶子节点,求的是最低层,最左边的叶子节点。关键是最底层。如果一路往左遍历,那求出来的不一定是最底层的叶子节点。

        这就需要我们遍历到一处叶子节点时,记录他的深度。然后取深度最大的,左边叶子节点。

        此时我们在记录深度时就需要用到回溯法了。在找到深度最大时,我们保证向左遍历优先,这样就也是最左边的节点了。

①递归函数的返回值及参数

我们可以返回一个int值作为答案,也可以用类中的一个成员变量来保存答案。此处我们选择返回void。

参数传入TreeNode* root,以及每层的深度depth。

void travesal(TreeNode* root,int depth)

②确定递归终止条件

每当遇到叶子节点时,就需要更新一下深度,看此叶子节点的深度与maxDepth谁更大。如果此叶子节点更大,就更新maxDepth。然后返回。

if(root->left==nullptr&&root->right==nullptr)
{			if (depth > maxDepth)
			{
				maxDepth = depth;
				result = root->val;
			}
    return;
}

③单层递归逻辑

在找最大深度的时候,递归的过程中依然要使用回溯。

if (root->left != nullptr)
		{
			depth++;
			travesal(root->left, depth);
			depth--;	//深度回溯
		}
		if (root->right != nullptr)
		{
			depth++;
			travesal(root->right, depth);
			depth--;
		}
		return;

题目代码:

class Solution {
public:
	int findBottomLeftValue(TreeNode* root) {
		travesal(root, 0);
		return result;
	}
private:
	void travesal(TreeNode* root,int depth)
	{
		if(root->left==nullptr&&root->right==nullptr)
			if (depth > maxDepth)
			{
				maxDepth = depth;
				result = root->val;
			}
		if (root->left != nullptr)
		{
			depth++;
			travesal(root->left, depth);
			depth--;	//深度回溯
		}
		if (root->right != nullptr)
		{
			depth++;
			travesal(root->right, depth);
			depth--;
		}
		return;
	}
private:
	int maxDepth = INT_MIN;
	int result;
};

112. 路径总和 (简单

leetcode题目链接:

112. 路径总和 - 力扣(LeetCode)

文章讲解:代码随想录 (programmercarl.com)

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


题目描述:

解题思路: 

遍历到一个节点,就用targetSum减去当前节点的值,如果到叶子节点时,targetSum=0,那么就有这么一条路径。

①递归函数的返回值及参数

返回值应为bool:当某条路径符合题意时,我们要从叶子节点逐层返回,如果下层返回true,则本次也可以直接返回true。

参数:TreeNode* root,sum用来递减。

bool travesal(TreeNode* root, int sum)

②确定递归终止条件

遇到叶子节点且sum=0时返回true,sum!=0时返回false。

if (root->left == nullptr && root->right == nullptr)
		{
			if (sum == 0)
				return true;
			else
				return false;
		}

③单层递归逻辑

如果该节点的孩子返回了true,则本次递归也可以直接返回true。如果返回false,则将sum回溯。

        if (root->left)
		{
			sum -= root->left->val;
			if (travesal(root->left, sum))
				return true;
			sum += root->left->val;
		}
		if (root->right)
		{
			sum -= root->right->val;
			if (travesal(root->right, sum))
				return true;
			sum += root->right->val;
		}
		return false;

 题目代码:

class Solution {
public:
	bool hasPathSum(TreeNode* root, int targetSum) {
		if (root == nullptr)
			return false;
		return travesal(root, targetSum-root->val);
	}
private:
	bool travesal(TreeNode* root, int sum)
	{
		if (root->left == nullptr && root->right == nullptr)
		{
			if (sum == 0)
				return true;
			else
				return false;
		}
		if (root == nullptr)
			return false;
		if (root->left)
		{
			sum -= root->left->val;
			if (travesal(root->left, sum))
				return true;
			sum += root->left->val;
		}
		if (root->right)
		{
			sum -= root->right->val;
			if (travesal(root->right, sum))
				return true;
			sum += root->right->val;
		}
		return false;
	}
};

113.路径总和Ⅱ(中等

leetcode题目链接:113. 路径总和 II - 力扣(LeetCode)

本题思路和上题一致,但需要注意一点,travesal函数返回值为void,因为我们要遍历所有节点,找所有符合条件的路径。

题目代码

class Solution {
public:
	vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
		if (root == nullptr)
			return result;
		path.push_back(root->val);
		travesal(root,targetSum-root->val);
		return result;
	}
private:
	void travesal(TreeNode* root,int sum)
	{
		if (root->left == nullptr && root->right == nullptr&&sum == 0)
		{
				result.push_back(path);
				return;
		}
		if (root->left == nullptr && root->right == nullptr)
			return;
		if (root == nullptr)
			return;
		if (root->left)
		{
			path.push_back(root->left->val);
			travesal(root->left,sum - root->left->val);
			path.pop_back();
		}
		if (root->right)
		{
			path.push_back(root->right->val);
			travesal(root->right,sum - root->right->val);
			path.pop_back();
		}
		return;
	}
private:
	vector<int> path;
	vector<vector<int>> result;
};

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

leetcode题目链接:106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)

文章讲解:代码随想录 (programmercarl.com)

视频讲解:坑很多!来看看你掉过几次坑 | LeetCode:106.从中序与后序遍历序列构造二叉树_哔哩哔哩_bilibili

题目描述:

 


解题思路 

主要分为以下几个步骤:

1.后序数组为0,空节点。

if (postorder.size() == 0)
			return nullptr;

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

int rootValue = postorder[postorder.size() - 1];
		TreeNode* root = new TreeNode(rootValue);
		//叶子节点
		if (postorder.size() == 1) 
			return root;

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

//找到中序遍历的切割点
		int delimiterIndex;
		for (delimiterIndex = 0; delimiterIndex < inorder.size(); delimiterIndex++)
			if (inorder[delimiterIndex] == rootValue)
				break;

4.切割中序数组,切成中序左数组和中序右数组。

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

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

        postorder.resize(postorder.size() - 1);
//切割后序数组
		//[0,leftInorer.size() )
		vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size());
		//[leftInorder.size(),end)
		vector<int> rightPostorder(postorder.begin() + leftInorder.size(), postorder.end());

6.递归处理左右区间。

root->left = traversal(leftInorder, leftPostorder);
		root->right = traversal(rightInorder, rightPostorder);

题目代码:

class Solution {
public:
	TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
		if (inorder.size() == 0 || postorder.size() == 0)
			return nullptr;
		return traversal(inorder, postorder);
	}
private:
	TreeNode* traversal(vector<int>& inorder, vector<int>& postorder)
	{
		if (postorder.size() == 0)
			return nullptr;
		//后序遍历数组最后一个元素,就是当前的中间节点。
		int rootValue = postorder[postorder.size() - 1];
		TreeNode* root = new TreeNode(rootValue);
		//叶子节点
		if (postorder.size() == 1) 
			return root;

		//找到中序遍历的切割点
		int delimiterIndex;
		for (delimiterIndex = 0; delimiterIndex < inorder.size(); delimiterIndex++)
			if (inorder[delimiterIndex] == rootValue)
				break;

		//切割中序数组
		//[0,delimiterIndex)
		vector<int> leftInorder(inorder.begin(), inorder.begin() + delimiterIndex);
		//[delimiterIndex+1,end)
		vector<int> rightInorder(inorder.begin() + delimiterIndex + 1, inorder.end());
		
		postorder.resize(postorder.size() - 1);

		//切割后序数组
		//[0,leftInorer.size() )
		vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size());
		//[leftInorder.size(),end)
		vector<int> rightPostorder(postorder.begin() + leftInorder.size(), postorder.end());
		root->left = traversal(leftInorder, leftPostorder);
		root->right = traversal(rightInorder, rightPostorder);

		return root;
	}
};

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

class Solution {
private:
        TreeNode* traversal (vector<int>& inorder, int inorderBegin, int inorderEnd, vector<int>& preorder, int preorderBegin, int preorderEnd) {
        if (preorderBegin == preorderEnd) return NULL;

        int rootValue = preorder[preorderBegin]; // 注意用preorderBegin 不要用0
        TreeNode* root = new TreeNode(rootValue);

        if (preorderEnd - preorderBegin == 1) return root;

        int delimiterIndex;
        for (delimiterIndex = inorderBegin; delimiterIndex < inorderEnd; delimiterIndex++) {
            if (inorder[delimiterIndex] == rootValue) break;
        }
        // 切割中序数组
        // 中序左区间,左闭右开[leftInorderBegin, leftInorderEnd)
        int leftInorderBegin = inorderBegin;
        int leftInorderEnd = delimiterIndex;
        // 中序右区间,左闭右开[rightInorderBegin, rightInorderEnd)
        int rightInorderBegin = delimiterIndex + 1;
        int rightInorderEnd = inorderEnd;

        // 切割前序数组
        // 前序左区间,左闭右开[leftPreorderBegin, leftPreorderEnd)
        int leftPreorderBegin =  preorderBegin + 1;
        int leftPreorderEnd = preorderBegin + 1 + delimiterIndex - inorderBegin; // 终止位置是起始位置加上中序左区间的大小size
        // 前序右区间, 左闭右开[rightPreorderBegin, rightPreorderEnd)
        int rightPreorderBegin = preorderBegin + 1 + (delimiterIndex - inorderBegin);
        int rightPreorderEnd = preorderEnd;

        root->left = traversal(inorder, leftInorderBegin, leftInorderEnd,  preorder, leftPreorderBegin, leftPreorderEnd);
        root->right = traversal(inorder, rightInorderBegin, rightInorderEnd, preorder, rightPreorderBegin, rightPreorderEnd);

        return root;
    }

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

        // 参数坚持左闭右开的原则
        return traversal(inorder, 0, inorder.size(), preorder, 0, preorder.size());
    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值