第一题: 找树左下角的值
这道题用迭代法比较简单,通过层序遍历很容易就能解决这道题目,我们只需要记录最后一行的最左侧元素即可,可以通过一个变量记录每一行的第一个元素,每次循环时对这个变量进行覆盖即可,最后跳出循环的时候这个变量就记录的就是最后一行的最左侧元素;或者在层序遍历时,每次都让right节点先进入队列,这样最后一个出队列的就是最后一行的最左侧元素了!
给出代码:
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
TreeNode* pre = nullptr;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()) {
int size = que.size();
while(size--) {
TreeNode* node = que.front();
que.pop();
pre = node;
if(node->right) que.push(node->right);
if(node->left) que.push(node->left);
}
}
return pre->val;
}
};
当然也可以利用递归+回溯的方法来做这道题目,按照递归三部曲的思路来进行:
①确定函数的参数与返回值;
②确定终止条件;
③确定单层递归的逻辑;
代码如下:
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;
}
};
第二题: 路径总和
这类题型都是使用递归+回溯的方法来解决,代码如下:
①112. 路径总和:
class Solution {
public:
bool hasPathSum(TreeNode* node, int targetSum) {
if(!node) return false;
if(targetSum == node->val && !node->left && !node->right) return true;
if(!node->left && !node->right) return false;
if(node->left) {
if(hasPathSum(node->left, targetSum - node->val)) return true;
}
if(node->right) {
if(hasPathSum(node->right, targetSum - node->val)) return true;
}
return false;
}
};
②112. 路径总和Ⅱ
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
void traversal(TreeNode* root, int targetSum) {
if(!root) return;
path.push_back(root->val);
if(!root->left && !root->right && targetSum == root->val) {
res.push_back(path);
return;
}
if(root->left) {
traversal(root->left, targetSum - root->val);
path.pop_back();
}
if(root->right) {
traversal(root->right, targetSum - root->val);
path.pop_back();
}
return;
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
traversal(root, targetSum);
return res;
}
};
第三题: 从中序与后序遍历序列构造二叉树
这道题比较容易想到的方法是递归法,可以分为以下这六个步骤:
①如果后续数组的size为0,则说明是空节点;
②后续数组的最后一个元素为root节点(中间节点);
③找到后序数组最后一个元素在中序数组的位置,作为切割点
④根据中间节点分割中序数组,前半部分为中序左数组,后半部分为中序右数组;
⑤根据中序数组的分割结果,来分割后续数组,得到后序左数组和后序右数组;
⑥递归处理左区间和右区间;
难点在于:如何进行切割,以及边界值找不好就容易乱套。在切割的过程中会产生四个区间,把握不好不变量的话,一会左闭右开,一会左闭右闭,必然乱套!
代码如下:
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)
vector<int> leftInorder(inorder.begin(), inorder.begin() + delimiterIndex);
// [delimiterIndex + 1, end)
vector<int> rightInorder(inorder.begin() + delimiterIndex + 1, inorder.end() );
// postorder 舍弃末尾元素
postorder.resize(postorder.size() - 1);
// 切割后序数组
// 依然左闭右开,注意这里使用了左中序数组大小作为切割点
// [0, leftInorder.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;
}
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if (inorder.size() == 0 || postorder.size() == 0) return NULL;
return traversal(inorder, postorder);
}
};
Day18打卡!!!