2025/8/5
题目(easy):
我的思路:
这题的直径很显然一定会经过某个节点作为“转折节点",然后通过这个转折节点的左右最大子树的深度相加就可以得到我们需要的最大直径。但是现在有个问题就是,我怎么知道哪一个节点是转折节点呢?很显然是以它为转折节点计算出来直径最大的节点,但是这就循环论证了。所以我们没有办法很快地知道哪一个是转折节点,所以我感觉可能只能先遍历每一个节点,然后计算以这个节点的转折节点的时候的直径值是否最大。
①广度优先搜索以层次遍历每个节点
②对每个节点用之前递归搜索深度的方式计算它的左右子树深度值
③左右子树深度值相加就可以得到当前节点为转折节点的直径值,然后把它和目前的最大值比较即可
具体代码如下:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
import queue
class Solution:
def diameterOfBinaryTree(self, root: Optional[TreeNode]) -> int:
#层次遍历每个节点 + 深度递归计算当前节点左右子树深度值
if not root.left and not root.right:
return 0
maxD = 0
q = queue.Queue()
q.put(root)
while not q.empty():
turnNode = q.get()
#1.找到直径所在的转折节点
# turnNode = self.FindTurnNode(root)
#2.计算转折节点的左右子树的单边最大路径长度
leftPath = self.GetMaxEdgePath(turnNode.left)
rightPath = self.GetMaxEdgePath(turnNode.right)
newD = leftPath + rightPath
maxD = max(maxD, newD)
if turnNode.left:
q.put(turnNode.left)
if turnNode.right:
q.put(turnNode.right)
#3.进行加和计算
return maxD
def FindTurnNode(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
#或者目前可以把所有节点都当转折点算一遍?
return root
def GetMaxEdgePath(self, root: Optional[TreeNode]) -> int:
#那这个基本就是求深度了
if not root:
return 0
return 1 + max(self.GetMaxEdgePath(root.left), self.GetMaxEdgePath(root.right))
时间复杂度:O(N的平方)
空间复杂度:O(N)
优化思路:
你也是神人了,明明用深度优先搜索遍历到每个节点的时候,是可以同时计算它的左右子树的深度值和当前该节点作为转折点的直径值的。你上面偏偏要先用层次遍历来访问每一个节点,再对这个节点进行递归计算左右子树深度,这就导致了时间复杂的的升高。所以要降下来的话,你可以直接用深度优先搜索(递归)去遍历每个节点的同时计算它的直径值。即:
①设一个当前方法中的全局变量maxD
②设一个当前方法中的深度优先搜索函数去访问每一个节点
③对每个节点去计算它的左右子树的深度值(也是通过这个函数去递归进行计算,规定空节点深度值为-1,叶子节点深度值为0)
④计算当前节点的直径值:左右子树深度值+2(+2是因为左右子树的根节点两条线分别连接上当前节点),然后和目前maxD进行比较
⑤返回当前节点的深度值:左右子树深度值中最大值+1
具体代码如下:
class Solution:
def diameterOfBinaryTree(self, root: Optional[TreeNode]) -> int:
#用深度优先搜索遍历每一个节点
#对遍历到的每一个节点,同时计算该处节点的深度与直径
#1.定义最大直径为该类的全局变量
self.maxD = 0
#2.定义深度优先搜索函数
def dfs(root: Optional[TreeNode]) -> int:
if not root:
return -1 #空节点的深度值为-1
#计算该处节点的左右深度值
left_depth = dfs(root.left)
right_depth = dfs(root.right)
#计算该处节点的最大直径值
self.maxD = max(self.maxD, left_depth + right_depth + 2)
return max(left_depth, right_depth) + 1
#调用并计算
dfs(root)
return self.maxD
时间复杂度:O(N)
空间复杂度:O(Height)【当前树的高度】
总结:
①对于树的问题,主要要注意的是对节点的遍历处理操作,主要分为深度优先搜索和广度优先搜索两部分。如果是要求的和树的深度有关的深度优先搜索会更好,如果要求的是类似当前节点对其左右孩子的影响之类的用广度优先搜索会更好(之前做的翻转二叉树那种)
②对每个节点能够一次处理完的事情,不要分两次来做