letcode第85场双周赛&第307场周赛(Easy+Medium)
第85场双周赛
6156. 得到 K 个黑块的最少涂色次数
难度简单
给你一个长度为 n
下标从 0 开始的字符串 blocks
,blocks[i]
要么是 'W'
要么是 'B'
,表示第 i
块的颜色。字符 'W'
和 'B'
分别表示白色和黑色。
给你一个整数 k
,表示想要 连续 黑色块的数目。
每一次操作中,你可以选择一个白色块将它 涂成 黑色块。
请你返回至少出现 一次 连续 k
个黑色块的 最少 操作次数。
示例 1:
输入:blocks = "WBBWWBBWBW", k = 7
输出:3
解释:
一种得到 7 个连续黑色块的方法是把第 0 ,3 和 4 个块涂成黑色。
得到 blocks = "BBBBBBBWBW" 。
可以证明无法用少于 3 次操作得到 7 个连续的黑块。
所以我们返回 3 。
示例 2:
输入:blocks = "WBWBBBW", k = 2
输出:0
解释:
不需要任何操作,因为已经有 2 个连续的黑块。
所以我们返回 0 。
提示:
n == blocks.length
1 <= n <= 100
blocks[i]
要么是'W'
,要么是'B'
。1 <= k <= n
滑动窗口
最少涂色次数等同于最少白色块数,在满足题目条件的情况下,找出窗口内最少白色块数的情况即可。
class Solution {
public:
int minimumRecolors(string blocks, int k) {
int ans = INT_MAX;
int num = 0;
int r = -1, l = 0;
int len = blocks.size();
while (r < len-1)//注意此处必须len-1
{
r++;
if (blocks[r] == 'B')
num++;
if (r - l + 1 == k)
{
ans = min(ans, k - num);
if (blocks[l] == 'B')
{
num--;
}
l++;
}
}
return ans;
}
};
class Solution {
public:
int minimumRecolors(string blocks, int k) {
int l=0,r=-1;
int num=0,ans=INT_MAX,len=blocks.size();
while(r<len-1)//此处必须len-1
{
r++;
if(blocks[r]=='W')
{
num++;
}
if(r-l+1==k)
{
ans=min(ans,num);
if(blocks[l]=='W')
num--;
l++;
}
}
return ans==INT_MAX?0:ans;
}
};
6157. 二进制字符串重新安排顺序需要的时间
难度中等
给你一个二进制字符串 s
。在一秒之中,所有 子字符串 "01"
同时 被替换成 "10"
。这个过程持续进行到没有 "01"
存在。
请你返回完成这个过程所需要的秒数。
示例 1:
输入:s = "0110101"
输出:4
解释:
一秒后,s 变成 "1011010" 。
再过 1 秒后,s 变成 "1101100" 。
第三秒过后,s 变成 "1110100" 。
第四秒后,s 变成 "1111000" 。
此时没有 "01" 存在,整个过程花费 4 秒。
所以我们返回 4 。
示例 2:
输入:s = "11100"
输出:0
解释:
s 中没有 "01" 存在,整个过程花费 0 秒。
所以我们返回 0 。
提示:
1 <= s.length <= 1000
s[i]
要么是'0'
,要么是'1'
。
暴力模拟
class Solution {
public:
int secondsToRemoveOccurrences(string s) {
int ans=0;
bool flag=true;
while(flag)
{
flag=false;
for(int i=1;i<s.size();i++)
{
if(s[i-1]=='0'&&s[i]=='1')
{
s[i-1]='1';
s[i]='0';
i++;
flag=true;
}
}
if(flag)
ans++;
}
return ans;
}
};
一次遍历(重点)
思考时,我们可以把 01→ 10 的替换看成是 1 向左移动。每一秒,如果 1 的左面是 0,则会向左移动一步。注意连续的 11 不能同时向左移动。
每个 1 向左移动的过程中,有两种情况:
-
在到达最终位置之前,未受到左侧的 1 的 “阻挡”,也就是每一秒都移动了一次,此时,移动次数 = 其左侧 00的个数
-
在到达最终位置之前,受到了左侧 1 的 “阻挡”,也就是说,在某一时刻,其与左侧的 11相邻而组成了 11。在此之后,我们可以证明,当左侧的那个 1到达最终位置时,右侧的 1 一定与左侧的 1 间隔 1 个 0。此时,移动次数 = 左侧 1 的移动次数 + 1。
上面结论的证明: -
当两个 1 相邻时,若左侧的 1 可以移动,此时右侧的 1 不可以移动,因此会有 11→101;
-
当两个 1 间隔 1 个 0 时,也就是 101,那么当左侧的 1可以移动时,右侧的 1 也可以移动,因此 101 继续保持一个 0 的间隔;当左侧的 1不能移动时,右侧的 1 可以移动,此时两者又相邻了,成为 11。
-
综上所述,这两个 1 移动时,其间隔不会超过 1 个 0,但是当左侧的 1 刚到达最终位置时,两者又不可能相邻,因此,两者必定间隔 1 个 0。
class Solution {
public:
int secondsToRemoveOccurrences(string s) {
int res = 0;
for(int i = 0, cnt = 0; i < s.size(); ++i) {
if(s[i] == '0') ++cnt;
else if(cnt > 0) res = max(res + 1, cnt);
}
return res;
}
};
6158. 字母移位 II
难度中等
给你一个小写英文字母组成的字符串 s
和一个二维整数数组 shifts
,其中 shifts[i] = [starti, endi, directioni]
。对于每个 i
,将 s
中从下标 starti
到下标 endi
(两者都包含)所有字符都进行移位运算,如果 directioni = 1
将字符向后移位,如果 directioni = 0
将字符向前移位。
将一个字符 向后 移位的意思是将这个字符用字母表中 下一个 字母替换(字母表视为环绕的,所以 'z'
变成 'a'
)。类似的,将一个字符 向前 移位的意思是将这个字符用字母表中 前一个 字母替换(字母表是环绕的,所以 'a'
变成 'z'
)。
请你返回对 s
进行所有移位操作以后得到的最终字符串。
示例 1:
输入:s = "abc", shifts = [[0,1,0],[1,2,1],[0,2,1]]
输出:"ace"
解释:首先,将下标从 0 到 1 的字母向前移位,得到 s = "zac" 。
然后,将下标从 1 到 2 的字母向后移位,得到 s = "zbd" 。
最后,将下标从 0 到 2 的字符向后移位,得到 s = "ace" 。
示例 2:
输入:s = "dztz", shifts = [[0,0,0],[1,1,1]]
输出:"catz"
解释:首先,将下标从 0 到 0 的字母向前移位,得到 s = "cztz" 。
最后,将下标从 1 到 1 的字符向后移位,得到 s = "catz" 。
提示:
1 <= s.length, shifts.length <= 5 * 104
shifts[i].length == 3
0 <= starti <= endi < s.length
0 <= directioni <= 1
s
只包含小写英文字母。
一维差分数组
这个题多次对区间进行加一和减一操作,很容易可以想到使用差分来做,需要注意的细节就是小写字母是循环的
class Solution {
public:
string shiftingLetters(string s, vector<vector<int>>& shifts) {
vector<int>deffer(s.size()+1,0);
vector<int>num(s.size(),0);
for(int i=0;i<shifts.size();i++)
{
int t=shifts[i][2]==1?1:-1;
deffer[shifts[i][0]]+=t;
deffer[shifts[i][1]+1]-=t;
}
num[0]=deffer[0];
for(int i=1;i<s.size();i++)
{
num[i]=num[i-1]+deffer[i];
}
for(int i=0;i<s.size();i++)
{
int x=((s[i]-'a')+num[i])%26;
if(x>=0)
s[i]=x+'a';
else
{
s[i]=x+'z'+1;
}
}
return s;
}
};
线段树
看题解的时候看到一位大佬用线段树写了出来,不过是java版本的,看代码思路还是很清晰的
class Solution {
public String shiftingLetters(String s, int[][] shifts) {
// 首先更新所有区间
// d = 1,则➕1;反之➖1
for (int[] shift : shifts) {
int start = shift[0], end = shift[1], d = shift[2];
update(root, 0, N, start, end, d == 1 ? 1 : -1);
}
char[] cur = s.toCharArray();
for (int i = 0; i < cur.length; i++) {
int c = cur[i] - 'a';
// 查询区间 [i, i] 最终修改值
int d = query(root, 0, N, i, i);
c = ((c + d) % 26 + 26) % 26;
cur[i] = (char) (c + 'a');
}
return new String(cur);
}
// *************** 下面是模版 ***************
class Node {
Node left, right;
int val, add;
}
private int N = (int) 1e9;
private Node root = new Node();
public void update(Node node, int start, int end, int l, int r, int val) {
if (l <= start && end <= r) {
node.val += (end - start + 1) * val;
node.add += val;
return ;
}
int mid = (start + end) >> 1;
pushDown(node, mid - start + 1, end - mid);
if (l <= mid) update(node.left, start, mid, l, r, val);
if (r > mid) update(node.right, mid + 1, end, l, r, val);
pushUp(node);
}
public int query(Node node, int start, int end, int l, int r) {
if (l <= start && end <= r) return node.val;
int mid = (start + end) >> 1, ans = 0;
pushDown(node, mid - start + 1, end - mid);
if (l <= mid) ans += query(node.left, start, mid, l, r);
if (r > mid) ans += query(node.right, mid + 1, end, l, r);
return ans;
}
private void pushUp(Node node) {
node.val = node.left.val + node.right.val;
}
private void pushDown(Node node, int leftNum, int rightNum) {
if (node.left == null) node.left = new Node();
if (node.right == null) node.right = new Node();
if (node.add == 0) return ;
node.left.val += node.add * leftNum;
node.right.val += node.add * rightNum;
// 对区间进行「加减」的更新操作,下推懒惰标记时需要累加起来,不能直接覆盖
node.left.add += node.add;
node.right.add += node.add;
node.add = 0;
}
}
第307场周赛
6152. 赢得比赛需要的最少训练时长
难度简单
你正在参加一场比赛,给你两个 正 整数 initialEnergy
和 initialExperience
分别表示你的初始精力和初始经验。
另给你两个下标从 0 开始的整数数组 energy
和 experience
,长度均为 n
。
你将会 依次 对上 n
个对手。第 i
个对手的精力和经验分别用 energy[i]
和 experience[i]
表示。当你对上对手时,需要在经验和精力上都 严格 超过对手才能击败他们,然后在可能的情况下继续对上下一个对手。
击败第 i
个对手会使你的经验 增加 experience[i]
,但会将你的精力 减少 energy[i]
。
在开始比赛前,你可以训练几个小时。每训练一个小时,你可以选择将增加经验增加 1 或者 将精力增加 1 。
返回击败全部 n
个对手需要训练的 最少 小时数目。
示例 1:
输入:initialEnergy = 5, initialExperience = 3, energy = [1,4,3,2], experience = [2,6,3,1]
输出:8
解释:在 6 小时训练后,你可以将精力提高到 11 ,并且再训练 2 个小时将经验提高到 5 。
按以下顺序与对手比赛:
- 你的精力与经验都超过第 0 个对手,所以获胜。
精力变为:11 - 1 = 10 ,经验变为:5 + 2 = 7 。
- 你的精力与经验都超过第 1 个对手,所以获胜。
精力变为:10 - 4 = 6 ,经验变为:7 + 6 = 13 。
- 你的精力与经验都超过第 2 个对手,所以获胜。
精力变为:6 - 3 = 3 ,经验变为:13 + 3 = 16 。
- 你的精力与经验都超过第 3 个对手,所以获胜。
精力变为:3 - 2 = 1 ,经验变为:16 + 1 = 17 。
在比赛前进行了 8 小时训练,所以返回 8 。
可以证明不存在更小的答案。
示例 2:
输入:initialEnergy = 2, initialExperience = 4, energy = [1], experience = [3]
输出:0
解释:你不需要额外的精力和经验就可以赢得比赛,所以返回 0 。
提示:
n == energy.length == experience.length
1 <= n <= 100
1 <= initialEnergy, initialExperience, energy[i], experience[i] <= 100
贪心
记 a 为当前精力,b 为当前经验,我们先从 a = initialEnergy 与 b = initialExperience 开始比赛。
- 若 a <= energy[i],那么我们一开始至少需要增加 energy[i] - a + 1 的精力,才能让现在的精力刚好超过对手 i。
- 若 b <= experience[i],那么我们一开始至少需要增加 experience[i] - b + 1 的经验,才能让现在的经验刚好超过对手 i。
因为精力和经验的增加量都取到了至少需要的值,因此我们能得到最优答案。
class Solution {
public:
int minNumberOfHours(int a, int b, vector<int>& energy, vector<int>& experience) {
int sum=0;
for(int i=0;i<energy.size();i++)
sum+=energy[i];
if(sum-a>=0)
{
ans=sum-a+1;// 精力上无法打败对手,因此最开始需要增加一些精力,使得精力恰好满足要求
}
else
ans=0;//不需要补充精力
for(int i=0;i<experience.size();i++)
{
if(b<=experience[i])
{
ans+=experience[i]-b+1;
b=experience[i]+1; // 经验上无法打败对手,因此最开始需要增加一些经验,使得经验恰好满足要求
}
b+=experience[i]; // 打败对手后数值变更
}
return ans;
}
};
6166. 最大回文数字
难度中等
给你一个仅由数字(0 - 9
)组成的字符串 num
。
请你找出能够使用 num
中数字形成的 最大回文 整数,并以字符串形式返回。该整数不含 前导零 。
注意:
- 你 无需 使用
num
中的所有数字,但你必须使用 至少 一个数字。 - 数字可以重新排序。
示例 1:
输入:num = "444947137"
输出:"7449447"
解释:
从 "444947137" 中选用数字 "4449477",可以形成回文整数 "7449447" 。
可以证明 "7449447" 是能够形成的最大回文整数。
示例 2:
输入:num = "00009"
输出:"9"
解释:
可以证明 "9" 能够形成的最大回文整数。
注意返回的整数不应含前导零。
提示:
1 <= num.length <= 105
num
由数字(0 - 9
)组成
贪心
一个回文串(如 998767899,123321)可以被分成两部分:
两边对应的部分(如 9987 和 7899,123 和 321),这两部分中的数字每种都出现偶数次。
中间单独一个数字(如 6),这部分是可选的。
因此令 cnt[i] 表示数字 i 出现的次数,我们先从 9 到 0 枚举第一部分中出现的数,再看是否还有剩下的数放进中间单独的数字即可。复杂度O(n)。
由于题目要求不能有前导零,所以代码细节部分需要注意
class Solution {
public:
string largestPalindromic(string num) {
string ans1,ans2; // ans1 表示对应的部分中的前一半,ans2 是 ans1 的倒序
int cnt[10]={0};
for(int i=0;i<num.size();i++)
cnt[num[i]-'0']++;//统计字符个数
for(int i=9;i>=0;i--)
{
if(i==0&&ans1.size()==0) // 已经枚举到了 0,但是之前从来没有加入过别的数字。此时加入 0 将会导致前导 0,因此直接结束。
break;
for(int j=0;j<cnt[i]/2;j++) // 在这部分中出现过的数必须出现偶数次
{
ans1+=(i+'0');
}
cnt[i]-=cnt[i]/2*2;
}
ans2=ans1;
reverse(ans2.begin(),ans2.end());
for(int i=9;i>=0;i--)
{
// 此时 0 无需跳过,因为单独一个 0 是合法的答案
if(cnt[i])
{
ans1+=i+'0';
break;
}// 看看是否还有剩下的数,可以作为中间单独的一个数字
}
return ans1+ans2;
}
};
6154. 感染二叉树需要的总时间
难度中等
给你一棵二叉树的根节点 root
,二叉树中节点的值 互不相同 。另给你一个整数 start
。在第 0
分钟,感染 将会从值为 start
的节点开始爆发。
每分钟,如果节点满足以下全部条件,就会被感染:
- 节点此前还没有感染。
- 节点与一个已感染节点相邻。
返回感染整棵树需要的分钟数*。*
示例 1:
输入:root = [1,5,3,null,4,10,6,9,2], start = 3
输出:4
解释:节点按以下过程被感染:
- 第 0 分钟:节点 3
- 第 1 分钟:节点 1、10、6
- 第 2 分钟:节点5
- 第 3 分钟:节点 4
- 第 4 分钟:节点 9 和 2
感染整棵树需要 4 分钟,所以返回 4 。
示例 2:
输入:root = [1], start = 1
输出:0
解释:第 0 分钟,树中唯一一个节点处于感染状态,返回 0 。
提示:
- 树中节点的数目在范围
[1, 105]
内 1 <= Node.val <= 105
- 每个节点的值 互不相同
- 树中必定存在值为
start
的节点
第一次做这种类型的题,没做出来,但是看题解的时候受益匪浅,为了保证能够深刻理解这题,打算等次日在把这题所有可以实现的方法全部写一遍,所以此处有些代码不是自己手写的
建图求深度
实际上就是给定一棵无根树,求以 start 为根时树的深度。只不过无根树是以二叉树的形式给出的,因此需要先从二叉树中建出无向图。最后求出深度即可,求深度可用bfs也可用dfs
dfs建图+dfs求深度
/**
* 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 {
int mx = 0;
vector<vector<int>> e;
void dfs1(TreeNode *node) {
if (node == nullptr) return;
mx = max(mx, node->val);
dfs1(node->left); dfs1(node->right);
}
void dfs2(TreeNode *node) {
if (node->left != nullptr) {
e[node->val].push_back(node->left->val);
e[node->left->val].push_back(node->val);
dfs2(node->left);
}
if (node->right != nullptr) {
e[node->val].push_back(node->right->val);
e[node->right->val].push_back(node->val);
dfs2(node->right);
}
}
int dfs3(int sn, int fa) {
int ret = 0;
for (int fn : e[sn]) if (fn != fa) ret = max(ret, dfs3(fn, sn) + 1);
return ret;
}
public:
int amountOfTime(TreeNode* root, int start) {
dfs1(root);
e.resize(mx + 1);
dfs2(root);
return dfs3(start, -1);
}
};
dfs建图+bfs求深度
/**
* 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 {
map<int,vector<int>> mp;
int vis[100001];
public:
void dfs(TreeNode *root){
if(root->left){
mp[root->val].push_back(root->left->val);
mp[root->left->val].push_back(root->val);
dfs(root->left);
}
if(root->right){
mp[root->val].push_back(root->right->val);
mp[root->right->val].push_back(root->val);
dfs(root->right);
}
}
int amountOfTime(TreeNode* root, int start) {
int time=-1;
dfs(root);
if(mp.size()==0) return 0;
queue<int> q;
q.push(start);
while(!q.empty()){
int n=q.size();
while(n--){
int fr=q.front();
vis[fr]=1;
q.pop();
for(auto v:mp[fr]){
if(!vis[v]) {
q.push(v);
}
}
}
time++;
}
return time;
}
};
建立带父母信息的二叉树
让每个结点关联起他的父结点,类似于线索树
这样广度搜索,每次把他的孩子结点和父结点都感染,一轮时间+1
思路虽然不一样但是代码实质和建立无向图差不多
Java版本:
class Solution {
public int amountOfTime(TreeNode root, int start) {
//关联父节点 <当前结点,当前结点父节点>
Map<TreeNode,TreeNode> map = new HashMap<>();
//关联是否被感染 <当前结点,是否感染>
Map<TreeNode,Boolean> flag = new HashMap<>();
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
map.put(root,null); //根结点无父节点
//指向感染结点
TreeNode x = null;
while(!queue.isEmpty()){
int size = queue.size();
//层序遍历,确定好每个结点的 父结点 及 是否被感染信息
while(size!=0){
TreeNode t = queue.poll();
size--;
//找到感染结点
if(t.val == start){
x = t;
flag.put(t,true);
}
else
flag.put(t,false);
if(t.left!=null){
queue.add(t.left);
map.put(t.left,t);
}
if(t.right!=null){
queue.add(t.right);
map.put(t.right,t);
}
}
}
//感染结点为首,入队
queue.add(x);
int minutes = 0;
while(!queue.isEmpty()){
int size = queue.size();
while(size!=0){
TreeNode t = queue.poll();
size--;
if(t.left!=null && flag.get(t.left)==false){
queue.add(t.left);
flag.put(t.left,true);
}
if(t.right!=null && flag.get(t.right)==false){
queue.add(t.right);
flag.put(t.right,true);
}
//就层序遍历多扫一个父亲结点
if(map.get(t)!=null && flag.get(map.get(t))==false){
//父节点入队
queue.add(map.get(t));
flag.put(map.get(t),true);
}
}
//每轮结束 minutes++
minutes++;
}
return minutes-1;
}
}
一次dfs传递感染时间
一个节点被感染,有四个可能,从上一个节点被感染,本身被感染,左子树传染的感染,右子树传染的感染
可以在dfs里面传递一个参数sum,如果是-1代表之前没有被感染,不是-1则代表感染的时间
并把sum+1作为返回值(没感染返回-1),代表被本节点感染的时间
然后如果没有感染就判断一下,本节点是否是感染节点,是就设置sum为0
如果感染了,就把sum+1作为参数传递到左右子树中
如果还未感染,则感染会从左子树或右子树来,选择被感染的子树的返回值,作为本节点感染的时间,并传递到另一个子树当中
最后,最大的sum值即为返回的结果
class Solution {
public:
int max=0;
int dfs(TreeNode* root, int start,int sum){
if(root==NULL)return -1;
if(sum==-1&&root->val==start){//本节点为感染节点
sum=0;
}
if(sum!=-1){//本节点已感染,传递到子树中
dfs(root->left,start,sum+1);
dfs(root->right,start,sum+1);
if(sum>max)max=sum;
return sum+1;
}else{
int tem=dfs(root->left,start,sum);
if(tem!=-1){//左子树被感染,传递到右子树
sum=tem;
dfs(root->right,start,sum+1);
}else{//右子树被感染,传递到左子树
sum=dfs(root->right,start,sum);
dfs(root->left,start,sum+1);
}
}
if(sum>max)max=sum;
if(sum!=-1)return sum+1;
return -1;
}
int amountOfTime(TreeNode* root, int start) {
dfs(root,start,-1);
return max;
}
};
不建图直接求深度
这道题目问题可以转换为,以start结点为起点的最长路径
那么,如何求解呢?
首先,我们将其分为两部分
1.以start结点向下的路径
2.以start结点向上的路径
- 比较容易求解,我们可以吧start结点看作root结点,然后求其树的高度,即为向下路径中最长的那一条
- 如何求解?重点来了:
这里我们需要对二叉树的数据结构,后序遍历,dfs调用过程(即压栈弹栈过程)有一个非常透彻的理解,才能理解该算法的巧妙之处
既然start结点为起点,那么可以理解为向上弹栈过程中,每弹一层栈,距离+1,注意,这一规则仅适用于,所有压栈的结点,(这句话换个意思就是说,从root结点我们是如何通过进行dfs压栈来得到start结点,那么我们对其所有被压结点进行弹栈过程中距离+1),而我们需要求以start结点为起点的最长路径
所有弹栈结点,即为中间结点mid,假设其到start结点距离为d,而另一子树高度为h,那么以start结点为起点,并且经过中间结点mid的最长距离为d + h
同时,我们维护最长路径变量,不断更新
那么,我们前面提到了要对二叉树的数据结构,后序遍历,dfs调用过程(即压栈弹栈过程)有一个非常透彻的理解
后序遍历如何体现?
这里使用后序遍历的原因是,我们在对mid结点处理时,需要首先得到左右子树的返回值,距离d或者高度h,所以使用后序遍历,即先访问左右子树,最后访问根节点
class Solution {
public:
int dfs(TreeNode *root, const int start, bool &flag) {
if (root == nullptr) {
return -1;//自底向上计算高度
}
bool lflag = false, rflag =false;//通过bool变量来确定压栈弹栈路径
int l = dfs(root->left, start, lflag) + 1;
int r = dfs(root->right, start, rflag) + 1;
if (lflag || rflag) {//当前结点为mid结点
res = max(res, l + r);//更新最长路径
flag = true;//向上传递弹栈路径
if (lflag) {//确定start结点到当前结点距离
return l;
}
else {
return r;
}
}
if (root->val == start) {
res = max(l, r);//计算所有向下路径中最大值,即部分1
flag = true;
return 0;//弹栈过程重新计算距离,start为起点所以距离为0
}
return max(l, r);//正常计算树的高度,贪心选择最长路径
}
int res = 0;
int amountOfTime(TreeNode* root, int start) {
bool flag = false;
int level = dfs(root, start, flag);
return res;
}
};