天天看點

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