Leetcode 235.二叉搜索树的最近公共祖先

题目:235.二叉搜索树的最近公共祖先

初始思路

236是二叉树的最近公共祖先,也可以用到这题。这题可以利用二叉搜索树的特性减少一些查询。

代码

  1. var lowestCommonAncestor = function (root, p, q) {
  2. if (!root) return root
  3. if (root.val > p.val && root.val > q.val) {
  4. // 在左子树查询
  5. let left = lowestCommonAncestor(root.left, p, q)
  6. if (left) return left
  7. } else if (root.val < p.val && root.val < q.val) {
  8. // 在右子树查询
  9. let right = lowestCommonAncestor(root.right, p, q)
  10. if (right) return right
  11. } else {
  12. // 当前节点的值在给定值的中间,就是最深的祖先
  13. return root
  14. }
  15. };
  1. var lowestCommonAncestor = function (root, p, q) {
  2. while (root) {
  3. if (root.val > p.val && root.val > q.val) {
  4. root = root.left
  5. } else if (root.val < p.val && root.val < q.val) {
  6. root = root.right
  7. } else {
  8. return root
  9. }
  10. }
  11. return null
  12. }

感想

  1. 二叉树是有序的,因为所有节点的值都不同,且p q值不同。其实只要从上到下遍历的时候,cur节点是数值在[p, q]区间中则说明该节点cur就是最近公共祖先了。
  2. 而且因为二叉树有序,就不需要回溯,直接往下找就行了。

Leetcode 701.二叉搜索树中的插入操作

题目:701.二叉搜索树中的插入操作

初始思路

在不改变原BST的结构上,将val挂载在这颗树上。

代码

  1. var insertIntoBST = function(root, val) {
  2. const setInOrder = (root, val) => {
  3. if (!root) {
  4. let node = new TreeNode(val)
  5. return node
  6. }
  7. if (root.val > val) {
  8. root.left = setInOrder(root.left, val)
  9. } else if (root.val < val) {
  10. root.right = setInOrder(root.right, val)
  11. }
  12. return root
  13. }
  14. return setInOrder(root, val)
  15. };
  1. var insertIntoBST = function (root, val) {
  2. if (!root) {
  3. root = new TreeNode(val)
  4. } else {
  5. // 找到val的父节点
  6. let parent = new TreeNode(0)
  7. let cur = root
  8. while (cur) {
  9. parent = cur
  10. if (cur.val > val) cur = cur.left
  11. else cur = cur.right
  12. }
  13. let node = new TreeNode(val)
  14. // 将node节点挂载在父节点上
  15. if (parent.val > val) parent.left = node
  16. else parent.right = node
  17. }
  18. return root
  19. }

感想

  1. 题目说有多种答案,其实就是改变了原BST的结构,可以不改变,只是遵循原结构的基础上新增一个节点。
  2. 还是递归容易想出来。

Leetcode 450.删除二叉搜索树中的节点

题目:450.删除二叉搜索树中的节点 讲解:https://www.bilibili.com/video/BV1tP41177us

初始思路

删除节点需要改变BST的结构

代码

  1. var deleteNode = function (root, key) {
  2. if (!root) return null
  3. if (key > root.val) {
  4. root.right = deleteNode(root.right, key)
  5. return root
  6. } else if (key < root.val) {
  7. root.left = deleteNode(root.left, key)
  8. return root
  9. } else {
  10. // 情况一:左右都为空,是叶子节点
  11. if (root.left == null && root.right == null) {
  12. return null
  13. }
  14. // 情况二:左右节点其中一个不存在,直接让父节点指向子节点即可
  15. if (root.left !== null && root.right == null) {
  16. return root.left
  17. } else if (root.left == null && root.right !== null) {
  18. return root.right
  19. }
  20. // 情况三:左右节点都不为空,将右子树中最小的节点补位
  21. const rightNode = root.right
  22. // 获取右子树中最左侧的节点
  23. const minNode = getMinNode(rightNode)
  24. // 将待删除的节点的值更换
  25. root.val = minNode.val
  26. // 删除最小值节点
  27. root.right = deleteNode(root.right, minNode.val)
  28. return root
  29. }
  30. };
  31. function getMinNode (root) {
  32. while (root.left) {
  33. root = root.left
  34. }
  35. return root
  36. }
  1. var deleteNode = function (root, key) {
  2. const deleteOneNode = target => {
  3. if (!target) return target
  4. if (!target.right) return target.left
  5. let cur = target.right
  6. while (cur.left) {
  7. cur = cur.left
  8. }
  9. cur.left = target.left
  10. return target.right
  11. }
  12. if (!root) return root
  13. let cur = root
  14. let pre = null
  15. while (cur) {
  16. if (cur.val === key) break
  17. pre = cur
  18. cur.val > key ? cur = cur.left : cur = cur.right
  19. }
  20. if (!pre) {
  21. return deleteOneNode(cur)
  22. }
  23. if (pre.left && pre.left.val === key) {
  24. pre.left = deleteOneNode(cur)
  25. }
  26. if (pre.right && pre.right.val === key) {
  27. pre.right = deleteOneNode(cur)
  28. }
  29. return root
  30. }

感想

  1. 没找到删除的节点:遍历到空节点直接返回
  2. 左右孩子都为空(叶子节点):直接删除该节点,返回null为根节点
  3. 左孩子为空,右孩子不为空:删除节点,右孩子补位,返回右孩子为根节点
  4. 右孩子为空,左孩子不为空:删除节点,左孩子补位,返回左孩子为根节点
  5. 左右孩子均不为空:删除节点,将右子树中最小的值补位,返回删除后的root节点为根节点