You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LeetCode 235:二叉搜索树最近公共祖先代码返回None问题排查

LeetCode 235. 二叉搜索树的最近公共祖先代码错误分析

我正在解决LeetCode 235. Lowest Common Ancestor of a Binary Search Tree问题,需要在给定二叉搜索树(BST)中找出两个指定节点的最近公共祖先(LCA)。我的代码如下:

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        ans = None

        def travel(root, p, q, ans):
            if not root: return
            temp=[]
            if root:
                temp.append(root.val)
            if root.right:
                temp.append(root.right.val)
            if root.left:
                temp.append(root.left.val)
            if p.val in temp and q.val in temp:
                ans = root
            if ans:
                return ans
            travel(root.left, p, q, ans)
            travel(root.right, p, q, ans)

        return travel(root, p, q, ans)

在测试用例 Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4 时,代码返回None,但在travel函数内尝试print(ans)时却能看到正确结果2。请问我的代码错误在哪里?


错误原因拆解

1. 变量作用域搞错了

你在外部函数定义的ans和内部travel函数里的ans是两个完全独立的变量。当你在travel里执行ans = root时,只是修改了函数内部的临时ans,外面的ans还是初始的None。所以哪怕你在travel内部print能看到正确值,外部的变量根本没被改动,最后返回的自然是None。

2. 递归返回值没处理

你递归调用travel(root.left, p, q, ans)的时候,就算左子树的递归已经找到了LCA节点,你也没接收这个返回值并向上传递。比如当左子树的travel返回了节点2,你直接忽略了这个结果,继续调用右子树的travel,最后整个travel函数没有把找到的节点返回出去,导致最终返回None。

3. LCA的判断逻辑不对

你用当前节点及其左右子节点的值组成列表,判断p和q的val是否在里面来确定LCA,这个逻辑不严谨。比如如果p和q都在当前节点的同一子树深处,你的逻辑会漏掉正确的LCA节点,而且完全没利用BST“左子树值全小于根,右子树值全大于根”的特性,既低效又容易出错。


修复方案

方案一:修正递归逻辑

用nonlocal关键字让内部函数能修改外部的ans,同时处理递归返回值:

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        ans = None

        def travel(node):
            nonlocal ans
            if not node or ans:  # 已经找到结果就直接返回,不用继续遍历
                return
            # 正确的LCA判断:当前节点是p/q,或者p和q分别在左右子树
            if (node.val == p.val or node.val == q.val) or \
               (p.val < node.val < q.val) or (q.val < node.val < p.val):
                ans = node
                return
            travel(node.left)
            travel(node.right)

        travel(root)
        return ans

方案二:利用BST特性优化(更高效)

BST的有序性可以让我们直接定位LCA,不用遍历整个树:

  • 如果p和q的值都比当前节点小,LCA肯定在左子树;
  • 如果p和q的值都比当前节点大,LCA肯定在右子树;
  • 剩下的情况(当前节点是p/q,或者p和q分别在左右),当前节点就是LCA。

递归版本:

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if p.val < root.val and q.val < root.val:
            return self.lowestCommonAncestor(root.left, p, q)
        elif p.val > root.val and q.val > root.val:
            return self.lowestCommonAncestor(root.right, p, q)
        else:
            return root

迭代版本(空间复杂度O(1)):

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        while root:
            if p.val < root.val and q.val < root.val:
                root = root.left
            elif p.val > root.val and q.val > root.val:
                root = root.right
            else:
                return root
        return None

内容的提问来源于stack exchange,提问作者Jeflee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 17:43:11