第一题是找树左下角的值https://leetcode.cn/problems/find-bottom-left-tree-value/description/,没啥思路。看看题解代码随想录。卡哥提到了层序遍历,上手写一下,一遍整出。
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
queue que;
int result = 0;
if (root != NULL)
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;
}
};
递归方法通过更新叶子结点的深度值,先遍历左,后遍历右,保证找到的第一个深度最大的叶子结点是最后一行最左侧的点。
class Solution {
public:
int maxdepth = INT_MIN;
int result;
void travel(TreeNode* node, int depth) { //确定递归函数的参数和返回值
if (node->left == NULL && node->right == NULL) { //确定终止条件
if (maxdepth < depth) {
maxdepth = depth;
result = node->val;
}
return;
}
if (node->left) { //确定单层递归逻辑
depth++;
travel(node->left, depth);
depth--; //回溯,返回上层
}
if (node->right) {
depth++;
travel(node->right, depth);
depth--;
}
return;
}
int findBottomLeftValue(TreeNode* root) {
travel(root, 0);
return result;
}
};
拿下。
第二题是路径总和https://leetcode.cn/problems/path-sum/description/,有点想法了,写了一遍发现细节还是不清楚,如何由下向上返回判断结果。看题解才写出来第一遍代码。
class Solution {
public:
bool travel(TreeNode* node, int count) { //确定递归函数的参数与返回类型//
if (node->left == NULL && node->right == NULL && count == 0)
return true;
if (node->left == NULL && node->right == NULL && count != 0)
return false; //终止递归逻辑//
if (node->left) {
count -= node->left->val;
if (travel(node->left, count))
return true; //向上返回true//
count += node->left->val;
}
if (node->right) {
count -= node->right->val;
if (travel(node->right, count))
return true;
count += node->right->val; //回溯//
}
return false;
}
bool hasPathSum(TreeNode* root, int targetSum) {
if (root == NULL)
return false;
return travel(root, targetSum - root->val);
}
};
迭代用栈也是可以的。
class Solution {
public:
bool hasPathSum(TreeNode* root, int targetSum) {
if (root == NULL)
return false;
stack> st;
st.push(pair(root, root->val));
while (!st.empty()) {
pair node = st.top();
st.pop();
if (!node.first->left && !node.first->right &&
targetSum == node.second)
return true;
if (node.first->right)
st.push(pair(
node.first->right, node.second + node.first->right->val));
if (node.first->left)
st.push(pair(
node.first->left, node.second + node.first->left->val));
}
return false;
}
};
相似题目是https://leetcode.cn/problems/path-sum-ii/,不过此题需要我们遍历整颗树,因此递归函数不需要返回值。
class Solution {
public:
vector> result;
vector path;
void travel(TreeNode* node, int count) {
if (!node->left && !node->right && count == 0) {
result.push_back(path);
return;
}
if (!node->left && !node->right)
return;
if (node->left) {
path.push_back(node->left->val);
count -= node->left->val;
travel(node->left, count);
count += node->left->val;
path.pop_back();
}
if (node->right) {
path.push_back(node->right->val);
count -= node->right->val;
travel(node->right, count);
count += node->right->val;
path.pop_back();
}
return;
}
vector> pathSum(TreeNode* root, int targetSum) {
result.clear();
path.clear();
if (root == NULL)
return result;
path.push_back(root->val);
travel(root, targetSum - root->val);
return result;
}
};
第三题是构造二叉树力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台,直接上卡哥讲解。重点在于切割两个数组,再对切割结果进行递归。
class Solution {
public:
TreeNode* travel(vector& inorder, vector& 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;
}
vector leftInorder(inorder.begin(),
inorder.begin() +
delimiterIndex); //确定中序左子树//
vector rightInorder(inorder.begin() + delimiterIndex + 1,
inorder.end()); //确定中序右子树//
postorder.resize(postorder.size() - 1); //丢最后一个数组//
vector leftPostorder(postorder.begin(),
postorder.begin() +
leftInorder.size()); //确定后序左子树//
vector rightPostorder(postorder.begin() + leftInorder.size(),
postorder.end()); //确定后序右子树//
root->left = travel(leftInorder, leftPostorder);
root->right = travel(rightInorder, rightPostorder);
return root;
}
TreeNode* buildTree(vector& inorder, vector& postorder) {
if (inorder.size() == 0 || postorder.size() == 0)
return NULL;
return travel(inorder, postorder);
}
};
下标法规避了建立vector的麻烦。
class Solution {
public:
TreeNode* travel(vector& inorder, int inorderBegin, int inorderEnd, vector& postorder, int postorderBegin, int postorderEnd){
if (postorderBegin == postorderEnd) return NULL;
int rootValue = postorder[postorderEnd - 1];
TreeNode* root = new TreeNode(rootValue);
if (postorderBegin - postorderEnd == 1) return root;
int delimiterIndex;
for(delimiterIndex = 0; delimiterIndex < inorderEnd; delimiterIndex++){
if (inorder[delimiterIndex] == rootValue) break;
}
//切割中序数组
int leftInorderBegin = inorderBegin;
int leftInorderEnd = delimiterIndex;
int rightInorderBegin = delimiterIndex + 1;
int rightInorderEnd = inorderEnd;
//切割后序数组
int leftPostorderBegin = postorderBegin;
int leftPostorderEnd = postorderBegin + delimiterIndex - inorderBegin;
int rightPostordreBegin = postorderBegin + delimiterIndex - inorderBegin;
int rightPostordreEnd = postorderEnd - 1;
root->left = travel(inorder, leftInorderBegin, leftInorderEnd, postorder, leftPostorderBegin, leftPostorderEnd);
root->right = travel(inorder,rightInorderBegin, rightInorderEnd, postorder, rightPostordreBegin, rightPostordreEnd);
return root;
}
TreeNode* buildTree(vector& inorder, vector& postorder) {
if (inorder.size() == 0 || postorder.size() == 0) return NULL;
return travel(inorder, 0, inorder.size(), postorder, 0, postorder.size());
}
};
下一题是用前序和中序构造二叉树,照猫画虎 。
class Solution {
public:
TreeNode* travel(vector& preorder, vector& inorder){
if (preorder.size() == 0) return NULL;
int rootvalue = preorder[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;//找到切割点//
}
//切中序数组
vector leftInorder(inorder.begin(), inorder.begin() + delimiterIndex);
vector rightInorder(inorder.begin() + delimiterIndex + 1, inorder.end());
//切前序数组
vector leftPreorder(preorder.begin() + 1, preorder.begin() + leftInorder.size());
vector rightPreorder(preorder.begin() + leftInorder.size(), preorder.end());
root->left = travel(leftPreorder, leftInorder);
root->right = travel(rightPreorder, rightInorder);
return root;
}
TreeNode* buildTree(vector& preorder, vector& inorder) {
if (preorder.size() == 0 || inorder.size() == 0) return NULL;
return travel(preorder, inorder);
}
};
下标法如下:
class Solution {
public:
TreeNode* travel(vector& preorder, int preorderBegin, int preorderEnd, vector& inorder, int inorderBegin, int inorderEnd){
if (preorderBegin == preorderEnd) return NULL;
int rootValue = preorder[preorderBegin];
TreeNode* root = new TreeNode(rootValue);
if (preorderEnd - preorderBegin == 1) return root;
//找中序切割点
int delimiterIndex;
for (delimiterIndex = 0; delimiterIndex < inorderEnd; delimiterIndex++){
if (inorder[delimiterIndex] == rootValue) break;
}
//切割中序
int leftinorderBegin = inorderBegin;
int leftinorderEnd = delimiterIndex;
int rightinorderBegin = delimiterIndex + 1;
int rightinorderEnd = inorderEnd;
//切割后序
int leftpreorderBegin = preorderBegin + 1;
int leftpreorderEnd = preorderBegin + 1 + delimiterIndex - inorderBegin;
int rightpreorderBegin = preorderBegin + 1 + delimiterIndex - inorderBegin;
int rightpreorderEnd = preorderEnd;
root->left = travel(preorder, leftpreorderBegin, leftpreorderEnd, inorder, leftinorderBegin, leftinorderEnd);
root->right = travel(preorder, rightpreorderBegin, rightpreorderEnd, inorder, rightinorderBegin, rightinorderEnd);
return root;
}
TreeNode* buildTree(vector& preorder, vector& inorder) {
if (preorder.size() == 0 || inorder.size() == 0) return NULL;
return travel(preorder, 0, preorder.size(), inorder, 0, inorder.size());
}
};
今天的最大收获是用中序和后序,中序和前序建立二叉树。再一次加深了对递归和回溯的掌握。