文章目录
543. 二叉树的直径
题目描述
给你一棵二叉树的根节点,返回该树的 直径 。
二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 。
两节点之间路径的 长度 由它们之间边数表示。
- 示例1:
输入:root = [1,2,3,4,5]
输出:3
解释:3 ,取路径 [4,2,1,3] 或 [5,2,1,3] 的长度。
- 示例2:
输入:root = [1,2]
输出:1
思路分析
本题让我们查找二叉树的最大直径,所谓的二叉树最大直径不就是左子树的深度+右子树的深度嘛,所以我们就把这道题转化成了寻找二叉树最大深度的问题
那么为了找到二叉树的最大深度,我们需要递归遍历整个二叉树,那么说到递归,我们就需要关注递归的结束条件,通过分析,我们不难发现,为了找到二叉树的最大深度,我们需要分别遍历二叉树的左子树和右子树,然后去比较左右子树的深度,深度较大的就是该二叉树的最大深度,所以递归的结束条件一定是根节点为nullptr时结束
接下来我们就来关注一下这个递归函数的返回值,我们发现我们最后的返回值一定是左右子树中深度的较大值,所以我们需要选取左右子树深度的较大值,除此之外,我们不能遗忘根节点,所以我们需要对最大深度+1
但是我们看到题目要求,题目并不是让我们找到二叉树的最大深度,题目要求我们找到二叉树的最大直径,而二叉树的直径就等于左子树的深度+右子树的深度,所以我们在递归遍历二叉树的同时可以不断更新二叉树的直径,为了让外部能够直接返回这个直径的大小,我们将直径申明为全局的,然后的到左子树和右子树的深度后,我们把左子树和右子树深度的和与当前的最大直径做对比,如果和要更大,我们就更新最大的直径
由此我们就可以编写代码
代码编写
cpp
class Solution {
public:
int diameter=0;
int depth(TreeNode*root)
{
if(root==nullptr){return 0;}
int leftDepth=depth(root->left);
int rightDepth=depth(root->right);
diameter=max(diameter,leftDepth+rightDepth);
return max(leftDepth,rightDepth)+1;
}
int diameterOfBinaryTree(TreeNode* root) {
depth(root);
return diameter;
}
};
621.任务调度器
题目描述
给你一个用字符数组 tasks 表示的 CPU 需要执行的任务列表,用字母 A 到 Z 表示,以及一个冷却时间 n。每个周期或时间间隔允许完成一项任务。任务可以按任何顺序完成,但有一个限制:两个 相同种类 的任务之间必须有长度为 n 的冷却时间。
返回完成所有任务所需要的 最短时间间隔 。
- 示例1:
输入:tasks = ["A","A","A","B","B","B"], n = 2
输出:8
解释:
在完成任务 A 之后,你必须等待两个间隔。对任务 B 来说也是一样。在第 3 个间隔,A 和 B 都不能完成,所以你需要待命。在第 4 个间隔,由于已经经过了 2 个间隔,你可以再次执行 A 任务。
- 示例2:
输入:tasks = ["A","C","A","B","D","B"], n = 1
输出:6
解释:一种可能的序列是:A -> B -> C -> D -> A -> B。
由于冷却间隔为 1,你可以在完成另一个任务后重复执行这个任务。
- 示例3:
输入:tasks = ["A","A","A","B","B","B"], n = 3
输出:10
解释:一种可能的序列为:A -> B -> idle -> idle -> A -> B -> idle -> idle -> A -> B。
只有两种任务类型,A 和 B,需要被 3 个间隔分割。这导致重复执行这些任务的间隔当中有两次待命状态。
思路分析
刚读完题目要求后,我们肯定会面对着一头雾水,但是我们通过分析下面的示例后,我们可以找到其中的一些规律:
- 两个相同的任务之间必须间隔n个不同的任务
- 返回的最小时间间隔是指能够指行完所有任务后所需要的时间,这个时间一定大于等于任务的个数
所以根据上面的两条要求,我们首先需要找到出现次数最多的元素,然后将出现次数最多的元素依次排列,中间间隔n个位置;然后我们只需要在不破坏第一条规律的前提下,依次将剩下的元素插进这些空余的位置里面即可
假设A元素出现的次数最多,我们记为maxsize,A元素所在的每一个位置将整个数组分割成了maxsize块,我们只需要计算出每一块的长度,然后相加即可,我们来看前maxsize-1块,我们发现每一块空间长度都是n+1,那么前maxsize-1块的时间就是(n+1)*(maxsize-1);然后我们发现最后一块空间的长度与出现次数为maxsize的元素个数有关,如果出现次数为maxsize的元素个数为num个,那么最后一块空间的长度就是num,那么最终计算所得的最小的时间间隔等于(maxsize-1)(n+1)+num
由此我们编写代码的逻辑就变成了:
- 寻找元素最多出现的次数maxsize
- 寻找出现次数为maxsize的元素个数
- 按照公式计算最短时间间隔
- 最后与最初的数组长度作比较,取较大的那一个作为返回值
代码编写
cpp
class Solution {
public:
int leastInterval(vector<char>& tasks, int n) {
vector<int> hash(26,0);
for(char ch:tasks){hash[ch-'A']++;}
int maxSize=0;
for(int i=0;i<hash.size();++i)
{
if(hash[i]>maxSize){maxSize=hash[i];}
}
int num=0;
for(int i=0;i<hash.size();++i)
{
if(maxSize==hash[i]){++num;}
}
int partSize=maxSize-1;
int partLength=n+1;
int minTime=partSize*partLength+num;
return max((int)tasks.size(),minTime);
}
};
739.每日温度
题目描述
给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用 0 来代替。
- 示例1:
输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]
- 示例2:
输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]
- 示例3:
输入: temperatures = [30,60,90]
输出: [1,1,0]
思路分析
题目要求我们返回一个数组answer[i] 是指对于第 i 天,下一个更高温度出现在几天后,那么我们此时来思考一下,假设我们当前的元素下标为i,下一个更高的温度所在的下标为j,那么answer[i]位置的值就保存j-i,所以所谓的更高的温度出现在几天之后,本质就是两个一大一小的值所在的下标相减的结果,所以我们需要不断对比第i个位置的元素与第j个位置元素的大小,如果第j个位置的元素大于第i个位置的元素,那么就更新answer[i]所对应的值
根据上面的分析,为了得到第i个位置和第j个位置的值,我们一定是需要遍历整个temperatures数组的;同时我们还要对下标进行计算,所以我们还需要保存每个位置的下标;最后我们还需要对比i位置和j位置的值,来决定要不要更新answer[i],那么此时我们就面临一个巨大的问题,我们该如何在满足下标运算的前提下对下标所对应的值做比较呢?
此时我们就可以借助栈这个数据结构先进先出的特点,我们始终保持栈内存放元素的下标,栈顶元素为temperatures数组中较小的值所对应的下标,然后后续对每一个位置的下标所对应的值与栈顶元素所对应的值做比较,如果当前位置的值大于栈顶元素,我们就出栈,然后更新栈顶元素下标所对应的answer数组的值,其值就等于i减去栈顶元素
代码编写
cpp
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
stack<int> st;
vector<int> result(temperatures.size(),0);
for(int i=0;i<temperatures.size();++i)
{
while(!st.empty()&&temperatures[st.top()]<temperatures[i])
{
int index=st.top();
st.pop();
result[index]=i-index;
}
st.push(i);
}
return result;
}
};