导语
leetcode刷题笔记记录,本篇博客记录二叉搜索树部分的题目,主要题目包括:
- 236 二叉树的最近公共祖先
- 235 二叉搜索树的最近公共祖先
- 701 二叉搜索树中的插入操作
Leetcode 236. 二叉树的最近公共祖先
题目描述
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
示例 1:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3 。
解法
使用递归来解决这道题目,一共分为以下两种情况:
- 节点左子树中包含p(或者q),右子树中包含q(或者p),那么该节点就是p和q的最近公共祖先。
- 节点本身p(q),它拥有一个子孙节点q(p)
递归三部曲:
- 递归函数返回值以及参数:需要递归函数返回最近公共节点,如果遇到p或者q,就把q或者p返回,返回值不为空,就说明找到了q或者p。
- 终止条件:
- 遇到空的话,因为树都是空了,所以返回空。
- 如果 root == q,或者 root == p,说明找到 q p ,则将其返回,
- 单层递归逻辑中,本题函数有返回值,是因为回溯的过程需要递归函数的返回值做判断,但本题我们依然要遍历树的所有节点。之前已经在二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值? (opens new window)中讨论了递归函数有返回值就是要遍历某一条边,但有返回值也要看如何处理返回值!
如果递归函数有返回值,如何区分要搜索一条边,还是搜索整个树呢?
搜索一条边的写法:
if (递归函数(root->left)) return ;
if (递归函数(root->right)) return ;
搜索整个树写法:
left = 递归函数(root->left); // 左
right = 递归函数(root->right); // 右
left与right的逻辑处理; // 中
区别在于:
在递归函数有返回值的情况下:如果要搜索一条边,递归函数返回值不为空的时候,立刻返回,如果搜索整个树,直接用一个变量left、right接住返回值,这个left、right后序还有逻辑处理的需要,也就是后序遍历中处理中间节点的逻辑(也是回溯) 。
本题代码如下:
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if root is None: # 返回值
return None
if root==p or root==q:
return root
left = self.lowestCommonAncestor(root.left, p, q) # 左
right = self.lowestCommonAncestor(root.right, p, q) # 右
if left != None and right != None: # 中
return root
elif left is None and right is not None:
return right
elif left is not None and right is None:
return left
else:
return None
Leetcode 235. 二叉搜索树的最近公共祖先
递归法
本题是236的简单版本,即二叉树被约束为了二叉搜索树,因此可以利用这个良好的排序性质来简化代码:递归法的代码如下:
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)
elif root.val > p.val and root.val > q.val:
return self.lowestCommonAncestor(root.left, p, q)
else:
return root
迭代法
层次遍历法如下:
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
while root:
if root.val < p.val and root.val < q.val:
root = root.right
elif root.val > p.val and root.val > q.val:
root = root.left
else:
return root
Leetcode 701.二叉搜索树中的插入操作
题目描述
给定二叉搜索树(BST)的根节点 root 和要插入树中的值 value ,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。
注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。
示例 1:
输入: root = [4,2,7,1,3], val = 5
输出: [4,2,7,1,3,5]
解释: 另一个满足题目要求可以通过的树是:
解法
只要按照二叉搜索树的规则去遍历,遇到空节点就插入节点就可以了。
递归法
class Solution:
def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
if root is None:
return TreeNode(val)
if val < root.val:
root.left = self.insertIntoBST(root.left, val)
else:
root.right = self.insertIntoBST(root.right, val)
return root
迭代法
层次遍历法需要双指针,pre指针用于记录当前指针cur变为None时的上一个节点。之后,新建一个节点挂到pre上即可。
class Solution:
def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
if root is None:
return TreeNode(val)
cur = root
pre = None
while cur:
pre = cur
if cur.val < val:
cur = cur.right
else:
cur = cur.left
if val < pre.val:
pre.left = TreeNode(val)
else:
pre.right = TreeNode(val)
return root