[Leetcode]二叉树&二叉搜索树——python版本

本篇文章根据labuladong的算法小抄汇总二叉树与二叉搜索树的常见算法,采用python3实现

二叉树

翻转二叉树

class TreeNode:
    def __init__(self,val=0,left=None,right=None):
        self.val = val
        self.left = left
        self.right = right
class Solution:
    def invertTree(self,root):
        if root is None:
            return None
        tmp = root.left
        root.left = root.right
        root.right = tmp
        self.invertTree(root.left)
        self.invertTree(root.right)
        return root

填充二叉树节点的右侧指针

def connect(root):
    if root is None:
        return None
    connectTwoNode(root.left,root.right)
    return root
def connectTwoNode(node1,node2):
    if (node1 is None) or (node2 is None):
        return
    node1.next = node2
    connectTwoNode(node1.left,node1.right)
    connectTwoNode(node2.left,node2.right)
    connectTwoNode(node1.right,node2.left)

二叉树展开为链表

def flatten(root):
    if root is None:
        return None
    flatten(root.left)
    flatten(root.right)
    left = root.left
    right = root.right
    root.left = None
    root.right = left
    p = root
    while p.right is not None:
        p = p.right
    p.right = right

构造最大二叉树

#超过递归深度
def constructMaximumBinaryTree(nums):
    return build(nums, 0, nums.length - 1)
def build(nums, lo , hi):
    if lo > hi:
        return None
    index = -1
    maxVal = float("-inf")
    for i in range(lo,hi+1):
        if maxVal < nums[i]:
            maxVal = nums[i]
            index = i
            
    root = TreeNode(maxVal)
    root.left = build(nums,lo,index-1)
    root.right = build(nums,index+1,hi)
    return root

通过前序和中序遍历结果构造二叉树

def buildTree(preorder,inorder):
    return build(preorder,0,len(preorder)-1,inorder,0,len(inorder)-1)
def build(preorder,preStart,preEnd,inorder,inStart,inEnd):
    if preStart > preEnd:
        return None
    rootVal = preorder[preStart]
    index = 0
    for i in range(inStart,inEnd+1):
        if inorder[i] == rootVal:
            index = i
            break
    root = TreeNode(rootVal)
    leftSize = index - inStart
    root.left = build(preorder,preStart+1,preStart+leftSize,inorder,inStart,index-1)
    root.right = build(preorder,preStart+leftSize+1,preEnd,inorder,index+1,inEnd)
    return root

通过中序和后序遍历结果构造二叉树

class TreeNode:
    def __init__(self,val=0,left=None,right=None):
        self.val = val
        self.left = left
        self.right = right
def buildTree(inorder,postorder):
    def build(inorder,instart,inend,postorder,poststart,postend):
        if instart > inend:
            return None
        rootValue = postorder[postend]
        for i in range(instart,inend+1):
            if inorder[i] == rootValue:
                index = i
                break
        root = TreeNode(rootValue)
        leftSize = index-instart
        root.left = build(inorder,instart,index-1,postorder,poststart,poststart+leftSize-1)
        root.right = build(inorder,index+1,inend,postorder,poststart+leftSize,postend-1)
        return root
    return build(inorder,0,len(inorder)-1,postorder,0,len(postorder)-1)

寻找重复子树

class treeNode():
    def __init__(self,val=0,left=None,right=None):
        self.val = val
        self.left = left
        self.right = right
class Solution:
    def findDuplicateSubtrees(self, root: Optional[TreeNode]) -> ist[Optional[TreeNode]]:
        def traverse(root):
            if root is None:
                return None
            left = traverse(root.left)
            right = traverse(root.right)
            subTree = str(left) + "," + str(right)+ "," + str(root.val)
            fre = subTree_fre.setdefault(subTree,0)
            if fre == 1:
                res.append(root)
            subTree_fre[subTree] = fre + 1
            return subTree
        res = []
        subTree_fre = dict()
        traverse(root)
        return res

二叉树的序列化与反序列化

前序遍历

class Codec:
    def serialize(self,root):
        if root is None:
            return "None"
        return str(root.val)+","+str(self.serialize(root.left))+","+str(self.serialize(root.right))
    def deserialize(self,data):
        def dfs(datalist):
            data = datalist.pop(0)
            if data == "None":
                return None
            root = TreeNode(int(data))
            root.left = dfs(datalist)
            root.right = dfs(datalist)
            return root
        datalist = data.split(",")
        return dfs(datalist)
  • 中序遍历无法实现反序列化

层级遍历

class Codec:
    def serialize(self,root):
        if root is None:
            return ""
        queue = collections.deque([root])
        res = []
        while queue:
            node = queue.popleft()
            if node is None:
                res.append("None")
               	continue
            res.append(str(node.val))
            queue.append(node.left)
            queue.append(node.right)
        return ",".join(res)
    def deserialize(self,data):
        if not data:
            return []
        dataList = data.split(",")
        root = TreeNode(int(dataList[0]))
        queue = collections.deque(root)
        i = 1
        while queue:
            node = queue.popleft()
            if dataList[i] != "None":
                node.left = TreeNode(int(dataList[i]))
                queue.append(node.left)
            i += 1
            if dataList[i] != "None":
                node.right = TreeNode(int(data))
                queue.append(node.right)
            i += 1
        return root
        
                

扁平化嵌套列表迭代器

class NestedIterator:
    def __init__(self,nestedList):
        self.q = collections.deque()
        self.dfs(nestedList)
    def dfs(self,nestedList):
        for elem in nestedList:
            if elem.isInteger():
                self.q.append(elem.getInteger())
            else:
                self.dfs(elem.getList())
    def next(self):
        return self.q.popleft()
    def hasNext(self):
        return len(self.q)

二叉树的最近公共祖先LCA

def lowestCommonAncestor(root,p,q):
    if root is None:
        return None
    if (root == p) or (root == q):
        return root
    left = lowestCommonAncestor(root.left,p,q)
    right = lowestCommonAncestor(root.right,p,q)
    if (left is not None) and (right is not None):
        return root
    if (left is None) and (right is None):
        return None
    return right if left is None else left

完全二叉树的节点个数

完全二叉树:

[Leetcode]二叉树&二叉搜索树——python版本_第1张图片

满二叉树:

[Leetcode]二叉树&二叉搜索树——python版本_第2张图片
#普通二叉树,时间复杂度O(N)
def countNodes(root):
    if root is None:
        return 0
    return 1 + countNodes(root.left) + countNodes(root.right)
#满二叉树,节点总数和树的高度呈指数关系
def countNodes(root):
    h = 0
    while root:
        root = root.left
        h += 1
    return pow(2,h) - 1
#完全二叉树,时间复杂度O(logN*logN)
def countNodes(root):
    if root is None:
        return 0
    l = root
    r = root
    hl = 0
    hr = 0
    while l:
        l = l.left
        hl += 1
    while r:
        r = r.right
        hr += 1
    if hl == hr:
        return pow(2,hl) - 1
    return 1 + countNodes(root.left) + countNodes(root.right)
  • 由于完全二叉树的性质,其子树一定有一棵是满的

递归改迭代

stk = collections.deque()
#左侧遍历到底,存入栈
def pushLeftBranch(p):
    while p:
        #前序遍历代码位置
        stk.append(p)
        p = p.left
def traverse(root):
    visited = TreeNode(-1) #指向上一次遍历完的子树根节点
    pushLeftBranch(root)
    while stk:
        p = stk[-1]
        if ((p.left is None) or (p.left == visited)) and (p.right != visited):
            #中序遍历代码位置
            pushLeftBranch(p.right)
        if (p.right is None) or (p.right == visited):
            #后序遍历代码位置
            visited = stk.pop(-1)
  • 除了BFS层级遍历外,二叉树还是用递归,因为递归最符合二叉树结构他点

二叉搜索树(BST)

  • BST特点:

    1、对于BST的每个节点node,左子树节点的值 < node的值 < 右子树节点的值

    2、对于BST的每个节点node,左子树和右子树都是BST

    3、BST的中序遍历结果是有序的(升序)

寻找第K小的元素

class Solution:
    def kthSmallest(self, root: Optional[TreeNode], k: int) -> int:
        self.res = 0
        self.rank = 0
        self.traverse(root,k)
        return self.res
    
    def traverse(self,root,k):
        if root is None:
            return None
        self.traverse(root.left,k)
        self.rank += 1
        if self.rank == k:
            self.res = root.val
            return
        self.traverse(root.right,k)

BST转化累加树

class Solution():
    def convertTree(root):
        def convert(root):
            if root is None:
                return None
            convert(root.right)
            self.sum += root.val
            root.val = self.sum
            convert(root.left)
        self.sum = 0
        convert(root)
        return root

判断BST合法性

def isValidBST(root):
    return isValidBST(root,None,None)
def isValidBST(root,min,max):
    if root is None:
        return True
    if min is not None and root.val <= min.val:
        return False
    if max is not None and root.val >= max.val:
        return False
    return isValidBST(root.left,min,root) and isValidBST(root.right,root,max)    

在BST中搜索元素

def search(root,val):
    if root is None:
        return None
    if val > root.val:
        return search(root.right,val)
    if val < root.val:
        return search(root.left,val)
    return root

在BST中插入一个数

def insertIntoBST(root,val):
    if root is None:
        return TreeNode(val)
    if val > root.val:
        root.right = insertIntoBST(root.right,val)
    if val < root.val:
        root.left = insertIntoBST(root.left,val)
    return root

在BST中删除一个数

class Solution:
    def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
        def getMin(root):
            while root.left is not None:
                root = root.left
            return root
        if root is None:
            return None
        if root.val == key:
            if root.left is None:
                return root.right
            elif root.right is None:
                return root.left
            minNode = getMin(root.right)
            minNode.left = root.left
            minNode.right = root.right
            root = minNode
        elif root.val < key:
            self.deleteNode(root.right,key)
        else:
            self.deleteNode(root.left,key)
        return root

不同的二叉搜索树

class Solution:
    def numTrees(self, n: int) -> int:
        memo = [[0 for i in range(n+1)] for j in range(n+1)]
        return count(1,n,memo)
def count(lo,hi,memo):
    if lo > hi:
        return 1
    if memo[lo][hi] != 0:
        return memo[lo][hi]
    res = 0
    for i in range(lo,hi+1):
        left = count(lo,i-1,memo)
        right = count(i+1,hi,memo)
        res += left * right
    memo[lo][hi] = res
    return res

不同的二叉搜索树②

def generateTrees(n):
    if n == 0:
        return TreeNode()
    return build(1,n)
def build(lo,hi):
    res = []
    if lo > hi:
        return r[None]
    for i in range(lo,hi+1):
        leftTree = build(lo,i-1)
        rightTree = build(i+1,hi)
        for left in leftTree:
            for right in rightTree:
                root = TreeNode(i)
                root.left = left
                root.right = right
                res.append(root)
    return res

二叉搜索子树的最大键值和

import sys
sum = 0
def maxSumBST(root):
	traverse(root)
    return maxSum
def traverse(root): #返回[isBST,min,max,sum]
    if root is None:
        return [1,sys.maxsize,-sys.maxsize-1,0]
    left = traverse(root.left)
    right = traverse(root.right)
    res = [0 for i in range(4)]
    if (left[0] == 1) and (right[0] == 1) and (left[2] < root.val < right[1]):
        #以root为根的二叉树是BST
        res[0] = 1
        res[1] = min(left[1],root.val)
        res[2] = max(right[2],root.val)
        res[3] = left[3] + right[3] + root.val
        maxSum = max(maxSum,res[3])
    else:
        res[0] = 0
    return res
  • BST相关问题:(1)利用BST左小右大的特性提升算法效率;(2)中序遍历的特性(有序)满足题目要求
  • 如果当前节点要做的事情需要通过左右子树的计算结果推导出来,就要用到后序遍历
  • 要尽可能避免递归函数中调用其他递归函数

你可能感兴趣的:(leetcode刷题笔记,leetcode,算法,二叉树,python,数据结构)