在LeetCode的示例中,通常会看到以下命名约定:
- 类名:使用大驼峰命名法(PascalCase)。
- 方法名和变量名:使用小驼峰命名法(camelCase)。
本篇所有题目先用分解问题思路解决,再用遍历思路解决
112. 路径总和
**方法一,分解问题的思路. 分解成左子树是否能满足target - root.val 或者右子树是否能满足target - root.val 再详细考虑base case **
class Solution:
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
if root is None:
return False
if (root.left is None and root.right is None) and root.val == targetSum:
return True
return self.hasPathSum(root.left, targetSum - root.val) or self.hasPathSum(root.right, targetSum - root.val)
在递归函数中,基线条件(base case)是用于停止递归的条件,这里有两个base case
if root is None: return False
:
- 这是基线条件之一。当树为空时,没有路径可以满足条件,返回
False
。
if (root.left is None and root.right is None) and root.val == targetSum: return True
:
- 这是基线条件之二。当节点是叶子节点且其值等于目标和时,说明找到了一条满足条件的路径,返回
True
。
**方法二,遍历的思路,遍历是没有返回值的,想清楚每个节点进行的操作,遍历不返回值,但是改变某个记录状态的值 ** 递归的执行分为两个主要阶段:
- 递归下降(递归调用阶段):从根节点开始向下遍历树的每个分支。
- 递归上升(回溯阶段):在到达叶子节点或基线条件后,逐层返回上一层调用。
class Solution:
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
if root is None:
return False
self.target = targetSum
self.curSum = 0
self.found = False
self.traverse(root)
return self.found
def traverse(self, root) -> None:
if root is None:
return
self.curSum += root.val
if root.left is None and root.right is None:
if self.curSum == self.target:
self.found = True
self.traverse(root.left)
self.traverse(root.right)
self.curSum -= root.val
class Solution:
def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]:
#分解问题思路很清晰,
if root1 is None:
return root2
if root2 is None:
return root1
root1.val += root2.val
root1.left = self.mergeTrees(root1.left, root2.left)
root1.right = self.mergeTrees(root1.right, root2.right)
return root1 #把root1作为根基
递归遍历的思路
class Solution:
def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]:
if root1 is None:
return root2
self.traverse(root1, root2)
return root1
def traverse(self, root1, root2) -> None:
if root1 is None or root2 is None:
return
if root1 is not None and root2 is not None:
root1.val += root2.val
if root1.left is None and root2.left is not None:
root1.left = root2.left
root2.left = None
if root1.right is None and root2.right is not None:
root1.right = root2.right
root2.right = None #遍历时候想清楚每个结点要干什么,针对这个具体的结点
self.traverse(root1.left, root2.left)
self.traverse(root1.right, root2.right)
解决问题的思路,关键在于明白递归函数的定义,之后利用这个定义走下去
938. 二叉搜索树的范围和
遍历的思路就是单纯用 traverse
函数遍历一遍 BST,找到落在区间的元素。分解问题的思路关键是要明确函数定义,然后利用这个定义。
class Solution:
def __init__(self):
self.sum = 0
def rangeSumBST(self, root: Optional[TreeNode], low: int, high: int) -> int:
self.traverse(root, low, high)
return self.sum
def traverse(self, root, low, high) -> None: #(主函数那里有的low,high,在定义别的函数时候可以直接使用)
if root is None:
return
if low <= root.val <= high:
self.sum += root.val
self.traverse(root.left,low,high)
self.traverse(root.right,low, high)
#自己写的,未使用到二叉搜索树的性质,也能通过,时间复杂度会更高
分解问题的思路,求整个树上在区间数字之和分解为 左右子树位于区间数字之和。 分解问题都是分解成左右子树,
class Solution:
#求真个二叉搜索树的范围和,变成左右子树在这个范围的数有多少
def rangeSumBST(self, root: Optional[TreeNode], low: int, high: int) -> int:#这个函数的定义就是求得BST上,这个范围的数字和是多少。
if root is None:
return 0
if root.val < low :
return self.rangeSumBST(root.right, low, high)
elif root.val > high:
return self.rangeSumBST(root.left, low, high)
else:
#root.va.如果在这个范围那么就左右子树都有可能在整个范围
return root.val + self.rangeSumBST(root.left, low, high) + self.rangeSumBST(root.right, low, high)
##分解问题的思路, 函数的定义很关键, 问题的分解也很关键