My first instinct was to just return a boolean and I had to stop myself.
Use a top-down DFS that passes down the valid (min, max) range for each node, counting a node as violating if its value is outside that range and then stopping recursion into its children to avoid double-counting. For non-violating nodes, update the range for left and right subtrees accordingly.
Pro tip: Clarify that once a node violates the BST property, its entire subtree is considered invalid, so you should not recurse further into it—this avoids counting descendants as separate violations and matches the 'counting each violating node only once' requirement.
Confirm that a node violates if its value is outside the range implied by all ancestors, and that once a node violates, its descendants are not counted separately. This sets the recursion base case.
Write a function that takes a node, a lower bound, and an upper bound, and returns the count of violating nodes in the subtree. Use -infinity and +infinity for the root.
If the node is null, return 0. If node.val is outside [low, high], return 1 (and do not recurse). Otherwise, recurse left with (low, node.val) and right with (node.val, high), and return the sum.
Explain that each node is visited at most once, so time complexity is O(n) and space complexity is O(h) for the recursion stack, where h is the tree height.
Walk through examples: a valid BST (returns 0), a tree where the root violates (returns 1), and a tree with multiple violations at different levels to ensure no double-counting.
AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.