一、找树左下角的值
题目描述:
给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。
思路
-一定要理解题目,找最后一行的最左侧结点,它不一定是左孩子
-找树左下角的值就是找深度最大的叶子结点的值
-没有中间结点的处理逻辑,优先左遍历,所以前序、中序、后序都可以
代码实现
// 递归法
class Solution {
public:
int maxDepth = INT_MIN;
int result;
void traversal(TreeNode* root, int depth) {
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) {
depth++;
traversal(root->right, depth);
depth--; // 回溯
}
return;
}
int findBottomLeftValue(TreeNode* root) {
traversal(root, 0);
return result;
}
};
// 迭代法
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;
}
};
二、路径总和
思路
没有中的处理逻辑,所以前序、中序、后序都可以
确定递归的返回值和参数 :需要找某一条符合题目要求的路径,所以需要返回值;直接传入目标值,遇到一个结点数值就做减法,如果减完叶子结点的值之后count为0,说明找到了一条符合题目要求的路径
有递归就一定有回溯!
代码实现
class Solution {
private:
bool traversal(TreeNode* cur, int count) {
if(cur->left == NULL && cur->right == NULL && count == 0) return true;
if(cur->left == NULL && cur->right == NULL) return false;
if(cur->left) {
count -= cur->left->val; // 递归,处理结点
if(traversal(cur->left,count)) return true;
count += cur->left->val; // 回溯,撤销处理结果
}
if(cur->right) {
count -= cur->right->val;
if(traversal(cur->right,count)) return true;
count += cur->right->val;
}
return false;
}
public:
bool hasPathSum(TreeNode* root, int targetSum) {
if(root == NULL) return false;
return traversal(root,targetSum - root->val);
}
};
三、从中序与后序遍历序列构造二叉树
思路
了解手动构造二叉树的流程
- 后序数组为0,空节点
- 后序数组最后一个元素为根节点
- 寻找后序数组最后一个元素在中序数组里的位置
- 切割中序数组
- 切割后序数组
- 递归处理左右区间
注意:切中序用index,切后序用中序数组的左区间(切区间的时候一定要统一规则)
代码实现
class Solution {
private:
TreeNode* traversal(vector<int>& inorder, vector<int>& postorder) {
if(postorder.size() == 0) return NULL;
// 后序遍历数组的最后一个元素,就是当前的中间结点
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) [delimiterIndex + 1,end)
vector<int> leftInorder(inorder.begin(), inorder.begin() + delimiterIndex);
vector<int> rightInorder(inorder.begin() + delimiterIndex + 1, inorder.end());
// postorder舍弃末尾元素
postorder.resize(postorder.size() - 1);
// 切割后序数组 左闭右开原则[0,leftInorder.size) [leftInorder.size, end]
vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size());
vector<int> rightPostorder(postorder.begin() + leftInorder.size(), postorder.end());
root->left = traversal(leftInorder, leftPostorder);
root->right = traversal(rightInorder, rightPostorder);
return root;
}
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if(inorder.size() == 0 || postorder.size() == 0) return NULL;
return traversal(inorder, postorder);
}
};
总结
1.了解了递归函数在什么时候应该有返回值
2.中序+后序、中序+前序可以构造一个唯一的二叉树,前序+后序不可以
3.切割的时候,一定先切割中序,再用中序的左区间去切割另一个数组,切割的时候一定要遵循统一的区间规则