2246. 相邻字符不同的最长路径
大约 4 分钟
2246. 相邻字符不同的最长路径
- 标签:树、深度优先搜索、图、拓扑排序、数组、字符串
- 难度:困难
题目链接
题目大意
描述:给定一个长度为 的数组 来表示一棵树(即一个连通、无向、无环图)。该树的节点编号为 ,共 个节点,其中根节点的编号为 。其中 表示节点 的父节点,由于节点 是根节点,所以 。再给定一个长度为 的字符串,其中 表示分配给节点 的字符。
要求:找出路径上任意一对相邻节点都没有分配到相同字符的最长路径,并返回该路径的长度。
说明:
- 。
- 。
- 对所有 , 均成立。
- 。
- 表示一棵有效的树。
- 仅由小写英文字母组成。
示例:
- 示例 1:
输入:parent = [-1,0,0,1,1,2], s = "abacbe"
输出:3
解释:任意一对相邻节点字符都不同的最长路径是:0 -> 1 -> 3 。该路径的长度是 3 ,所以返回 3。
可以证明不存在满足上述条件且比 3 更长的路径。
- 示例 2:
输入:parent = [-1,0,0,0], s = "aabc"
输出:3
解释:任意一对相邻节点字符都不同的最长路径是:2 -> 0 -> 3 。该路径的长度为 3 ,所以返回 3。
解题思路
思路 1:树形 DP + 深度优先搜索
因为题目给定的是表示父子节点的 数组,为了方便递归遍历相邻节点,我们可以根据 数组,建立一个由父节点指向子节点的有向图 。
如果不考虑相邻节点是否为相同字符这一条件,那么这道题就是在求树的直径(树的最长路径长度)中的节点个数。
对于根节点为 的树来说:
- 如果其最长路径经过根节点 ,则 最长路径长度 = 某子树中的最长路径长度 + 另一子树中的最长路径长度 + 1。
- 如果其最长路径不经过根节点 ,则 最长路径长度 = 某个子树中的最长路径长度。
即:最长路径长度 = max(某子树中的最长路径长度 + 另一子树中的最长路径长度 + 1,某个子树中的最长路径长度)。
对此,我们可以使用深度优先搜索递归遍历 的所有相邻节点 ,并在递归遍历的同时,维护一个全局最大路径和变量 ,以及当前节点 的最大路径长度变量 。
- 先计算出从相邻节点 出发的最长路径长度 。
- 更新维护全局最长路径长度为 。
- 更新维护当前节点 的最长路径长度为 。
因为题目限定了「相邻节点字符不同」,所以在更新全局最长路径长度和当前节点 的最长路径长度时,我们需要判断一下节点 与相邻节点 的字符是否相同,只有在字符不同的条件下,才能够更新维护。
最后,因为题目要求的是树的直径(树的最长路径长度)中的节点个数,而:路径的节点 = 路径长度 + 1,所以最后我们返回 作为答案。
思路 1:代码
class Solution:
def longestPath(self, parent: List[int], s: str) -> int:
size = len(parent)
# 根据 parent 数组,建立有向图
graph = [[] for _ in range(size)]
for i in range(1, size):
graph[parent[i]].append(i)
ans = 0
def dfs(u):
nonlocal ans
u_len = 0 # u 节点的最大路径长度
for v in graph[u]: # 遍历 u 节点的相邻节点
v_len = dfs(v) # 相邻节点的最大路径长度
if s[u] != s[v]: # 相邻节点字符不同
ans = max(ans, u_len + v_len + 1) # 维护最大路径长度
u_len = max(u_len, v_len + 1) # 更新 u 节点的最大路径长度
return u_len # 返回 u 节点的最大路径长度
dfs(0)
return ans + 1
思路 1:复杂度分析
- 时间复杂度:,其中 是树的节点数目。
- 空间复杂度:。