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

文章讲述了如何通过前序和中序遍历序列构建二叉树,以及解决路径总和和找到树左下角值的问题,涉及递归和广度优先搜索(BFS)算法的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

  • 首先是搞清楚如何通过前序和中序构造的
  • 有点类似于二分查找+二叉树
  • 我没有在函数参数中传入索引,这样每次递归会构造新的数组,更繁琐一点
class Solution {
 public:
	TreeNode *buildTree(vector<int> &preorder, vector<int> &inorder) {
		if (inorder.size() == 0 || preorder.size() == 0)
			return nullptr;

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

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

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

		if (preorder.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() );

		// preorder 舍弃末尾元素
		preorder.erase(preorder.begin());

		// 切割后序数组
		// 依然左闭右开,注意这里使用了左中序数组大小作为切割点
		// [0, leftInorder.size)
		vector<int> leftPreorder(preorder.begin(), preorder.begin() + leftInorder.size());
		// [leftInorder.size(), end)
		vector<int> rightPretorder(preorder.begin() + leftInorder.size(), preorder.end());

		root->left = traversal(leftInorder, leftPreorder);
		root->right = traversal(rightInorder, rightPretorder);

		return root;
	}
};

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

  • 类似于105
  • 代码随想录的写法,函数入参添加索引,降低复杂度
class Solution {
 private:
	// 中序区间:[inorderBegin, inorderEnd),后序区间[postorderBegin, postorderEnd)
	TreeNode* traversal (vector<int>& inorder, int inorderBegin, int inorderEnd, vector<int>& postorder, int postorderBegin, int postorderEnd) {
		if (postorderBegin == postorderEnd) return NULL;

		int rootValue = postorder[postorderEnd - 1];
		TreeNode* root = new TreeNode(rootValue);

		if (postorderEnd - postorderBegin == 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;

		// 切割后序数组
		// 左后序区间,左闭右开[leftPostorderBegin, leftPostorderEnd)
		int leftPostorderBegin =  postorderBegin;
		int leftPostorderEnd = postorderBegin + delimiterIndex - inorderBegin; // 终止位置是 需要加上 中序区间的大小size
		// 右后序区间,左闭右开[rightPostorderBegin, rightPostorderEnd)
		int rightPostorderBegin = postorderBegin + (delimiterIndex - inorderBegin);
		int rightPostorderEnd = postorderEnd - 1; // 排除最后一个元素,已经作为节点了

		root->left = traversal(inorder, leftInorderBegin, leftInorderEnd,  postorder, leftPostorderBegin, leftPostorderEnd);
		root->right = traversal(inorder, rightInorderBegin, rightInorderEnd, postorder, rightPostorderBegin, rightPostorderEnd);

		return root;
	}
 public:
	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());
	}
};

112.路径总和

  • 类似于寻找所有路径的那道题,
  • 使用一个数记录当前节点的count,与进行回溯
class Solution {
 public:
	bool traversal(TreeNode *node, int sum) {
		if (node->left == nullptr && node->right == nullptr) {
			if (sum == 0)
				return true;
			else
				return false;
		}
		if (node->left) {
			sum -= node->left->val;
			if (traversal(node->left, sum)) return true;
			sum += node->left->val;
		}
		if (node->right) {
			sum -= node->right->val;
			if (traversal(node->right, sum)) return true;
			sum += node->right->val;
		}
		return false;
	}
	bool hasPathSum(TreeNode *root, int targetSum) {
		if (root == nullptr) return false;
		return traversal(root, targetSum - root->val);
	}
};

113路径总和Ⅱ

  • 和112区别就是使用一个数组记录访问过的数字
  • 最后要输出的是访问过的数字
class Solution {
 public:
	void traversal(TreeNode *node, int count, vector<int> paths, vector<vector<int>> &res) {
		if (node->left == nullptr && node->right == nullptr) {
			if (count == 0)
				res.push_back(paths);
			return;
		}
		if (node->left) {
			paths.push_back(node->left->val);
			count -= node->left->val;
			traversal(node->left, count, paths, res);
			paths.pop_back();
			count += node->left->val;
		}
		if (node->right) {
			paths.push_back(node->right->val);
			count -= node->right->val;
			traversal(node->right, count, paths, res);
			paths.pop_back();
			count += node->right->val;
		}
	}
	vector<vector<int>> pathSum(TreeNode *root, int targetSum) {
		vector<int> path;
		vector<vector<int>> res;
		if (root == nullptr)return res;
		path.push_back(root->val);
		traversal(root, targetSum - root->val, path, res);
		return res;
	}
};

513.找树左下角的值

  • 我直接使用BFS
  • 最后一组的第一个数字,就是结果
class Solution {
 public:
	int findBottomLeftValue(TreeNode *root) {
		queue<TreeNode *> que;
		int res;
		que.push(root);
		while (!que.empty()) {
			int size = que.size();
			res = que.front()->val;
			for (int i = 0; i < size; ++i) {
				TreeNode *cur = que.front();
				que.pop();
				if (cur->left) que.push(cur->left);
				if (cur->right) que.push(cur->right);
			}
		}
		return res;
	}
};
  • 递归方法
class Solution2 {
 public:
	int maxDepth = INT_MIN;
	int res;
	void travsersal(TreeNode *root, int depth) {
		if (root->left == nullptr && root->right == nullptr) {
			if (depth > maxDepth) {
				maxDepth = depth;
				res = root->val;
			}
			return;
		}
		if (root->left) {
			depth++;
			travsersal(root->left, depth);
			depth--;
		}
		if (root->right) {
			depth++;
			travsersal(root->right, depth);
			depth--;
		}
		return;
	}
	int findBottomLeftValue(TreeNode *root) {
		travsersal(root, 0);
		return res;
	}
};

day18结束

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值