文档链接:https://programmercarl.com/
LeetCode513.找树左下角的值
题目链接:https://leetcode.cn/problems/find-bottom-left-tree-value/
思路:第一眼就有想用层序遍历的冲动,找到最后一层的第一个节点即可。
我们来分析一下题目:在树的最后一行找到最左边的值。
首先要是最后一行,然后是最左边的值。
如果使用递归法,如何判断是最后一行呢,其实就是深度最大的叶子节点一定是最后一行。
那么如何找最左边的呢?可以使用前序遍历(当然中序,后序都可以,因为本题没有 中间节点的处理逻辑,只要左优先就行),保证优先左边搜索,然后记录深度最大的叶子节点,此时就是树的最后一行最左边的值。
层序遍历:
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
queue<TreeNode*> que;
int result;
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 != NULL) que.push(node->left);
if(node->right != NULL) que.push(node->right);
}
}
return result;
}
};
递归法:
class Solution {
public:
int maxDepth = INT_MIN;
int result;
int findBottomLeftValue(TreeNode* root) {
int depth = 1;
traversal(root, depth);
return result;
}
void traversal(TreeNode* node, int depth) {
if(node->left == NULL && node->right == NULL) {
if(depth > maxDepth) {
maxDepth = depth;
result = node->val;
}
}
if(node->left != NULL) {
depth++;
traversal(node->left, depth);
depth--;
}
if(node->right != NULL) {
depth++;
traversal(node->right, depth);
depth--;
}
}
};
LeetCode112.路径总和
题目链接:https://leetcode.cn/problems/path-sum/
思路:很明显的递归,但自己写总是写不出来。
递归法:
class Solution {
public:
bool traversal(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 != NULL) {
count -= node->left->val;
if(traversal(node->left, count) == true) return true;
count += node->left->val;
}
if(node->right != NULL) {
count -= node->right->val;
if(traversal(node->right, count) == true) return true;
count += node->right->val;
}
return false;
}
bool hasPathSum(TreeNode* root, int targetSum) {
if(root == NULL) return false;
return traversal(root, targetSum - root->val);
}
};
LeetCode113.路径总和Ⅱ
题目链接:https://leetcode.cn/problems/path-sum-ii/
思路:同上一题,不过这次我们需要遍历整个树,寻找所有满足条件的路径。因此递归函数的返回值应该为void。
递归法:
class Solution {
public:
vector<vector<int>> result;
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
if(root == NULL) return result;
vector<int> vec;
vec.push_back(root->val);
traversal(root, targetSum - root->val, vec);
return result;
}
void traversal(TreeNode* node, int count, vector<int> vec) {
if(node->left == NULL && node->right == NULL && count != 0) return;
if(node->left == NULL && node->right == NULL && count == 0) {
result.push_back(vec);
return;
}
if(node->left != NULL) {
count -= node->left->val;
vec.push_back(node->left->val);
traversal(node->left, count, vec);
count += node->left->val;
vec.pop_back();
}
if(node->right != NULL) {
count -= node->right->val;
vec.push_back(node->right->val);
traversal(node->right, count, vec);
count += node->right->val;
vec.pop_back();
}
}
};
自己写的代码还是太过冗余,附上卡哥的代码:
class solution {
private:
vector<vector<int>> result;
vector<int> path;
// 递归函数不需要返回值,因为我们要遍历整个树
void traversal(TreeNode* cur, int count) {
if (!cur->left && !cur->right && count == 0) { // 遇到了叶子节点且找到了和为sum的路径
result.push_back(path);
return;
}
if (!cur->left && !cur->right) return ; // 遇到叶子节点而没有找到合适的边,直接返回
if (cur->left) { // 左 (空节点不遍历)
path.push_back(cur->left->val);
count -= cur->left->val;
traversal(cur->left, count); // 递归
count += cur->left->val; // 回溯
path.pop_back(); // 回溯
}
if (cur->right) { // 右 (空节点不遍历)
path.push_back(cur->right->val);
count -= cur->right->val;
traversal(cur->right, count); // 递归
count += cur->right->val; // 回溯
path.pop_back(); // 回溯
}
return ;
}
public:
vector<vector<int>> pathSum(TreeNode* root, int sum) {
result.clear();
path.clear();
if (root == NULL) return result;
path.push_back(root->val); // 把根节点放进路径
traversal(root, sum - root->val);
return result;
}
};
LeetCode106.从中序与后序遍历序列构造二叉树
题目链接:https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/
思路:给中序和后序序列手画二叉树肯定是会的,关键在于找到根节点划分新的中序和后序序列。那么该如何用代码实现?
说到一层一层切割,就应该想到了递归。
来看一下一共分几步:
-
第一步:如果数组大小为零的话,说明是空节点了。
-
第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
-
第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
-
第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
-
第五步:切割后序数组,切成后序左数组和后序右数组
-
第六步:递归处理左区间和右区间
代码:
class Solution {
public:
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);
int index;
for(index = 0; index < inorder.size(); index++) {
if(inorder[index] == rootValue) break;
}
vector<int> leftInorder(inorder.begin(), inorder.begin() + index);
vector<int> rightInorder(inorder.begin() + index + 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 = traversal(leftInorder, leftPostorder);
root->right = traversal(rightInorder, rightPostorder);
return root;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if(inorder.size() == 0 || postorder.size() == 0) return NULL;
return traversal(inorder, postorder);
}
};
LeetCode105.从前序与中序遍历序列构造二叉树
题目链接:https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
思路:同106一样
代码:
class Solution {
public:
TreeNode* traversal(vector<int>& preorder, vector<int>& inorder) {
if(preorder.size() == 0) return NULL;
int rootValue = preorder[0];
TreeNode* root = new TreeNode(rootValue);
int index;
for(index = 0; index < inorder.size(); index++) {
if(inorder[index] == rootValue) break;
}
vector<int> leftInorder(inorder.begin(), inorder.begin() + index);
vector<int> rightInorder(inorder.begin() + index + 1, inorder.end());
vector<int> leftPreorder(preorder.begin() + 1, preorder.begin() + leftInorder.size() + 1);
vector<int> rightPreorder(preorder.begin() + leftInorder.size() + 1, preorder.end());
root->left = traversal(leftPreorder, leftInorder);
root->right = traversal(rightPreorder, rightInorder);
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if(preorder.size() == 0 || inorder.size() == 0) return NULL;
return traversal(preorder, inorder);
}
};
总结:二叉树递归开始有点感觉了,不过还是忘不了层序遍历。