1. 案例
给定一个二叉搜索树,找到该树中两个指定节点的最近公共祖先(一个节点也可以是它自己的祖先)。所有节点的值都是唯一的。
p,q 为不同节点且均存在于给定的二叉搜索树中。
如:root = [6,2,8,0,4,7,9,null,null,3,5] ;
节点 2 和 节点 8 的最近公共祖先就是节点 6;
节点 2 和 节点 5 的最近公共祖先就是节点 2;
2. 思路
方法:迭代法
二叉搜索树也叫二叉排序树。其特点是根节点的左子树值小于或等于根节点值,右子树值大于或等于根节点值。二叉搜索树也可能是一颗空树,但只要不空就满足以上条件。
基于以上对二叉搜索树的理解,可以提炼出以下几个要点。
- 对于任意节点 p 或者 q。大的节点大于等于根节点,小的节点小于等于根节点时。它们的公共祖先就是根节点。比如节点 2<= 节点 6。节点 8>= 节点 6,根节点即为 6;节点4 <= 节点6,节点 7>= 节点 6,根节点也为 6。
- 如果两个节点均小于根节点 6。则其最近祖先节点一定在左子树上。那么把根节点(节点6)左子树(节点2)作为根节点继续判断,以此迭代。
- 如果两个节点均大于根节点 6。则其最近祖先节点一定在右子树上。那么把根节点(节点6)右子树(节点8)作为根节点继续判断,以此迭代。
基于以上的分析,可使用迭代法。
3. 代码
//构造函数如下
function TreeNode(val) {
this.val = val;
this.left = this.right = null;
}
//原始数据如下
var root = [6,2,8,0,4,7,9,null,null,3,5]
//变形后的数据结构如下
var tree = {val:6,
left: {val:2,left:{val:0,left: null,right:null}, right:{val:4,left:{val:3,left:null,right:null}, right:{val:5,left:null,right:null}}},
right:{val:8, left:{val:7,left:null,right:null},right:{val:9,left:null,right:null}}
};
let lowestCommonAncestor = function(root, p, q) {
let temp = root;
//如果p>q,调换 p,q 的顺序
if(p.val > q.val) {
[p, q] = [q, p];
}
while(true) {
//根元素大于等于大的元素值并且小于等于小的元素值,或者根元素为pq的任意一个,则直接返回根(顶层)元素
if((temp.val >= p.val && temp.val <= q.val) || (temp === p || temp === q)) {
return temp;
//p,q均大于根元素,则说明pq都在根元素的右子树。则把根元素的右子树作为根元素循环
} else if(temp.val < p.val && temp.val < q.val) {
temp = temp.right;
//p,q均小于根元素,则说明pq都在根元素的左子树。则把根元素的左子树作为根元素循环
} else {
temp = temp.left;
}
}
};
console.log(lowestCommonAncestor(tree,new TreeNode(9),new TreeNode(7)))