BST 的合法性

由于 BST 需要满足以下条件:

  • 节点的左子树仅包含键 小于 节点键的节点。
  • 节点的右子树仅包含键 大于 节点键的节点。
  • 左右子树也必须是二叉搜索树。

按照我们前面的理解是不是就会写出来

  1. func isValidBST(root *TreeNode) bool {
  2. if root == nil {
  3. return true
  4. }
  5. if root.Left != nil && root.Val < root.Left.Val {
  6. return false
  7. }
  8. if root.Right != nil && root.Val > root.Right.Val {
  9. return false
  10. }
  11. return isValidBST(root.Left) && isValidBST(root.Right)
  12. }

需要注意这个算法里,只考虑到了父子节点的大小问题,没有考虑到祖孙节点的比较。
BST 需要的是 root 的所有左子树节点的值都小于 root.Val , 所有右子树节点的值都要大于 root.Val
所以可以引入

  1. func isValidBST(root *TreeNode, min *TreeNode, max *TreeNode) bool {
  2. if root == nil {
  3. return true
  4. }
  5. if min != nil && root.Val < min.Val {
  6. return false
  7. }
  8. if max != nil && root.Val > max.Val {
  9. return false
  10. }
  11. return isValidBST(root.Left, nil, root) && isValidBST(root.Right, root, nil)
  12. }

这里的 min 和 max 不需要理解,只需要记住他们的作用是用来限制最大值和最小值的。
然后记住左子树的节点值都比 root.Val 小,右子树的节点都比 root.Val 大即可。

BST 中搜索一个数

  1. func isInBST(root *TreeNode, target int) bool {
  2. if root == nil {
  3. return false
  4. }
  5. if root.Val == target {
  6. return true
  7. }
  8. return isInBST(root.Left, target) || isInBST(root.Right,target)
  9. }

这么写相当于穷举了所有的节点,适用于普通的二叉树。那么对于 BST 我们应该利用 左小右大 的特性。

  1. func isInBST(root *TreeNode, target int) bool {
  2. if root == nil {
  3. return false
  4. }
  5. if root.Val == target {
  6. return true
  7. }
  8. if root.Val < target {
  9. return isInBST(root.Right, target)
  10. }
  11. if root.Val > target {
  12. return isInBST(root.Left, target)
  13. }
  14. }

BST 中插入一个数

这里需要理解为什么要生成新的节点

  1. func insertIntoBST(root *TreeNode, val int) *TreeNode{
  2. if root == nil {
  3. return &TreeNode{Val: val}
  4. }
  5. if root.Val < val {
  6. root.Right = insertIntoBST(root.Right, val)
  7. }
  8. if root.Val > val {
  9. root.Left = insertIntoBST(root.Left, val)
  10. }
  11. return root
  12. }

BST 中删除一个数

删除一个节点时可能会触发这三种情况:

  • 删除的节点正好是末端节点,没有子节点
  • 删除节点存在一个子节点
  • 删除节点存在两个子节点

其中第三个比较麻烦,为了不破坏 BST 的特性,A 必须找到左子树中最大的那个节点 或右子树中最小的节点来接替自己。
image.png

  1. /**
  2. * Definition for a binary tree node.
  3. * type TreeNode struct {
  4. * Val int
  5. * Left *TreeNode
  6. * Right *TreeNode
  7. * }
  8. */
  9. func deleteNode(root *TreeNode, key int) *TreeNode {
  10. if root == nil {
  11. return root
  12. }
  13. if root.Val == key {
  14. if root.Left == nil {
  15. return root.Right
  16. }
  17. if root.Right == nil {
  18. return root.Left
  19. }
  20. minNode := func(node *TreeNode) *TreeNode {
  21. for node.Left != nil {
  22. node = node.Left
  23. }
  24. return node
  25. }(root.Right)
  26. minNode.Left = root.Left
  27. root = root.Right
  28. } else if root.Val > key {
  29. root.Left = deleteNode(root.Left, key)
  30. } else {
  31. root.Right = deleteNode(root.Right, key)
  32. }
  33. return root
  34. }