Leetcode 513. 找树左下角的值
题目链接 513 找树左下角的值
本题目关键在于审题上,如果理解了左下角值的定义本题目就比较简单了,左下角的意思是二叉树最大深度的第一个节点就为左下角的值。说的这里,可以看出用迭代法模板更简单一些。but,这里我们先用递归法来写一下:
在这里,我们不需要考虑前中后序,因为三种情况都是先左后右的遍历方法,我们是不断往下寻找节点,只要保证不断的左右遍历即可。
1.确定递归函数的参数和返回值
参数必须有要遍历的树的根节点,还有就是一个int型的变量用来记录最长深度。 这里就不需要返回值了,所以递归函数的返回类型为void。
本题还需要类里的两个全局变量,maxLen用来记录最大深度,result记录最大深度最左节点的数值。
2.确定终止条件
当遇到叶子节点的时候,就需要统计一下最大的深度了,所以需要遇到叶子节点来更新最大深度。
3.确定递归单层逻辑
注意有回溯过程
下面上代码:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
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;
}
};
Leetcode 112. 路径总和
题目链接 112 路径总和
本题目和前面的题一样不需要考虑前中后序,我们用递归的方法来写一下:
1.确定递归函数的参数和返回类型:
参数:需要二叉树的根节点,还需要一个计数器,这个计数器用来计算二叉树的一条边之和是否正好是目标和,计数器为int型。
- 如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。(这种情况就是本文下半部分介绍的113.路径总和ii)
- 如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。
- 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(本题的情况)
2.确定终止条件:
我们这里在遍历二叉树时,我们做减法操作,对目标值不停的,当在叶子节点时,若计数器为零,那说明找到了符合要求的路径,反之,找不到。
3.单层循环条件:
因为终止条件是判断叶子节点,所以递归的过程中就不要让空节点进入递归了。
递归函数是有返回值的,如果递归函数返回true,说明找到了合适的路径,应该立刻返回。
下面上代码:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool traversal(TreeNode* cur ,int count){
if(!cur->left&&!cur->right&&count == 0){
return true;
}
if(!cur->left&&!cur->right&&count!=0){
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;
}
bool hasPathSum(TreeNode* root, int sum) {
if(root == NULL){
return false;
}
return traversal(root,sum-root->val);
}
};
Leetcode 113. 路径总和 II
题目链接 113 路径总和 II
本题目和上面的题目差不多,只是输出不同,这里返回的值是全部符合条件的路径,对于我们所写的递归函数的参数与返回值都需要做出一定的改变。
下面上代码:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
private:
vector<vector<int>> result;
vector<int> path;
void traversal(TreeNode* cur,int count){
if(!cur->left&&!cur->right&&count == 0){
result.push_back(path);
return ;
}
if(!cur->left && !cur->right && count != 0){
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;
}
};
Leetcode 106. 从中序与后序遍历序列构造二叉树
题目链接 106. 从中序与后序遍历序列构造二叉树
本题目考察的主要是对二叉树构造的步骤,
首先回忆一下如何根据两个顺序构造一个唯一的二叉树,相信理论知识大家应该都清楚,就是以 后序数组的最后一个元素为切割点,先切中序数组,根据中序数组,反过来再切后序数组。一层一层切下去,每次后序数组最后一个元素就是节点元素。
下面是代码思路:
说到一层一层切割,就应该想到了递归。
来看一下一共分几步:
-
第一步:如果数组大小为零的话,说明是空节点了。
-
第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
-
第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
-
第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
-
第五步:切割后序数组,切成后序左数组和后序右数组
-
第六步:递归处理左区间和右区间
下面上代码加注释:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
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.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);
}
};
Leetcode 105. 从前序与中序遍历序列构造二叉树
题目链接 105 从前序与中序遍历序列构造二叉树
该题目和上面的题目思路一样,画一个图即可明白,下面上代码:
class Solution {
private:
TreeNode* traversal (vector<int>& inorder, int inorderBegin, int inorderEnd, vector<int>& preorder, int preorderBegin, int preorderEnd) {
if (preorderBegin == preorderEnd) return NULL;
int rootValue = preorder[preorderBegin]; // 注意用preorderBegin 不要用0
TreeNode* root = new TreeNode(rootValue);
if (preorderEnd - preorderBegin == 1) return root;
int delimiterIndex;
for (delimiterIndex = inorderBegin; delimiterIndex < inorderEnd; delimiterIndex++) {
if (inorder[delimiterIndex] == rootValue) break;
}
// 切割中序数组
// 中序左区间,左闭右开[leftInorderBegin, leftInorderEnd)
int leftInorderBegin = inorderBegin;
int leftInorderEnd = delimiterIndex;
// 中序右区间,左闭右开[rightInorderBegin, rightInorderEnd)
int rightInorderBegin = delimiterIndex + 1;
int rightInorderEnd = inorderEnd;
// 切割前序数组
// 前序左区间,左闭右开[leftPreorderBegin, leftPreorderEnd)
int leftPreorderBegin = preorderBegin + 1;
int leftPreorderEnd = preorderBegin + 1 + delimiterIndex - inorderBegin; // 终止位置是起始位置加上中序左区间的大小size
// 前序右区间, 左闭右开[rightPreorderBegin, rightPreorderEnd)
int rightPreorderBegin = preorderBegin + 1 + (delimiterIndex - inorderBegin);
int rightPreorderEnd = preorderEnd;
root->left = traversal(inorder, leftInorderBegin, leftInorderEnd, preorder, leftPreorderBegin, leftPreorderEnd);
root->right = traversal(inorder, rightInorderBegin, rightInorderEnd, preorder, rightPreorderBegin, rightPreorderEnd);
return root;
}
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if (inorder.size() == 0 || preorder.size() == 0) return NULL;
// 参数坚持左闭右开的原则
return traversal(inorder, 0, inorder.size(), preorder, 0, preorder.size());
}
};
这里是不用重复定义vector了,每次用下标索引来分割。
end