题目来源:1008.前序遍历构造二叉搜索树
题解:
/**
* 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:
TreeNode* bstFromPreorder(vector<int>& preorder) {
return build(preorder,0,preorder.size()-1);
}
TreeNode* build(vector<int>& preorder,int start,int end){
if(start>end)
return nullptr;
int val=preorder[start];
TreeNode *root=new TreeNode(val);
int p=start+1;
while(p<=end&&preorder[p]<val)
p++;
root->left=build(preorder,start+1,p-1);
root->right=build(preorder,p,end);
return root;
}
};
题目来源:105.从前序与中序遍历序列构造二叉树
题解:
class Solution {
private:
unordered_map<int, int> index;
public:
TreeNode* myBuildTree(const vector<int>& preorder, const vector<int>& inorder, int preorder_left, int preorder_right, int inorder_left, int inorder_right) {
if (preorder_left > preorder_right) {
return nullptr;
}
// 前序遍历中的第一个节点就是根节点
int preorder_root = preorder_left;
// 在中序遍历中定位根节点
int inorder_root = index[preorder[preorder_root]];
// 先把根节点建立出来
TreeNode* root = new TreeNode(preorder[preorder_root]);
// 得到左子树中的节点数目
int size_left_subtree = inorder_root - inorder_left;
// 递归地构造左子树,并连接到根节点
// 先序遍历中「从 左边界+1 开始的 size_left_subtree」个元素就对应了中序遍历中「从 左边界 开始到 根节点定位-1」的元素
root->left = myBuildTree(preorder, inorder, preorder_left + 1, preorder_left + size_left_subtree, inorder_left, inorder_root - 1);
// 递归地构造右子树,并连接到根节点
// 先序遍历中「从 左边界+1+左子树节点数目 开始到 右边界」的元素就对应了中序遍历中「从 根节点定位+1 到 右边界」的元素
root->right = myBuildTree(preorder, inorder, preorder_left + size_left_subtree + 1, preorder_right, inorder_root + 1, inorder_right);
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int n = preorder.size();
// 构造哈希映射,帮助我们快速定位根节点
for (int i = 0; i < n; ++i) {
index[inorder[i]] = i;
}
return myBuildTree(preorder, inorder, 0, n - 1, 0, n - 1);
}
};
题目来源:1080. 根到叶路径上的不足节点
题解:
class Solution {
public:
TreeNode* sufficientSubset(TreeNode* root, int limit) {
if(root==nullptr)
return nullptr;
if(root->left==root->right)
{
if(root->val<limit)
return nullptr;
return root;
}
root->left=sufficientSubset(root->left,limit-root->val);
root->right=sufficientSubset(root->right,limit-root->val);
if(root->left==nullptr&&root->right==nullptr)
return nullptr;
return root;
}
};
题目来源:1110.删点成林
思路:
出现以下两种情况需要考虑添加节点进forest:
题解:
class Solution {
public:
vector<TreeNode*> forest;
unordered_set<int> delete_set;
TreeNode* deletea(TreeNode* root, TreeNode* parent) {
if(root==nullptr) return nullptr;
root->left=deletea(root->left,root);
root->right=deletea(root->right,root);
if(delete_set.find(root->val)!=delete_set.end()){
if(root->left) forest.push_back(root->left);
if(root->right) forest.push_back(root->right);
root=nullptr;
}
else if(parent==nullptr)
forest.push_back(root);
return root;
}
vector<TreeNode*> delNodes(TreeNode* root, vector<int>& to_delete) {
for(auto val:to_delete) delete_set.insert(val);
deletea(root,nullptr);
return forest;
}
};
题目来源:114.二叉树展开为链表
Tips: C++ Vector 库 - at() 函数:返回对向量中位置 n 处元素的引用
题解:
class Solution {
public:
void flatten(TreeNode* root) {
vector<TreeNode*> list;
dfs(root,list);
int n=list.size();
for(int i=1;i<n;i++){
TreeNode *prev=list.at(i-1),*cur=list.at(i);
prev->left=nullptr;
prev->right=cur;
}
cout<<endl;
}
void dfs(TreeNode* root,vector<TreeNode*> &list){
if(root!=nullptr)
{
list.push_back(root);
dfs(root->left,list);
dfs(root->right,list);
}
}
};
题目来源:1339.分裂二叉树的最大乘积
题解:
class Solution {
int sum=0;
int best=0;
public:
void dfs(TreeNode* root){
if(root==nullptr)
return;
sum+=root->val;
dfs(root->left);
dfs(root->right);
}
int dfs2(TreeNode* root){
if(root==nullptr)
return 0;
int cur=dfs2(root->left)+dfs2(root->right)+root->val;
if(abs(cur*2-sum)<abs(best*2-sum)){
best=cur;
}
return cur;
}
int maxProduct(TreeNode* root) {
dfs(root);
dfs2(root);
return (long long)best*(sum-best)%1000000007;
}
};
题目来源:1372. 二叉树中的最长交错路径
题解:
class Solution {
int maxans=0;
public:
void dfs(TreeNode* root,int dir,int len){
maxans=max(maxans,len);
if(dir==0){
if(root->left) dfs(root->left,1,len+1);
if(root->right) dfs(root->right,0,1);
}
else{
if(root->right) dfs(root->right,0,len+1);
if(root->left) dfs(root->left,1,1);
}
}
int longestZigZag(TreeNode* root) {
if(root==nullptr)
return 0;
dfs(root,0,0);
dfs(root,1,0);
return maxans;
}
};
题目来源:1373. 二叉搜索子树的最大键值和
思路:
题解:
class Solution {
int maxans=0;
public:
void dfs(TreeNode* root,int dir,int len){
maxans=max(maxans,len);
if(dir==0){
if(root->left) dfs(root->left,1,len+1);
if(root->right) dfs(root->right,0,1);
}
else{
if(root->right) dfs(root->right,0,len+1);
if(root->left) dfs(root->left,1,1);
}
}
int longestZigZag(TreeNode* root) {
if(root==nullptr)
return 0;
dfs(root,0,0);
dfs(root,1,0);
return maxans;
}
};
题目来源:1379.通知所有的员工所需的时间
题解:
class Solution {
public:
int numOfMinutes(int n, int headID, vector<int>& manager, vector<int>& informTime) {
int res = 0;
vector<int> help(n);//记忆化搜索数组 元素为最顶的头到该员工(下标为员工编号)花费的总时间
function<int(int)> dfs = [&](int sup) {//lambda递归函数
if (sup == -1) return 0;//到达最顶了 直接返回0
else if (help[sup]) return help[sup];//如果当前员工在表里,直接取值
help[sup] = informTime[sup] + dfs(manager[sup]);//返回来的上级总时间+当前员工通知时间即为 最顶员工到当前的总时间
return help[sup];
};
for (int i = 0; i < n; i++) {
if (informTime[i] != 0) continue;//只从最底层员工开始递归,不是底层员工直接排除
res = max(res, dfs(manager[i]));//传到当前最底层员工的总时间更新到全局
}
return res;
}
};
题目来源:1443.收集树上所有苹果的最少时间
思路:
把一个树拆分成许多小子树来看,对于一个根节点有三种情况
三种情况可以简化为
走到该节点的开销curcost=所有孩子的开销childcost+走到该节点的开销(cost==2)
所有孩子的开销childcost可能=0,表示所有的子节点里都无苹果
题解:
class Solution {
public:
//g 图
//vis 判断节点是否被访问过,遍历过的节点不能再遍历,
//同时因为是无向图,vis间接的确定了父子节点的关系,在子节点访问其子节点的时候不可能再去访问父节点
//cost 只有以0节点刚进去的时候cost=0,在之后访问0节点的子节点时,cost都等于2(来回)
int dfs(int curn, vector<vector<int> >& g, vector<bool>& vis, vector<bool>& hasApple, int cost)
{
if(vis[curn])
return 0;
vis[curn]=true;
int childcost=0;
for(auto next:g[curn])
{
childcost+=dfs(next,g,vis,hasApple,2);//遍历当前节点的所有子节点
//如果childcost=0的话代表所有的子节点都没有苹果
}
//对应上面的情况1,所有子节点里都无苹果,且该节点本身也无苹果,走到该节点的开销=0
if(!hasApple[curn] && childcost==0)
return 0;
//对应上面的情况2,3 走到该节点的开销为所有摘子节点里的苹果的开销+走到该节点的开销cost
//如果childcost=0的话,对应情况3
//如果childcost!=0的话,对应情况2
return childcost+cost;
}
int minTime(int n, vector<vector<int>>& edges, vector<bool>& hasApple) {
vector<vector<int>> g(n);
vector<bool> vis(n,false);
for(auto edge:edges)
{
g[edge[0]].push_back(edge[1]);
g[edge[1]].push_back(edge[0]);
}
return dfs(0,g,vis,hasApple,0);//第一层由0节点出发,开销是0
}
};
题目来源:1457.二叉树中的伪回文路径
题解:
class Solution {
public:
int count=0;
//检查是否为回文序列
void check(unordered_map<int,int> &path){
int flag=0;
for(unordered_map<int,int>::iterator it=path.begin();it!=path.end();it++)
{
if(it->second%2==1) flag++;
}
if(flag<=1) count++;
}
void dfs(TreeNode* root,unordered_map<int,int> &path)
{
if(root==nullptr) return;
path[root->val]++;
if(root->left==nullptr&&root->right==nullptr)
check(path);
dfs(root->left,path);
dfs(root->right,path);
path[root->val]--;
}
int pseudoPalindromicPaths (TreeNode* root) {
unordered_map<int,int> path;
dfs(root,path);
return count;
}
};
题目来源:2049.统计最高分的节点数目
题解:
class Solution {
public:
long maxScore = 0; //记录最大分数,用于cnt++
int cnt = 0; //返回值,即最高得分节点数目
int n; //节点总数,用于得到size用于计算三种情况下节点的个数
vector<vector<int>> children; //构图,用于dfs
int dfs(int node) {
long score = 1;
int size = n - 1; //当前节点被删除
for (int c : children[node]) {
int t = dfs(c); //得到以当前节点孩子节点为根节点的树的节点个数
score *= t; //乘左右孩子数量
size -= t; //保存剩余节点个数
}
//判断是否为最初根节点,否则导致size=0
if (node != 0) {
score *= size; //乘被删节点父节点所在树节点的节点个数
}
//代表出现了与最高分相同的节点,返回答案计数+1
if (score == maxScore) {
cnt++;
} else if (score > maxScore) {
maxScore = score;
cnt = 1;
}
return n - size; //返回以当前节点node为根节点组成的树的节点总数
}
int countHighestScoreNodes(vector<int>& parents) {
this->n = parents.size();
//[父亲]:{左右孩子}
this->children = vector<vector<int>>(n);
for (int i = 0; i < n; i++) {
int p = parents[i];
if (p != -1) {
children[p].emplace_back(i);
}
}
//从根节点开始dfs搜索
dfs(0);
//返回有最高得分节点的数目
return cnt;
}
};
题目来源:894. 所有可能的真二叉树
题解:
/**
* 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:
vector<TreeNode*> allPossibleFBT(int n) {
vector<TreeNode*> dp;
if(n%2==0) return dp;
if(n==1) {
dp.push_back(new TreeNode(0));
return dp;
}
for(int i=1;i<=n-2;i++){
vector<TreeNode*> left=allPossibleFBT(i);
vector<TreeNode*> right=allPossibleFBT(n-1-i);
for(int j=0;j<left.size();++j){
for(int k=0;k<right.size();++k){
TreeNode *root = new TreeNode(0);
root->left = left[j];
root->right = right[k];
//对于左子树有i个结点,右子树有N-1-i个结点时,我们把所有可能的树push进入队列
dp.push_back(root);
}
}
}
return dp;
}
};