Dado un árbol binario, determinar si es un árbol binario de búsqueda válida (BST).
Supongamos un BST se define como sigue:
El subárbol izquierdo de un nodo contiene sólo los nodos con claves menos que la clave del nodo. El subárbol derecho de un nodo contiene sólo los nodos con claves mayores que la clave del nodo. Tanto la izquierda como la derecha subárboles también deben ser árboles binarios de búsqueda.
Example 1:
2
/ \
1 3
Input: [2,1,3]
Output: true
Example 2:
5
/ \
1 4
/ \
3 6
Input: [5,1,4,null,null,3,6]
Output: false
Explanation: The root node's value is 5 but its right child's value is 4.
Mi código:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isValidBST(self, root: TreeNode) -> bool:
def helper(node, lower = float('-inf'), upper = float('inf')):
if(not node):
return True
if(node.val<=lower or node.val>=upper):
return False
if not helper(node.right, node.val, upper):
return False
if not helper(node.left, lower, node.val):
return False
return True
return helper(root)
El código anterior funciona bien para todos los casos de prueba. Sin embargo, el código de abajo no lo hace.
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isValidBST(self, root: TreeNode) -> bool:
def helper(node, lower = float('-inf'), upper = float('inf')):
if(not node):
return True
if(node.val<=lower or node.val>=upper):
return False
helper(node.right, node.val, upper)
helper(node.left, lower, node.val)
return True
return helper(root)
¿Cuál es la necesidad de que el extra si las condiciones? Incluso sin ellos, las funciones deben devolver falsa de la condición if abajo a la derecha? ¿Que me estoy perdiendo aqui?
if(node.val<=lower or node.val>=upper):
return False
básicamente estás preguntando cuál es la diferencia entre:
if not helper(node.right, node.val, upper):
return False
if not helper(node.left, lower, node.val):
return False
return True
y:
helper(node.right, node.val, upper)
helper(node.left, lower, node.val)
return True
Los primeros comprueba el valor de retorno de las helper
llamadas y actúa en consecuencia, devolver false si el sub-árbol no es un BST. Los controles de segundo los sub-árboles continuación, devuelve verdadero no importa qué.
Esto es importante. La definición de una BST válida es que root
es mayor que root.left
y menor que root.right
, y que ambos root.left
y root.right
son también BSTs válidos.
Al ignorar los valores de retorno, lo único que se está comprobando es que la parte superior tres nodos para un BST válida. En otras palabras, este pasaría a pesar de estar en ninguna parte cerca de validez:
__4__
/ \
2 8
/ \ / \
3 1 9 7
Sin devolver el resultado en cada nivel de recursividad, que, básicamente, lo pierde.
Consideremos el siguiente código, que es semejante a la pregunta que se ha planteado en un comentario ( "Pero dentro de la función auxiliar, si hay una condición que return false derecha ¿Cómo es que no entran en juego aquí?"):
def level2():
return 42 # Returns '42'.
def level1():
level2() # Returns 'None', not '42'.
print(level1()) # Prints 'None'.
Esta impresora None
, ya que, a pesar de que regresen 42
en el nivel dos, que se desecha en un nivel.
El método correcto sería cambiar la level2()
llamada a return level2()
.
Dicho sea de paso, no estoy seguro de cuál es el valor que está recibiendo de upper
y lower
aquí.
La definición recursiva de los medios de validez que la única cosa que necesita hacer es comprobar los tres nodos inmediatos y los sub-árboles.
En otras palabras, esto sería suficiente (pseudo-código, a pesar de que se ve como Python, siendo esta última una línea de base ideal para los primeros):
def isValidBst(node):
# Empty tree is valid (or sub-tree, for that matter
# but, since we never descend into a null, that's a
# moot point).
if node is null: return true
# Check left value and sub-tree.
if node.left is not null:
if node.left.value >= node.value: return false
if not isValidBst(node.left): return false
# Check left value and sub-tree.
if node.right is not null:
if node.right.value <= node.value: return false
if not isValidBst(node.right): return false
# If there were no failures, including the possibility
# we're at a leaf node, everything below this node is
# okay.
return true