记录 1 道算法题
二叉搜索树的最近公共祖先
剑指 Offer 68 - I. 二叉搜索树的最近公共祖先 - 力扣(LeetCode) (leetcode-cn.com)
- 遍历两遍
首先收集 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 遍
优化的方向就是减少遍历的次数。
当他们同一个分支,都大于某个数或小于某个数的时候,他们还在一起,他们最近的祖先元素就是他们的父元素。
当出现分岔的时候,一个要走左节点,一个要走右节点。这时无论他的目的在哪,他的共同祖先节点都是当前的父节点,并且后面不会在改变。
所以根据这个特点,我们只需要在遍历的时候,判断他如果是分岔,则直接返回这个节点就好了。
#递归版本
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
}
}
}