二叉树篇
98. 验证二叉搜索树
-
思路1:对二叉树进行中序遍历,如果是二叉树搜索树 自然遍历序列是升序的。因此采取数组保存中序遍历结果,如果前一个元素大于等于后面一个元素 则返回False
思路2:对二叉树进行中序遍历,如果是二叉树搜索树 自然遍历序列是升序的。采取一个成员变量preVal遍历记录上一次中序遍历的结果,然后与当前值比较即可
# 思路1
class Solution(object):
def __init__(self):
self.nums = []
def isValidBST(self, root):
self.dfs(root)
for i in range(len(self.nums)-1):
if self.nums[i]>=self.nums[i+1]:
return False
return True
def dfs(self,root):
if not root: return
self.dfs(root.left)
self.nums.append(root.val)
self.dfs(root.right)
# 思路2
class Solution(object):
def __init__(self):
self.preVal = -pow(2,31)-1
def isValidBST(self, root):
return self.dfs(root)
def dfs(self,root):
if not root: return True
a = self.dfs(root.left)
if self.preVal>=root.val:
return False
self.preVal = root.val
b = self.dfs(root.right)
return a and b
总结:中序遍历的递归写法 可更改成 借助显示栈的迭代写法!
36. 二叉搜索树与双向链表
- 思路1:引入哨兵节点,对二叉搜索树进行中序遍历,且用preNode记录中序遍历的上一个节点,然后preNode节点与当前节点相互连接即可
class Solution(object):
def __init__(self):
self.preNode = None
def treeToDoublyList(self, root):
if not root: return None
auxi = TreeNode(0,None,root)
self.preNode = auxi
self.dfs(root)
auxi.right.left = self.preNode
self.preNode.right = auxi.right
return auxi.right
def dfs(self,root):
if not root: return
self.dfs(root.left)
root.left = self.preNode
self.preNode.right = root
self.preNode = root
self.dfs(root.right)
68 - I. 二叉搜索树的最近公共祖先
- 思路1:采取迭代的思路,由于是二叉搜索树,所以当前节点值同时大于p,q节点值 当前节点就更新到其左孩子,其他情况类似分析
class Solution(object):
def lowestCommonAncestor(self, root, p, q):
cur = root
while cur:
if cur.val > p.val and cur.val > q.val:
cur = cur.left
elif cur.val < p.val and cur.val < q.val:
cur = cur.right
else:
return cur
236. 二叉树的最近公共祖先
- 思路1:通过后续遍历 找到后代节点后再去寻找祖先(如果root为p和q,root可能是祖先 当root左子树和右子树同时包含后代节点时 需要将结果更新为 当前root)
class Solution(object):
def __init__(self):
self.ret = TreeNode(0)
def lowestCommonAncestor(self, root, p, q):
self.dfs(root,p,q)
return self.ret
def dfs(self,root,p,q):
# 只有先访问了 两个儿子节点 才能知道祖先是谁 所以需要后续遍历
if not root:
return False
if root == p or root == q:
self.ret = root
return True
a = self.dfs(root.left,p,q)
b = self.dfs(root.right,p,q)
if a and b:
self.ret = root
return a or b
105. 从前序与中序遍历序列构造二叉树
- 思路1:根据前序遍历的根节点位置,找到中序遍历对应的下标,即可将数组分成 左子树的先序遍历和中序遍历,右子树的先序遍历和中序遍历 递归构造即可
class Solution(object):
def buildTree(self, preorder, inorder):
root = self.dfs(preorder,inorder)
return root
def dfs(self,preorder,inorder):
if not preorder: return None
index = inorder.index(preorder[0])
tmp = TreeNode(preorder[0])
tmp.left = self.dfs(preorder[1:index+1],inorder[:index])
tmp.right = self.dfs(preorder[index+1:],inorder[index+1:])
return tmp
33. 二叉搜索树的后序遍历序列
- 思路1:遇到二叉树+数组,基本都是递归+双指针的思想。后续遍历的最后一个节点是子树的根节点,二叉搜索树左子树值均小于根节点值,右子树值均大于根节点值,只需根据根节点找到右子树后续遍历起始节点,如果后面出现小于根节点的,即不为后续遍历序列
class Solution(object):
def verifyPostorder(self, postorder):
i,j = 0,len(postorder)-1
return self.dfs(postorder,i,j)
def dfs(self,postorder,i,j):
if i>=j: return True
mid = i
while postorder[mid]<postorder[j]:
mid += 1
cur = mid
while cur<=j:
if postorder[cur]<postorder[j]:
return False
cur += 1
a = self.dfs(postorder,i,mid-1) # 左子树
b = self.dfs(postorder,mid,j-1) # 右子树
return a and b
450. 删除二叉搜索树中的节点
- 思路1:引入哨兵节点,因为可能删除根节点。去遍历二叉搜索,查找key的节点,过程中记录pre(前一个)和cur(当前)节点,然后根据不同情况,删除节点 对剩下节点合理连接,并保留二叉树的性质即可
class Solution(object):
def deleteNode(self, root, key):
if not root: return None
auxi = TreeNode(0,root,None); # 哨兵节点
pre,cur = auxi,root
while True:
if cur.val == key: break
pre = cur
if key < cur.val: cur = cur.left
elif key > cur.val: cur = cur.right
if not cur: break
if not cur: return auxi.left # 找不到删除的节点
if not cur.left:
if pre.left == cur: pre.left = cur.right
if pre.right == cur: pre.right = cur.right
elif not cur.right:
if pre.left == cur: pre.left = cur.left
if pre.right == cur: pre.right = cur.left
else:
tmp = cur.left
while tmp.right:
tmp = tmp.right
tmp.right = cur.right
if pre.left == cur: pre.left = cur.left
if pre.right == cur: pre.right = cur.left
return auxi.left