第六章 二叉树part04
2026.03.13 02.12 第十六天
513 找树左下角的值
左下角的值是最深一层,从左到右第一个叶子节点的值。
递归法:
遍历到每个节点都判断当前深度,每一次出现更深的节点就可能是左下角的节点,最后一次出现的更深的节点就是要找的节点。
class Solution {
public:
int maxDepth = INT_MIN;
int result;
void travelsal(TreeNode* node, int depth) {
if(node->left == nullptr && node->right == nullptr) {
if(depth > maxDepth) {
maxDepth = depth;
result = node->val;
}
}
if(node->left) {
depth++;
travelsal(node->left, depth);
depth--;
}
if(node->right) {
depth++;
travelsal(node->right, depth);
depth--;
}
return;
}
int findBottomLeftValue(TreeNode* root) {
travelsal(root, 0);
return result;
}
};
迭代法实现:
迭代法更加直观,利用层序遍历,每到新到一层,就记录更新第一个节点的val即可。
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
queue<TreeNode*> que;
int result;
if(root != nullptr) que.push(root);
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;
}
};
112 路径总和
递归也有多种实现方式,但是不同的处理方式效率不同,本题代码随想录提供的递归方案比较优雅节省资源
通过返回bool类型数据,一旦找到满足要求的路径就可快速一路返回true,从而节省时间和内存。
至于是count减到0还是从0加到target都一样。
递归法:
class Solution {
public:
bool travelsal(TreeNode* cur, int count) {
if(cur->left == nullptr && cur->right == nullptr && count == 0) return true;
if(cur->left == nullptr && cur->right == nullptr) return false;
if(cur->left) {
if(travelsal(cur->left, count - cur->left->val)) return true;
}
if(cur->right) {
if(travelsal(cur->right, count - cur->right->val)) return true;
}
return false;
}
bool hasPathSum(TreeNode* root, int targetSum) {
if(root == nullptr) return false;
return travelsal(root, targetSum - root->val);
}
};
迭代法使用栈模拟递归,此时栈里一个元素不仅要记录该节点指针,还要记录从头结点到该节点的路径数值总和。从而判断当前路径是否满足条件。
113 路径之和||
在112基础上进行简单修改即可,下面的代码中将path和result声明为类中的变量更节省空间,避免每次递归都创建新的局部变量。
class Solution {
public:
void travelsal(TreeNode* cur, int count, vector<int> path, vector<vector<int>>& result) {
if(cur->left == nullptr && cur->right == nullptr && count == 0) {
result.push_back(path);
return;
}
if(cur->left == nullptr && cur->right == nullptr) return;
if(cur->left) {
path.push_back(cur->left->val);
travelsal(cur->left, count - cur->left->val, path, result);
path.pop_back();
}
if(cur->right) {
path.push_back(cur->right->val);
travelsal(cur->right, count - cur->right->val, path, result);
path.pop_back();
}
return;
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
if(root == nullptr) return {};
vector<vector<int>> result;
vector<int> path;
path.push_back(root->val);
travelsal(root, targetSum - root->val, path, result);
return result;
}
};
106 从中序与后序遍历序列构造二叉树
首先要了解基本原理:
就是以 后序数组的最后一个元素为切割点,先切中序数组,根据中序数组,反过来再切后序数组。一层一层切下去,每次后序数组最后一个元素就是节点元素。
那么代码应该怎么写呢?
说到一层一层切割,就应该想到了递归。
来看一下一共分几步:
第一步:如果数组大小为零的话,说明是空节点了。
第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
第五步:切割后序数组,切成后序左数组和后序右数组
第六步:递归处理左区间和右区间
其次既然有分割,就要保持好边界值的一致性,下面保持左闭右开的原则。
使用递归进行构造。
class Solution {
private:
TreeNode* travelsal(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;
}
}
vector<int> leftInorder(inorder.begin(), inorder.begin() + delimiterIndex);
vector<int> rightInorder(inorder.begin() + delimiterIndex + 1, inorder.end());
postorder.resize(postorder.size() - 1);
vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size());
vector<int> rightPostorder(postorder.begin() + leftInorder.size(), postorder.end());
root->left = travelsal(leftInorder, leftPostorder);
root->right = travelsal(rightInorder, rightPostorder);
return root;
}
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if(inorder.size() == 0 || postorder.size() == 0) return nullptr;
return travelsal(inorder, postorder);
}
};
上面的代码每次都创建了新的数组,既耗费时间又耗费空间,如果使用数组索引而不是直接创建数组的话,可以节省很多时间空间。
使用数组索引有一个隐藏的大坑,就是数组的索引已经是绝对坐标了,不用end-begin寻找相对位置!!!
105 从前序与中序遍历序列构造二叉树
与上一题完全一致
class Solution {
private:
TreeNode* travelsal(vector<int>& preorder, int prebegin, int preend, vector<int>& inorder, int inbegin, int inend) {
if(prebegin == preend) return nullptr;
int rootValue = preorder[prebegin];
TreeNode* root = new TreeNode(rootValue);
if(preend - prebegin == 1) return root;
int delimiterIndex;
for(delimiterIndex = inbegin; delimiterIndex < inend; delimiterIndex++) {
if(inorder[delimiterIndex] == rootValue) break;
}
int leftInorderBegin = inbegin;
int leftInorderEnd = delimiterIndex;
int rightInorderBegin = delimiterIndex + 1;
int rightInorderEnd = inend;
int leftPreorderBegin = 1 + prebegin;
int leftPreorderEnd = 1 + prebegin + (leftInorderEnd - leftInorderBegin);
int rightPreorderBegin = 1 + prebegin + (leftInorderEnd - leftInorderBegin);
int rightPreorderEnd = preend;
root->left = travelsal(preorder, leftPreorderBegin, leftPreorderEnd, inorder, leftInorderBegin, leftInorderEnd);
root->right = travelsal(preorder, rightPreorderBegin, rightPreorderEnd, inorder, rightInorderBegin, rightInorderEnd);
return root;
}
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if(inorder.size() == 0 || preorder.size() == 0) return nullptr;
return travelsal(preorder, 0, preorder.size(), inorder, 0, inorder.size());
}
};

浙公网安备 33010602011771号