目录
任务
235. 二叉搜索树的最近公共祖先
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
思路
由于是二叉搜索树,所以可以利用其性质进行查找,即,只有在p和q的值的范围内的才是其祖先,并且由于遍历的递归序,当第一次遇到符合条件节点的时候,就是其最近公共祖先。
如果不满足条件时,递归的向其子树寻找,然后向上层返回。
- 局部: 是否满足节点的数值条件
- 子树递归: 根据值的大小和BST的性质向下(左或右)寻找
- 返回值: 向上层返回当前的信息,告诉上层我找到了,节点是XXX。
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
return self.dfs(root,p,q)
def dfs(self,node,p,q):
if not node: return None
if node.val > p.val and node.val > q.val:
return self.dfs(node.left,p,q)
elif node.val < p.val and node.val < q.val:
return self.dfs(node.right,p,q)
else: return node
701. 二叉搜索树中的插入操作
思路
插入的初步也是找到插入的位置,即查找。根据对BST的分析,任意数值都可以插入成为叶子节点以满足题意,这样的作法最简单,不需要调整树的结构。
个人觉得无返回值的逻辑比较好理解,就是处理上只有递没有归的过程,一直告诉下层你去合适的位置插入节点,直到到达目标位置,之后归的过程全是空,即无返回值,因为到达叶子节点做完插入这件事后,归的过程父节点不需要子节点的信息了(虽然这个过程是一定会进行的)
- 边界条件:如果是空树,直接构造并返回新的节点。
- 边界条件:到达插入位置的父节点后,将新节点插入
- 子树递归: 根据BST性质,向左或者向右遍历,直到到达插入位置的父节点
class Solution:
def __init__(self):
self.pre = None
def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
if not root:
return TreeNode(val)
self.dfs(root,val)
return root
def dfs(self,node,value):
if not node:
newNode = TreeNode(value)
if self.pre.val > value:
self.pre.left = newNode
else:
self.pre.right = newNode
else:
self.pre = node
if value < node.val:
self.dfs(node.left,value)
elif value > node.val:
self.dfs(node.right,value)
而代码随想录的有返回值的思路有点不好理解,细细分析后也比较方便,且写法上比较简洁,这里给出思路分析和代码
- 如果是空树,或者说找到插入位置,直接构造并返回新的节点。
- 子树递归:根据值的大小向左右层递归,并修改当前层的左或右指针(实际只有到达最后一层之前才实际接上了新节点,而其他节点的操作和覆盖相同(比如node.left = 下一层左边返回的node,但是这个语句进行后和不进行是一样的,等于啥都没做,只是递归的归的过程自然进行,之所以还需要也是为了接新节点的那次链接)
- 返回值: 返回自身节点,是为了子树归的过程中,赋值给上层的left或者right
class Solution:
def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
return self.dfs(root,val)
def dfs(self,node,value):
if not node:
newNode = TreeNode(value)
return newNode
if value < node.val:
node.left = self.dfs(node.left,value)
return node
elif value > node.val:
node.right = self.dfs(node.right,value)
return node
450. 删除二叉搜索树中的节点
思路
逻辑是找到并删除。
- 找的过程用递归中递的逻辑,且需要接底层返回的节点,归的时候是向上返回删除后的当前节点。
- base case比较复杂,分为5种情况,代码中有详细注释
class Solution:
def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
return self.dfs(root,key)
def dfs(self,node,value):
if not node: return None # 情况1,没找到
if node.val == value:
if not node.left and not node.right: #情况2,删除节点为叶子节点
return None
if not node.left and node.right: #情况3,删除节点没有左孩子
return node.right
if node.left and not node.right: #情况4,删除节点没有右孩子
return node.left
else: #情况5,删除的节点有左右孩子,则将其左子树放到右子树最左,然后用右孩子替代删除节点
cur = node.right
while cur.left:
cur = cur.left
cur.left = node.left
return node.right
if value < node.val:
node.left = self.dfs(node.left,value)
else:
node.right = self.dfs(node.right,value)
return node
心得体会
学习了BST的增删查,总体思路为由BST性质一路向下找到对应的节点,进行操作,然后返回上层合法的节点并用上层的指针域链接。
标签:node,return,val,self,Day20,value,二叉树,Part7,节点 From: https://www.cnblogs.com/haohaoscnblogs/p/18343139