一:二叉搜索树的最近公共祖先
1、问题描述:
2、数据结构:
二叉搜索树
3、题解:
方法1:递归
二叉搜索树有个性质:即左子树的节点小于根节点,右子树的节点大于根节点,左右子树也是二叉搜索树。
最近公共祖先的定义: 设节点 root为节点 p,q 的某公共祖先,若其左子节点 root.left 和右子节点 root.right 都不是.p,q 的公共祖先,则称 root是 “最近的公共祖先” 。
最近的公共节点只能是下面几种情况:
1)p、q为root的子树,且分别在root的不同侧(即分别为左、右子树)
2)p = root,q在root的左(或右)子树
3)q = root,p在root的左(或右)子树
那么用递归去解题就是
若都大于root,则在右子树查找
若都小于root,则在左子树查找
否则返回为根节点。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if root.val < p.val and root.val < q.val:
return self.lowestCommonAncestor(root.right, p, q)
if root.val > p.val and root.val > q.val:
return self.lowestCommonAncestor(root.left, p, q)
return root
方法2:迭代
思路和递归差不多
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
#非递归
node = root
while node:
if p.val > node.val and q.val > node.val:
node = node.right
elif p.val < node.val and q.val < node.val:
node = node.left
else:
return node
优化:可以减少判断次数,先对p,q进行判断
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if p.val > q.val:#保证p <= q,减少判断次数
p,q = q,p
node = root
while node:
if p.val > node.val :
node = node.right
elif q.val < node.val:
node = node.left
else:
return node
4、复杂度分析:
方法1:
时间复杂度:O(logN)
空间复杂度:O(logN)
方法2:
时间复杂度:O(logN)
空间复杂度:O(1)
二、二叉树的最近公共祖先
1、问题描述:
2、数据结构:
二叉树
3、题解:
方法1:
如果有指向父节点的指针,那么可以返回找到p或q的路径的反方向,问题转化为求两个链表第一个公共节点的问题。举例:如上图,加入,p、q分别为7、4,那么有7-2-5-3,4-2-5-3,两个链表的第一个公共节点是2,找到。
可以使用数组存储路径,找到第一个不相等的节点的前一个节点就是最近公共祖先。那么使用先序遍历。如上图,加入p、q分别为7,4,则有3-5-2-7,3-5-2-4,2为两个数组中第一个不相等的值的前一个值。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode:
def dfs(root,node,stack):
if not root:
return False
stack.append(root)
if root.val == node.val:
return True
if (dfs(root.left,node,stack) or dfs(root.right,node,stack)):
return True
stack.pop()#都没找到,向上回溯
stack1 = []
stack2 = []
dfs(root,p,stack1)
dfs(root,q,stack2)
i ,res= 0,0
while i < len(stack1) and i < len(stack2) and stack1[i] == stack2[i]:
res = stack1[i]
i += 1
return res
方法2:
后序遍历,分析见第一题。
递归结束条件是:root为空或者等于p的值,或者等于q的值返回root.
因为二叉树没有二叉搜索树那样的性质,所以要先遍历左右子树,然后判断是否在左右子树中:
当左右子树为空时,返回;
当不在左子树中,返回右子树;
当不在右子树中,返回左子树;
当在两侧,说明找到最近公共祖先,返回即可。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode:
if not root or p.val == root.val or q.val == root.val:
return root
left = self.lowestCommonAncestor(root.left,p,q)
right = self.lowestCommonAncestor(root.right,p,q)
if not left and not right:
return
if not left:
return right
if not right:
return left
return root
4、复杂度分析:
两种方法都是:
时间复杂度:O(N)
空间复杂度:O(N)