[路飞]二叉搜索树的最近公共祖先节点

145 阅读1分钟

记录 1 道算法题

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

剑指 Offer 68 - I. 二叉搜索树的最近公共祖先 - 力扣(LeetCode) (leetcode-cn.com)


  1. 遍历两遍

首先收集 q 的路径,再收集 p 的路径,然后找他们最后一个相同的元素。

二叉搜索树的特点是左子节点小于根节点,右子节点大于根节点。

    function lowestCommonAncestor(root, p, q) {
        // 记录路径
        const s1 = move(root, p)
        const s2 = move(root, q)
        let i = 0
        // 比较
        while (s1[i] === s2[i]) {
          i++
        }
        // 最后一个相同的节点
        return s1[i - 1]
    }

    function move(root, val) {
      const stack = []

      while (root) {
        stack.push(root.val)
        if (root.val === val) {
          break
        }

        if (val > root.val) {
          root = root.right
        } else {
          root = root.left
        }
      }
      return stack
    }
  1. 遍历 1 遍

优化的方向就是减少遍历的次数。

当他们同一个分支,都大于某个数或小于某个数的时候,他们还在一起,他们最近的祖先元素就是他们的父元素。

当出现分岔的时候,一个要走左节点,一个要走右节点。这时无论他的目的在哪,他的共同祖先节点都是当前的父节点,并且后面不会在改变。

所以根据这个特点,我们只需要在遍历的时候,判断他如果是分岔,则直接返回这个节点就好了。

#递归版本

    function lowestCommonAncestor(root, p, q) {
        // 都往右走
        if (p > root.val && q > root.val) {
          return lowestCommonAncestor(root.right, p, q)
        }
        // 都往左走
        if (p < root.val && q < root.val) {
          return lowestCommonAncestor(root.left, p, q)
        }
        // 分岔路
        return root
    }

#循环版本

    function lowestCommonAncestor(root, p, q) {
        while (true) {
          // 往右走
          if (p > root.val && q > root.val) {
            root = root.right
          } else if (p < root.val && q < root.val) {
          // 往左走
            root = root.left
          } else {
          // 分岔路
            return root
          }
        }
    }