Given a binary tree, determine if it is a valid binary search tree (BST).
Assume a BST is defined as follows:
- The left subtree of a node contains only nodes with keys less than the node's key.
- The right subtree of a node contains only nodes with keys greater than the node's key.
- Both the left and right subtrees must also be binary search trees.
Example 1:
2 / \ 1 3
Binary tree [2,1,3]
, return true.
Example 2:
1 / \ 2 3
Binary tree [1,2,3]
, return false.
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * public int val; 5 * public TreeNode left; 6 * public TreeNode right; 7 * public TreeNode(int x) { val = x; } 8 * } 9 */ 10 public class Solution { 11 // idea: BST in order traversal is always sorted 12 public bool IsValidBST(TreeNode root) { 13 if (root == null) return true; 14 15 var stack = new Stack<TreeNode>(); 16 TreeNode prior = null; 17 18 while (root != null || stack.Count > 0) 19 { 20 while (root != null) 21 { 22 stack.Push(root); 23 root = root.left; 24 } 25 26 root = stack.Pop(); 27 if (prior != null) 28 { 29 if (root.val <= prior.val) return false; 30 } 31 prior = root; 32 root = root.right; 33 } 34 35 return true; 36 } 37 38 // idea: BST in order traversal is always sorted 39 // cons: it changes the tree structure which might be not allowed 40 public bool IsValidBSTSolution3(TreeNode root) { 41 if (root == null) return true; 42 43 var stack = new Stack<TreeNode>(); 44 stack.Push(root); 45 TreeNode prior = null; 46 47 while (stack.Count > 0) 48 { 49 var p = stack.Peek(); 50 if (p.left != null) 51 { 52 stack.Push(p.left); 53 p.left = null; 54 } 55 else 56 { 57 stack.Pop(); 58 59 if (prior != null) 60 { 61 if (prior.val >= p.val) return false; 62 } 63 64 prior = p; 65 66 if (p.right != null) 67 { 68 stack.Push(p.right); 69 p.right = null; 70 } 71 } 72 } 73 74 return true; 75 } 76 77 78 // cons: need to use the tricky min/max boundary 79 public bool IsValidBSTSolution2(TreeNode root) { 80 return DFS(root, Int64.MinValue, Int64.MaxValue); 81 } 82 83 private bool DFS(TreeNode node, long min, long max) 84 { 85 if (node == null) return true; 86 if ((long)node.val <= min || (long)node.val >= max) return false; 87 88 return DFS(node.left, min, (long)node.val) && DFS(node.right, (long)node.val, max); 89 } 90 91 92 // idea: for each node: get the min/max value from left and right tree, and check this node with left/right trees forms a BST 93 // then recursively do this for all child nodes. To optimize we can cache the min/max value for each node. 94 // cons: two passes of the tree though even with cache 95 public bool IsValidBSTSolution1(TreeNode root) { 96 if (root == null) return true; 97 98 var pair = new long[2] {Int64.MaxValue, Int64.MinValue}; 99 FindMinMax(root.left, pair); 100 if ((long)root.val <= pair[1]) return false; 101 pair = new long[2] {Int64.MaxValue, Int64.MinValue}; 102 FindMinMax(root.right, pair); 103 if ((long)root.val >= pair[0]) return false; 104 105 return IsValidBST(root.left) && IsValidBST(root.right); 106 } 107 108 private void FindMinMax(TreeNode node, long[] pair) 109 { 110 if (node == null) return; 111 pair[0] = Math.Min(pair[0], (long)node.val); 112 pair[1] = Math.Max(pair[1], (long)node.val); 113 FindMinMax(node.left, pair); 114 FindMinMax(node.right, pair); 115 } 116 }
/** * Definition for a binary tree node. * public class TreeNode { * public int val; * public TreeNode left; * public TreeNode right; * public TreeNode(int x) { val = x; } * } */public class Solution { // idea: BST in order traversal is always sorted public bool IsValidBST(TreeNode root) { if (root == null) return true; var stack = new Stack<TreeNode>(); TreeNode prior = null; while (root != null || stack.Count > 0) { while (root != null) { stack.Push(root); root = root.left; } root = stack.Pop(); if (prior != null) { if (root.val <= prior.val) return false; } prior = root; root = root.right; } return true; } // idea: BST in order traversal is always sorted // cons: it changes the tree structure which might be not allowed public bool IsValidBSTSolution3(TreeNode root) { if (root == null) return true; var stack = new Stack<TreeNode>(); stack.Push(root); TreeNode prior = null; while (stack.Count > 0) { var p = stack.Peek(); if (p.left != null) { stack.Push(p.left); p.left = null; } else { stack.Pop(); if (prior != null) { if (prior.val >= p.val) return false; } prior = p; if (p.right != null) { stack.Push(p.right); p.right = null; } } } return true; } // cons: need to use the tricky min/max boundary public bool IsValidBSTSolution2(TreeNode root) { return DFS(root, Int64.MinValue, Int64.MaxValue); } private bool DFS(TreeNode node, long min, long max) { if (node == null) return true; if ((long)node.val <= min || (long)node.val >= max) return false; return DFS(node.left, min, (long)node.val) && DFS(node.right, (long)node.val, max); } // idea: for each node: get the min/max value from left and right tree, and check this node with left/right trees forms a BST // then recursively do this for all child nodes. To optimize we can cache the min/max value for each node. // cons: two passes of the tree though even with cache public bool IsValidBSTSolution1(TreeNode root) { if (root == null) return true; var pair = new long[2] {Int64.MaxValue, Int64.MinValue}; FindMinMax(root.left, pair); if ((long)root.val <= pair[1]) return false; pair = new long[2] {Int64.MaxValue, Int64.MinValue}; FindMinMax(root.right, pair); if ((long)root.val >= pair[0]) return false; return IsValidBST(root.left) && IsValidBST(root.right); } private void FindMinMax(TreeNode node, long[] pair) { if (node == null) return; pair[0] = Math.Min(pair[0], (long)node.val); pair[1] = Math.Max(pair[1], (long)node.val); FindMinMax(node.left, pair); FindMinMax(node.right, pair); }}