513.找树左下角的值
题目链接:. - 力扣(LeetCode)
视频讲解:怎么找二叉树的左下角? 递归中又带回溯了,怎么办?| LeetCode:513.找二叉树左下角的值
题目描述:
给定一个二叉树的 根节点 root
,请找出该二叉树的 最底层 最左边 节点的值。
假设二叉树中至少有一个节点。
示例 1:
输入: root = [2,1,3] 输出: 1
解题思路:
递归法思路--引入一个深度概念,查找方法为先左子树后右子树。每次达到一个新的更大深度时,第一个找到的叶子节点即为左叶子,只要保证深度为最深,该叶子节点即为题目要求的结果。然而,有时第一个左叶子节点可能不是答案,因为它的深度不是最深。因此,需要使用回溯方法来确保找到正确的节点。
代码:
递归法:
class Solution {
public:
int result = 0;
int maxDepth = INT_MIN;
void traversal(TreeNode* root, int depth)
{
if(root->left == nullptr && root->right == nullptr)
{
if(depth > maxDepth)
{
maxDepth = depth;
result = root->val;
}
return;
}
if(root->left)
{
// depth++;
// traversal(root->left,depth);
// depth--;
traversal(root->left,depth+1);
}
if(root->right)
{
// depth++;
// traversal(root->right,depth);
// depth--;
traversal(root->right,depth+1);
}
}
int findBottomLeftValue(TreeNode* root) {
traversal(root,0);
return result;
}
};
层次遍历迭代法:
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
queue<TreeNode*> q;
int result;
q.push(root);
while(!q.empty())
{
int sz = q.size();
result = q.front()->val;
while(sz--)
{
TreeNode* node = q.front();
q.pop();
if(node)
{
if(node->left) q.push(node->left);
if(node->right) q.push(node->right);
}
}
}
return result;
}
};
112. 路径总和
题目链接:. - 力扣(LeetCode)
视频讲解:拿不准的遍历顺序,搞不清的回溯过程,我太难了! | LeetCode:112. 路径总和
题目描述:
给你二叉树的根节点 root
和一个表示目标和的整数 targetSum
。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum
。如果存在,返回 true
;否则,返回 false
。
叶子节点 是指没有子节点的节点。
示例 1:
输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22 输出:true 解释:等于目标和的根节点到叶节点路径如上图所示。
解题思路:
- 逆向思维--从targetSum初始值开始,每经过一个节点就减去该节点对应的值,若到达叶子节点时targetSum减为0,则找到一条路径。
- 回溯方法对比:该题跟上一题一样使用到了回溯方法,但上一题中有变量撤回操作(depth--),本题中没使用该操作是因为上一题中depth++后对当前函数而言此时depth不应属于当前层而是属于下一层,因此又使用depth--进行撤回操作。此题中targetSum -= root->val操作符合当前函数所做处理,属于当前层操作,因此在后来调用递归后没有再对targetSum再做操作。姑且称上一题为显式回溯,该题为隐式回溯(自己想的名词)。
- 没有前中后序方法。先左子树操作,再右子树操作。
代码:
class Solution {
public:
bool hasPathSum(TreeNode* root, int targetSum) {
if(root == nullptr) return false;
targetSum -= root->val;
if(root->left == nullptr && root->right == nullptr && targetSum == 0) return true;
else if(root->left == nullptr && root->right == nullptr && targetSum != 0) return false;
else
{
if(root->left && hasPathSum(root->left,targetSum)) return true;
if(root->right && hasPathSum(root->right,targetSum)) return true;
}
return false;
}
};
113. 路径总和Ⅱ
题目链接:. - 力扣(LeetCode)
题目描述:
给你二叉树的根节点 root
和一个整数目标和 targetSum
,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
叶子节点 是指没有子节点的节点。
示例 1:
输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22 输出:[[5,4,11,2],[5,8,4,5]]
题目对比:
- 112题是找到一条路径即可,该题目是返回所有满足条件的路径。
- 该题中要对path做显式回溯,因为通过递归后path中最后一个元素属于当前函数中得到的值,因此要删除path中最后一个元素。
代码:
class Solution {
public:
void searchPath(TreeNode* node, vector<vector<int>>& result, vector<int>& path, int targetSum)
{
if(node == nullptr) return;
targetSum -= node->val;
path.push_back(node->val);
if(!node->left && !node->right && targetSum == 0) result.push_back(path);
else if(!node->left && !node->right && targetSum != 0) return;
else
{
if(node->left)
{
searchPath(node->left,result,path,targetSum);
path.pop_back();
}
if(node->right)
{
searchPath(node->right,result,path,targetSum);
path.pop_back();
}
}
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
vector<vector<int>> result;
vector<int> path;
searchPath(root,result,path,targetSum);
return result;
}
};
106.从中序与后序遍历序列构造二叉树
题目链接:. - 力扣(LeetCode)
视频讲解:坑很多!来看看你掉过几次坑 | LeetCode:106.从中序与后序遍历序列构造二叉树
题目描述:
给定两个整数数组 inorder
和 postorder
,其中 inorder
是二叉树的中序遍历, postorder
是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
示例 1:
输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3] 输出:[3,9,20,null,null,15,7]
解题思路:
第一步:如果数组大小为零的话,说明是空节点了。
第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
第五步:切割后序数组,切成后序左数组和后序右数组
第六步:递归处理左区间和右区间
代码:
class Solution {
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if(postorder.size() == 0 || inorder.size() == 0) return nullptr;
TreeNode* root = new TreeNode(postorder[postorder.size()-1]);
int idx = 0;
while(idx < inorder.size() && inorder[idx] != root->val) idx++;
//划分左子树
vector<int> leftInorder(inorder.begin(),inorder.begin()+idx);
vector<int> leftPostorder(postorder.begin(),postorder.begin()+leftInorder.size());
root->left = buildTree(leftInorder,leftPostorder);
//划分右子树
vector<int> rightInorder(inorder.begin()+idx+1,inorder.end());
vector<int> rightPostorder(postorder.begin()+leftPostorder.size(),postorder.end()-1);
root->right = buildTree(rightInorder,rightPostorder);
return root;
}
};
105.从前序与中序遍历序列构造二叉树
题目链接:. - 力扣(LeetCode)
题目描述:
给定两个整数数组 preorder
和 inorder
,其中 preorder
是二叉树的先序遍历, inorder
是同一棵树的中序遍历,请构造二叉树并返回其根节点。
示例 1:
输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7] 输出: [3,9,20,null,null,15,7]
代码:
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if(preorder.size()==0 || inorder.size()==0) return nullptr;
TreeNode* root = new TreeNode(preorder[0]);
int idx = 0;
int val = root->val;
while(idx < inorder.size() && inorder[idx] != val) idx++;
vector<int> leftInorder(inorder.begin(),inorder.begin()+idx);
vector<int> rightInorder(inorder.begin()+idx+1,inorder.end());
vector<int>leftPreorder(preorder.begin()+1,preorder.begin()+1+leftInorder.size());
vector<int>rightPreorder(preorder.begin()+1+leftInorder.size(),preorder.end());
root->left = buildTree(leftPreorder,leftInorder);
root->right = buildTree(rightPreorder,rightInorder);
return root;
}
};