1.如果让你在二叉树的「树枝」上做文章,那么用遍历的思维模式解题是比较自然的想法 可以是求和问题也可以是路径问题,路径问题可以理解为回溯两次,在叶子结点那里的回溯,是把记录的一个叶子节点删除
2.如果让你在二叉树中的某些节点上做文章,一般来说也可以直接用遍历的思维模式。 某些节点符合一些特质,找到这些符合特质的节点,用递归遍历的思想来写
404. 左叶子之和 左叶子就是某些结点
class Solution:
def __init__(self):
self.sum = 0
# 记录左叶子之和
# int sum = 0; # This is handled in the constructor now
# 二叉树遍历函数
def traverse(self, root):
if root is None:
return
if root.left is not None and root.left.left is None and root.left.right is None:
# 找到左侧的叶子节点,记录累加值
self.sum += root.left.val
# 递归框架
self.traverse(root.left)
self.traverse(root.right)
def sumOfLeftLeaves(self, root: TreeNode) -> int:
self.traverse(root)
return self.sum
在这道题目中,我们需要计算二叉树中所有左叶子节点的和。因为我们只是需要遍历整棵树,并累加所有左叶子节点的值,而不需要修改或恢复树的状态,所以不需要回溯。以下是详细解释:
回溯法
回溯是一种常用于解决组合问题的算法技术。回溯会尝试所有可能的解决方案,找到所有可行解。在回溯过程中,我们需要记住当前的状态,并在离开当前状态时恢复到先前的状态。这种技术常用于路径问题或需要恢复先前状态的问题。
为什么这题不需要回溯
在这道题目中,我们的目标是遍历整棵树并累加所有左叶子节点的值。为了实现这一点,我们可以使用递归遍历树的每个节点。当我们找到一个左叶子节点时,将其值累加到 self.sum
中。 求和问题不需要回溯12
如果你对二叉树足够熟悉,可以想到很多方式通过递归函数得到层序遍历结果
class Solution:
res = []
def levelTraverse(self, root):
if root is None:
return self.res
# root 视为第 0 层
self.traverse(root, 0)
return self.res
def traverse(self, root, depth):
if root is None:
return
# 前序位置,看看是否已经存储 depth 层的节点了
if len(self.res) <= depth:
# 第一次进入 depth 层
self.res.append([])
# 前序位置,在 depth 层添加 root 节点的值
self.res[depth].append(root.val)
self.traverse(root.left, depth + 1)
self.traverse(root.right, depth + 1)
这段代码通过 DFS 模仿层序遍历,将二叉树每层的节点值收集到一个列表中。 还是dfs,不过获得了层序遍历的结果。
写dfs用遍历的方法思考时候,想想dfs需要接受的输入有哪些,要记录父节点,可以把父节点也加进去输入。
class Solution:
def __init(self):
self.depth_x = 0
self.depth_y = 0
self.parent_x = None
self.parent_y = None
self.x = 0
self.y = 0
def traverse(self, root, depth, parent):#由于要记录的数据有depth,所以depth也作为一个要记录的参数写进来
if root is None:
return
if self.x == root.val:
self.depth_x = depth
self.parent_x = parent
if self.y == root.val:
self.depth_y = depth
self.parent_y = parent
self.traverse(root.left, depth + 1, root)
self.traverse(root.right, depth + 1, root)
def isCousins(self, root: Optional[TreeNode], x: int, y: int) -> bool:
self.x = x
self.y = y
self.traverse(root, 0, None)
if self.depth_x == self.depth_y and self.parent_x != self.parent_y:
return True
return False
python命名风格命名规则在编程中非常重要,因为它影响代码的可读性和可维护性。Python 社区推荐使用 PEP 8 风格指南,它建议使用蛇形命名法(snake_case),即所有字母小写,单词之间用下划线分隔。
命名规则说明
- snake_case(蛇形命名法):
- 用于变量名和函数名。
- 例如:
depth_x
,depth_y
,calculate_depth
.
- CamelCase(驼峰命名法):
- 用于类名。
- 例如:
TreeNode
,Solution
.(而java的第一个名字不大写,看着不太顺眼)
在练习leetcode时候每一遍自己都把命名改过来,统一代码风格。
遍历一遍二叉树,对于节点值为偶数的节点,累加它的孙子节点的值即可。 从头往下找容易
class Solution:
def __init__(self):
self.sum = 0
def sumEvenGrandparent(self, root: TreeNode) -> int:
self.traverse(root)
return self.sum
def traverse(self, root):
if root is None:
return
if root.val % 2 == 0:
if root.left is not None:
if root.left.left is not None:
self.sum += root.left.left.val
if root.left.right is not None:
self.sum += root.left.right.val
if root.right is not None:
if root.right.left is not None:
self.sum += root.right.left.val
if root.right.right is not None:
self.sum += root.right.right.val
self.traverse(root.left)
self.traverse(root.right)
#求和就可以,没有回溯这一步,
1448.统计二叉树中好节点的数目
想一想在遍历的过程中好节点应该满足的属性 就是好节点的val >= path_max , path_max参数用来更新当前路径的最大值,并且之后更新path_max
class Solution:
def __init__(self):
self.count = 0
def traverse(self, root, path_max):
if root is None:
return
if root.val >= path_max:
self.count += 1
path_max = max(root.val, path_max)
self.traverse(root.left, path_max)
self.traverse(root.right, path_max)
def goodNodes(self, root: TreeNode) -> int:
self.traverse(root, root.val)
return self.count