代码随想录第十八天|Leetcode513.找树左下角的值、Leetcode112. 路径总和、Leetcode113. 路径总和ii、Leetcode106.从中序与后序遍历序列构造二叉树、Leetcode105.从前序与中序遍历序列构造二叉树
Leetcode513.找树左下角的值
遍历太熟悉了,完全通畅一遍过
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
int result;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()){
int size=que.size();
result=que.front()->val;
for(int i=0;i<size;i++){
TreeNode* temp=que.front();
que.pop();
if(temp->left) que.push(temp->left);
if(temp->right) que.push(temp->right);
}
}
return result;
}
};
DFS不太适合这道题,不过也得会
class Solution {
public:
void dfs(TreeNode* cur,int& result,int curHeight,int& maxHeight){
if(cur==NULL) return;
curHeight++;
dfs(cur->left,result,curHeight,maxHeight);
dfs(cur->right,result,curHeight,maxHeight);
if(curHeight>maxHeight){//对首次达到最深处的值进行保存
maxHeight=curHeight;
result=cur->val;
}
}
int findBottomLeftValue(TreeNode* root) {
int result=0;
int curHeight=0;
int maxHeight=0;
dfs(root,result,curHeight,maxHeight);
return result;
}
};
Leetcode112. 路径总和
简直是DFS的代表性题目,非常值得二刷
二刷提醒
class Solution {
public:
bool hasPathSum(TreeNode* root, int targetSum) {
if(root==NULL) return false;
if(root->left==NULL&&root->right==NULL) return targetSum==root->val; //到达叶子结点
return hasPathSum(root->left,targetSum-root->val) || hasPathSum(root->right,targetSum-root->val);//这太精髓了
}
};
Leetcode113. 路径总和ii
二刷提醒
由于path是临时变量,在结束一整套递归后,恰好会在return时清零释放掉,避免了自己写清零逻辑的混乱。
class Solution {
private:
vector<vector<int>> result;
void dfs(TreeNode* root, int targetSum,vector<int> path){
if(root==NULL) return;
targetSum-=root->val;
path.push_back(root->val);
if(root->left==NULL&&root->right==NULL&&targetSum==0){
result.push_back(path);
return;//path自动清零
}
if(root->left) dfs(root->left,targetSum,path);
if(root->right) dfs(root->right,targetSum,path);
}
public:
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
vector<int> path;
dfs(root,targetSum,path);
return result;
}
};
Leetcode106.从中序与后序遍历序列构造二叉树
注意
- 数组拷贝构造为左闭右开区间[start,end)
- 一定要自己先用注释梳理好逻辑再写
class Solution {
private:
TreeNode* treversal(vector<int>& inorder, vector<int>& postorder){
//如果为空,直接return
if(postorder.size()==0) return NULL;
//必须做的事
int value=postorder[postorder.size()-1];
TreeNode* cur=new TreeNode(value);
//结束逻辑,如果为1直接返回
if(postorder.size()==1) return cur;
//切割中序遍历
int i;
for(i=0;i<inorder.size();i++){//找到切割位置
if(inorder[i]==cur->val) break;
}
vector<int>inorderLeft(inorder.begin(),inorder.begin()+i);
vector<int>inorderRight(inorder.begin()+i+1,inorder.end());
//切割后序遍历
vector<int>postorderLeft(postorder.begin(),postorder.begin()+inorderLeft.size());
vector<int>postorderRight(postorder.begin()+inorderLeft.size(),postorder.end()-1);
//递归赋值给左右子树
cur->left=treversal(inorderLeft,postorderLeft);
cur->right=treversal(inorderRight,postorderRight);
//递归结束的return
return cur;
}
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
TreeNode* root = treversal(inorder,postorder);
return root;
}
};
Leetcode105.从前序与中序遍历序列构造二叉树
跟上道题一模一样,一遍过直接一个字都没错
class Solution {
private:
TreeNode* treversal(vector<int>& preorder, vector<int>& inorder){
//如果为空,直接返回
if(preorder.size()==0) return NULL;
//生成当前节点
TreeNode* cur=new TreeNode(preorder[0]);
//如果为1,直接返回当前节点
if(preorder.size()==1) return cur;
//找到根的位置
int i=0;
for(i=0;i<inorder.size();i++){
if(inorder[i]==preorder[0]) break;
}
//切割中序遍历
vector<int>inorderLeft(inorder.begin(),inorder.begin()+i);
vector<int>inorderRight(inorder.begin()+i+1,inorder.end());
//切割先序遍历
vector<int>preorderLeft(preorder.begin()+1,preorder.begin()+1+inorderLeft.size());
vector<int>preorderRight(preorder.begin()+1+inorderLeft.size(),preorder.end());
//给左右子树赋值
cur->left=treversal(preorderLeft,inorderLeft);
cur->right=treversal(preorderRight,inorderRight);
//返回当前节点
return cur;
}
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
TreeNode* root=treversal(preorder,inorder);
return root;
}
};
总结DFS模板
自顶向下寻找路径
一般路径
由于path是临时变量,在结束一整套递归后,恰好会在return时清零释放掉,避免了自己写清零逻辑的混乱。
vector<vector<int>>res;
void dfs(TreeNode*root,vector<int>path)
{
if(root==NULL) return; //根节点为空直接返回
path.push_back(root->val); //做必须做的事
if(!root->left && !root->right) //结束逻辑
{
res.push_back(path);
return;
}
dfs(root->left,path); //到这说明结束逻辑没生效,那就继续递归
dfs(root->right,path);
}
目标和路径targetsum
- 由于path是临时变量,在结束一整套递归后,恰好会在return时清零释放掉,避免了自己写清零逻辑的混乱。时刻牢记时刻牢记
- 不用新增一个临时变量cursum来判断当前路径和,只需要用目标和targetsum减去节点值,最终结束条件判断target==0即可
void dfs(TreeNode*root, int targetsum, vector<int> path)
{
if (root==NULL) return;//根节点为空直接返回
targetsum-= root->val; //做必须做的事
path.push_back(root->val);
if (!root->left && !root->right && targetsum == 0)//结束逻辑
{
res.push_back(path);
return;
}
dfs(root->left, targetsum, path);//到这说明结束逻辑没生效,那就继续递归
dfs(root->right, targetsum, path);
}