1104、二叉树寻路
在一棵无限的二叉树上,每个节点都有两个子节点,树中的节点 逐行 依次按 “之” 字形进行标记。
如下图所示,在奇数行(即,第一行、第三行、第五行……)中,按从左到右的顺序进行标记;
而偶数行(即,第二行、第四行、第六行……)中,按从右到左的顺序进行标记。
给你树上某一个节点的标号 label
,请你返回从根节点到该标号为 label
节点的路径,该路径是由途经的节点标号所组成的。
示例1:
输入:label = 14
输出:[1,3,4,14]
示例2:
输入:label = 26
输出:[1,2,6,10,26]
思路:
递归求上一层的结点值,
- 对于偶数层来说,由于是逆序,所以该节点原本的值应该是 最小值 + (最大值 - 当前值),也就是计算当前值和最大值得距离,然后累加到最小值上,那么上一层的值在这个基础上除以2即可
- 对于奇数层来说,该层的顺序是顺序的,也就是这个值没有问题,那么上层原本的值应该是该值除以2,但是上层肯定是逆序的,所以上层的值应该是上层最小值 + (上层最大值 - 上层本应该的值)
class Solution:
# 获取当前label所在层数
def getDep(self, label):
dep = 0
while label:
label = label // 2
dep += 1
return dep
def pathInZigZagTree(self, label: int) -> List[int]:
self.ans = []
def dfs(label):
self.ans.insert(0, label)
dep = self.getDep(label)
if dep <= 1: return
# 分别针对奇数列和偶数列求上层的值进行递归
if dep % 2 == 0:
maxLabel = (1 << dep) - 1
minLabel = 1 << (dep - 1)
preLabel = (minLabel + maxLabel - label) // 2
else:
preLabel = label // 2
dep -= 1
maxLabel = (1 << dep) - 1
minLabel = 1 << (dep - 1)
preLabel = minLabel + maxLabel - preLabel
dfs(preLabel)
dfs(label)
return self.ans
1372、二叉树中的最长交错路径
给你一棵以 root 为根的二叉树,二叉树中的交错路径定义如下:
- 选择二叉树中 任意 节点和一个方向(左或者右)。
- 如果前进方向为右,那么移动到当前节点的的右子节点,否则移动到它的左子节点。
- 改变前进方向:左变右或者右变左。
- 重复第二步和第三步,直到你在树中无法继续移动。
交错路径的长度定义为:访问过的节点数目 - 1(单个节点的路径长度为 0 )。
请你返回给定树中最长 交错路径 的长度。
示例1:
输入:root = [1,null,1,1,1,null,null,1,1,null,1,null,null,null,1,null,1]
输出:3
示例2:
输入:root = [1,1,1,null,1,null,null,1,1,null,1]
输出:4
示例3:
输入:root = [1]
输出:0
思路:
第一想到的是递归,根据上一步的前进方向确定下一步的前进方向
class Solution:
def longestZigZag(self, root: TreeNode) -> int:
# 用于存放最大交错长度
self.maxLen = 0
def dfs(root, isLeft=True, length=0):
if not root: return
self.maxLen = max(self.maxLen, length)
# 如果上一步是向左,那么这一步应该向右,所以应该是左节点向右移动,然后length + 1
# 这里还需要从右节点重新开始规划路径
# 同理如果上一步是向右,这一步应该向左,并且向右重新规划路径
if isLeft:
dfs(root.left, False, length + 1)
dfs(root.right, True, 0)
else:
dfs(root.right, True, length + 1)
dfs(root.left, False, 0)
# 从父节点的左右子节点出发,分别计算交错长度
dfs(root) and dfs(root, False)
return self.maxLen
使用BFS来遍历树,这个时候由于用bool值只能表示一个方向,否则其中一个方向数据会丢失,这里使用父节点和子节点的关系来表示方向。同时不停的更新节点向左走和向右走的交错长度。
class Solution:
def longestZigZag(self, root: TreeNode) -> int:
# 队列中存放父节点和当前结点,用来表示上一步的前进方向
queue = [(None, root)]
# l存放的是向左走到该节点的交错长度,r是向右走到该节点的交错长度
l = collections.defaultdict(int)
r = collections.defaultdict(int)
while queue:
parent, node = queue.pop(0)
if parent:
# 分别记录该节点向左走和向右走的交错长度,如果这一步是向左走,那么上一步应该是向右走,所以取r里的值
if parent.left == node:
l[node] = r[parent] + 1
else:
r[node] = l[parent] + 1
if node.left:
queue.append((node, node.left))
if node.right:
queue.append((node, node.right))
# 计算最长的交错路径,这里加上0,避免整个数组长度为0,导致报错
return max([0] + [v for v in l.values()] + [v for v in r.values()])
1457、二叉树中的伪回文路径
给你一棵二叉树,每个节点的值为 1 到 9 。我们称二叉树中的一条路径是 「伪回文」的,当它满足:路径经过的所有节点值的排列中,存在一个回文序列。
请你返回从根到叶子节点的所有路径中 伪回文 路径的数目。
示例1:
输入:root = [2,3,1,3,1,null,1]
输出:2
示例2:
输入:root = [2,1,1,1,3,null,null,null,null,null,1]
输出:1
示例3:
输入:root = [9]
输出:1
思路:
有回文路径,说明该路径中节点值为奇数的至多只能有一个,所以当遇到叶子结点时,统计该路径中奇数值的个数即可。
class Solution:
def __init__(self):
self.cache = collections.defaultdict(int)
self.pathCount = 0
def check(self):
count = 0
print(self.cache)
for key, value in self.cache.items():
if value % 2:
count += 1
self.pathCount += count <= 1
def pseudoPalindromicPaths (self, root: TreeNode) -> int:
def dfs(root):
if not root: return 0
# 统计节点出现的次数
self.cache[root.val] += 1
# 叶子结点进行奇数节点统计
if not root.left and not root.right:
self.check()
dfs(root.left)
dfs(root.right)
# 路径遍历完之后,将该节点统计值删除
self.cache[root.val] -= 1
dfs(root)
return self.pathCount