leetcode 面试题 04.12. 求和路径的创意解法
2024-01-30 03:16:37
二叉树求和路径:巧妙解法,助你征服面试
深入剖析二叉树求和路径
在算法面试中,二叉树求和路径问题以其简洁的题意和巧妙的解法而闻名。本篇博客将带你深入剖析这道经典难题,为你提供一种独创且高效的解题思路,助你面试中脱颖而出。
题目背景
给定一棵二叉树,每个节点包含一个正或负整数。你的任务是找出从根节点到叶节点的所有路径,使得路径上的节点值之和等于一个给定的目标和。
朴素解法
最直接的解法是深度优先搜索(DFS),以递归的方式遍历二叉树。在遍历过程中,我们维护一个路径和变量,并不断将其更新。对于每个节点,我们考虑两种情况:将其纳入或排除在路径和之外。如果路径和等于目标和,我们便输出该路径。
这种朴素解法的复杂度为 O(2^n),其中 n 为二叉树的节点数。对于规模较大的二叉树,该解法的效率较低。
优化解法
为了提高效率,我们可以利用二叉树的性质进行优化。我们知道,每个节点要么是叶节点,要么拥有左子树和右子树。因此,对于每个节点,我们只需要考虑三种情况:
- 路径和不包含该节点,继续搜索其左子树和右子树。
- 路径和包含该节点,继续搜索其左子树或右子树(但不能同时搜索)。
- 路径和减去该节点的值等于目标和,输出该路径。
这种优化后的解法复杂度为 O(n),对于规模较大的二叉树,效率显著提高。
代码实现
def path_sum(root, target_sum):
def dfs(node, current_sum, path):
if not node:
return
current_sum += node.val
path.append(node.val)
if current_sum == target_sum:
result.append(path.copy())
dfs(node.left, current_sum, path)
dfs(node.right, current_sum, path)
path.pop()
result = []
dfs(root, 0, [])
return result
创造性解法
我们还可以对优化后的解法进行进一步优化。利用二叉树的性质,我们发现每个节点都拥有一个父节点(根节点除外)。因此,我们可以维护一个指向父节点的指针,在搜索过程中不断更新该指针。
对于每个节点,我们只需要考虑两种情况:
- 路径和不包含该节点,继续搜索其左子树和右子树。
- 路径和包含该节点,继续搜索其左子树或右子树(但不能同时搜索)。
这种创造性的解法的复杂度仍然为 O(n),但在实际运行中的效率更高。
代码实现
def path_sum(root, target_sum):
def dfs(node, current_sum, path):
if not node:
return
current_sum += node.val
path.append(node.val)
if current_sum == target_sum:
result.append(path.copy())
if node.left:
dfs(node.left, current_sum, path)
if node.right:
dfs(node.right, current_sum, path)
path.pop()
result = []
dfs(root, 0, [])
return result
总结
通过巧妙利用二叉树的性质和高效的算法,我们可以解决二叉树求和路径问题。优化后的解法复杂度为 O(n),创造性解法在实际运行中效率更高。希望这篇文章能够帮助你深入理解这道经典面试题,并为你的面试做好充分准备。
常见问题解答
-
如何处理负节点值?
我们的解法可以处理负节点值,因为我们在计算路径和时会将其考虑在内。
-
如果有多条路径满足目标和,该怎么办?
我们的解法会返回所有满足目标和的路径。
-
为什么需要维护一个指向父节点的指针?
维护指向父节点的指针可以帮助我们避免重复搜索已经探索过的子树。
-
这种解法能否用于解决其他二叉树问题?
这种解法可以用于解决其他需要遍历二叉树的二叉树问题,例如找到最长路径或检查二叉树是否为二叉搜索树。
-
还有什么其他优化可以应用?
我们可以使用剪枝技术来进一步优化解法。如果当前路径和与目标和相差太大,我们可以停止搜索该子树。