【问题标题】:Check if a tree is a Binary Search Tree (BST)检查树是否为二叉搜索树 (BST)
【发布时间】:2017-07-03 12:21:43
【问题描述】:

我正在尝试解决二叉搜索树问题,但我无法通过所有测试用例。如果树是二叉搜索树,我需要返回 true,否则,我需要返回 false。谁能告诉我我做错了什么?

'''
class node:
    def __init__(self, data):
        self.data = data
        self.left = None
        self.right = None
'''

def checkBST(root):
    if root.left == None and root.right == None:
        return True
    if root == None:
        return True
    if root.left != None:
        if root.left.data < root.data:
            return True
    else:
        return False
    if root.right != None:
        if root.right.data > root.data:
            return True
        else:
            return False
    return chckBST(root.left) and chckBST(root) and chckBST(root.right)

【问题讨论】:

  • 你为什么要再次调用chckBST(root),应该是测试用例本身的第一次调用吧?我认为递归调用应该只用于左右

标签: python python-3.x tree binary-search-tree


【解决方案1】:

您的代码中有很多多余的if 条件。您可以像这样简化它:

def checkBST(root):
    if root == None or (root.left == None and root.right == None):
        return True

    elif root.right == None:
        return root.left.data < root.data and checkBST(root.left)

    elif root.left == None:
        return root.right.data >= root.data and checkBST(root.right)

    return checkBST(root.left) and checkBST(root.right)

首先,检查所有None 条件。 python 中的短路保证如果第一个条件是False,则不会评估第二个条件。这使您可以编写简洁的语句,例如return root.left.data &lt; root.data and checkBST(root.left)

最后,如果左右节点都不是None,请不要再次调用checkBST(root)。这导致无限递归。

【讨论】:

  • 此实现将对 Artur 提到的测试用例返回误报。
【解决方案2】:

所以你没有通过一些测试的原因是你只检查了一个级别。例如,如果有一个tree 使得它有一个root.left.right.data > root.data,那么你的代码将无法捕捉到它。有很好的解释here

但要点是:

  • 您的代码将通过此

  • 但它不会通过这个注意2的右孩子> root.data

我认为这个解决方案解决了它(很抱歉用 JS 代码回答 Python 问题,但我相信你会明白的):

function checkBST(root) {
    let isBST = true;
    let BSTUtil = r => {
        let left, right
        if(r.left) // Bottom out on the left side
            left = BSTUtil(r.left)
        if(r.right) // Bottom out on the right side
            right = BSTUtil(r.right)

        if(left > r.data) // Compare with parent
            isBST = false
        if(right < r.data) // Compare with parent
            isBST = false

        // Return MAX from branch
        if(!left && !right)
            return r.data
        else if(!left)
            return Math.max(right, r.data)
        else
            return Math.max(left, right, r.data)
    }
    BSTUtil(root)
    return isBST;
}

另外,请不要使用此代码,它使用O(n) 空间来解决问题,如果我花一些时间在这个问题上,我相信我可以找到更有效的解决方案。

【讨论】:

  • 看起来这个实现为checkBST({data: 10, left: null, right: {data: 12, left: {data: 2, left: null, right: null}, right: null}})返回true,即使右分支包含的值低于根值。
【解决方案3】:

正如 Artur 所说,您需要检查 所有 左侧节点是否小于或等于当前节点(假设您允许重复值,否则仅小于),并且 所有正确的节点都大于当前节点。

您可以通过递归传递最小允许值和最大允许值并根据这些值测试子节点来做到这一点。

def check_bst(root) -> bool:
    def is_bst_internal(root, min_allowed_val, max_allowed_val) -> bool:
        if root is None:
            return True

        if min_allowed_val is not None and root.data <= min_allowed_val:
            return False

        if max_allowed_val is not None and root.data > max_allowed_val:
            return False

        return is_bst_internal(root.left, min_allowed_val, root.data) and is_bst_internal(root.right, root.data, max_allowed_val)
    return is_bst_internal(root, None, None)

当我们向左走时,我们将当前值作为允许的最大值传递,因为我们在左分支遇到的任何更高的值都将无法通过检查。当我们向右时,我们将当前值作为最小值传递,因为任何较低(或相等)的值都将无法通过检查。 None 表示没有最大值/最小值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-09
    • 1970-01-01
    • 2020-04-07
    • 2018-05-16
    • 2012-06-05
    相关资源
    最近更新 更多