天天看点

LeetCode-树-Hard

记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步

目录

      • 297. Serialize and Deserialize Binary Tree 二叉树的序列化与反序列化
      • 685. Redundant Connection II 冗余连接 II
      • 834. Sum of Distances in Tree 树中距离之和
      • 968. Binary Tree Cameras 监控二叉树
      • 1028. Recover a Tree From Preorder Traversal 从先序遍历还原二叉树

297. Serialize and Deserialize Binary Tree 二叉树的序列化与反序列化

序列化 反序列化 都使用list来存放node

反序列化注意list范围

class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Codec:

    def serialize(self, root):
        """Encodes a tree to a single string.
        
        :type root: TreeNode
        :rtype: str
        """
        l=[root]
        ret=[]
        while len(l)>0:
            tmp = l.pop(0)
            if tmp==None:
                ret.append("null")
                continue
            ret.append(tmp.val)
            left,right = tmp.left,tmp.right
            l.append(left)
            l.append(right)
        for i in range(len(ret)-1,-1,-1):
            if ret[i]!="null":
                return ret[:i+1]
            
        

    def deserialize(self, data):
        """Decodes your encoded data to tree.
        
        :type data: str
        :rtype: TreeNode
        """
        if not data:
            return
        root = TreeNode(data[0])
        l = [root]
        i=1
        while len(l)>0:
            tmp = l.pop(0)
            if tmp==None or i>=len(data):
                continue
            tmp.left = None if data[i]=="null" else TreeNode(data[i])
            if i+1<len(data):
                tmp.right = None if data[i+1]=="null" else TreeNode(data[i+1])
            else:
                tmp.right = None
            i+=2
            l.append(tmp.left)
            l.append(tmp.right)
        
        return root
           

685. Redundant Connection II 冗余连接 II

check用来检查是否满足

1.入度不能有大于1的

2.不能存在圈

先将所有点的父节点取出,如果存在有两个父节点 那么说明这个节点需要取出一条边 遍历后check是否正确 若正确 将结果暂存ret

判断ret,

若ret内有多个 则取出位置最靠后的作为结果

若ret==0:

所有节点入度都正常 说明存在圈 从后往前去除一个点 check是否正常 若正常则答案为这个点

def findRedundantDirectedConnection(edges):
    """
    :type edges: List[List[int]]
    :rtype: List[int]
    """
    dic={}
    ans=[]
    ret =[]
    def check(l):
        #入度不能大于1
        endpoint = [y for x,y in l]
        if len(endpoint)!=len(set(endpoint)):
            return False

        def find(p,x):
            while p[x] != x:
                p[x] = p[p[x]]
                x = p[x]
            return p[x]

        # 判断给定的图是不是有圈
        def cycle(graph):
            p = {}
            for a, b in graph:
                p.setdefault(a, a)
                p.setdefault(b, b)
                pa, pb = find(p, a), find(p, b)
                if pa == pb: 
                    return(True)
                else:
                    p[pa] = p[pb]
                    
        if cycle(l):
            return False
            
        return True
    
    for v in edges:
        top = v[0]
        end = v[1]
        dic.setdefault(end,[])
        dic[end].append(top)
            
    for k in dic.keys():
        if len(dic[k])>1:
            for v in dic[k]:
                ori = edges[:]
                tmp=[v,k]
                ori.pop(ori.index(tmp))
                if check(ori):
                    ret.append(tmp)
    
    if len(ret)==0:
        for i in range(len(edges)-1,-1,-1):
            ori = edges[:]
            ori.pop(i)
            if check(ori):
                ans = edges[i]
                break
    else:
        pos = -1
        for i in ret:
            if edges.index(i)>pos:
                pos = edges.index(i)
                ans = i    
    
    return ans
    


def find(p,x):
    while p[x] != x:
        p[x] = p[p[x]]
        x = p[x]
    return p[x]
        # 判断给定的图是不是有圈
def cycle(graph):
    p = {}
    for a, b in graph:
       
        p.setdefault(a, a)
        p.setdefault(b, b)
        pa, pb = find(p, a), find(p, b)
        print([a,b],p,pa,pb)
        if pa == pb: 
            return(True)
        else:
            p[pa] = p[pb]
           

834. Sum of Distances in Tree 树中距离之和

使用count[n]记录某一节点n的子节点包含自己

使用res[n]记录节点n到各个不同节点的距离

若有[a,b] a为根节点 b为子节点

求根节点a时:

对于count的计算:

count[a]+=count[b]

对于res的计算:

b的所有节点count(b)从b到a 距离都增加了1 所以从b到a总共增加了count(b)*1

res[a] += res[b]+count[b]

求子节点b时:

对于res的计算:

同样从a到b有count[b]个节点距离减少了1 而有N-count[b]个节点距离增加了1

所以:

res[b] = res[a]- count[b] + (N-count[b])

def sumOfDistancesInTree(N, edges):
    """
    :type N: int
    :type edges: List[List[int]]
    :rtype: List[int]
    """
    from collections import defaultdict
    tree = defaultdict(set)
    for x,y in edges:
        tree[x].add(y)
        tree[y].add(x)
    
    count = [1 for i in range(N)]
    ret = [0 for i in range(N)]
        
    def dfs(root,visit):
        visit.add(root)
        for i in tree[root]:
            if i not in visit:
                dfs(i,visit)
                count[root] += count[i]
                ret[root] += ret[i] + count[i]
                
    def dfs2(root,visit):
        visit.add(root)
        for i in tree[root]:
            if i not in visit:
                ret[i] = ret[root]-count[i]+N-count[i]
                dfs2(i,visit)
    dfs(0,set())
    dfs2(0,set())
    return ret
           

968. Binary Tree Cameras 监控二叉树

每个节点有三种状态:

1:可以观察到

2:不可以观察到

3:安装了摄像头

对树进行dfs从叶节点开始往上分析

若节点的左右节点存在不可观测到的点(2) 则该节点需要安装摄像头 ret+=1 返回该节点的状态3

若节点的左右节点存在安装摄像头的点(3) 则该节点可以被观察到 返回状态1

否则 该节点无法被观察到 返回 2

对根节点开始分析dfs(root) 返回根节点的状态 如果这个状态==2 则需要在root上安装 ret+=1

class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None
def minCameraCover(root):
    """
    :type root: TreeNode
    :rtype: int
    """
    ret = 0
    
    def dfs(node):
        if not node:
            return 1
        left,right = dfs(node.left),dfs(node.right)
        if left==2 or right==2:
            ret=ret+1
            return 3
        elif left==3 or right==3:
            return 1
        else:
            return 2
    if dfs(root)==2:
        ret+=1
    return ret
           

1028. Recover a Tree From Preorder Traversal 从先序遍历还原二叉树

1.递归

check:

用来返回“-”的个数ans 以及这个数值v ans就是这个v应该在的层数level

do:

用来添加节点

如果节点的dot=ans 及应该在的层数与目前的层数level相等 则生成tmp节点

这个是该node节点的左子节点

再对这个左节点进行分析

do 返回生成的节点 以及该节点的层数tmpdot

若tmpdot与level相等 则该节点为node的右节点

否则 将节点tmp 以及其层数tmpdot 返回

2.使用stack解题

先对S进行初步处理:

在list中存放(x,level) x为值 level表示这个值应该在的层数

遍历list:

对于节点node stack内存放node上层的节点 若存在层数与node相同或更下层的 则这些节点将不会再使用到 pop出stack中

此时 stack中的末节点及该node节点的父节点 parent

若parent已有左节点 则node放至右边 否则 node为左节点

class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution(object):
    def recoverFromPreorder(self,S):
        """
        :type S: str
        :rtype: TreeNode
        """
        self.S=S
        
        def check():
            ans = 0
            v=""
            if len(self.S)==0:
                return 0,0
            while self.S[0]=="-":
                ans+=1
                self.S = self.S[1:]
            
            while len(self.S)>0 and self.S[0]!="-":
                v += self.S[0]
                self.S = self.S[1:]
            return ans,v
        
        if self.S[0]=="-":
            return 
        v=""
        while len(self.S)>0 and self.S[0]!="-":
            v += self.S[0]
            self.S = self.S[1:]
        root = TreeNode(v)
        if len(self.S)==0:
            return root
        self.S=self.S[1:]
        
        def do(node,level):
            dot,v = check()
            print("40",dot,v,level)
            tmp = TreeNode(v)
            if dot==level:
                node.left =tmp
                tmp,tmpdot = do(node.left,level+1)
                print(tmpdot,tmp.val,level)
                if tmpdot==level:
                    node.right = tmp
                    tmp,tmpdot = do(node.right,level+1)
                return tmp,tmpdot
            return tmp,dot 
            
        do(root,1)
        return root
    
    def recoverFromPreorder2(self,S):
        """
        :type S: str
        :rtype: TreeNode
        """
        s = S.split('-')
        level = 0
        l = list()
        for x in s:
            if x:
                l.append((x, level))
                level = 1
            else:
                level += 1
        root = TreeNode(None)
        stack = [(root,-1)]
        for value, depth in l:
            while depth <= stack[-1][1]:
                stack.pop()
            node = TreeNode(value)
            parent = stack[-1][0]
            stack.append((node, depth))
            if parent.left:
                parent.right = node
            else:
                parent.left = node
        return root.left