Tree真题

[骨骼清奇]n-array tree, 给一个node 算出包括这个node在内的所有child的sum
[骨骼清奇]n-array tree,给一个node 打印出从这node出发的所有path. 问了时间复杂度和空间复杂度。
[骨骼清奇]第一轮问了两题,第一题是一个数组,在某个位置前元素单调递增,然后单调递减,就是那种元素大小像山一样形状的数组,然后求最大最小值,用binary search做,然后第二题是比较二叉树是否相同,问了一下时间复杂度。

[骨骼清奇]Write a function to detect if two trees are isomorphic.
给定两颗树,判断它们是否有相同的shape.
follow up:如果允许树的节点拥有任意数目的父节点,如何判断?
Two trees are called isomorphic if one of them can be obtained from other by a series of flips, i.e. by swapping left and right children of a number of nodes. Any number of nodes at any level can have their children swapped. Two empty trees are isomorphic.

def isIsomorphic(n1, n2): 
    if n1 is None and n2 is None: 
        return True
  
    if n1 is None or n2 is None: 
        return False
  
    if n1.data != n2.data : 
        return False

    # Case 1: subtrees NOT  "Flipped". 
    # Case 2: subtrees "Flipped" 
    return ((isIsomorphic(n1.left, n2.left)and 
            isIsomorphic(n1.right, n2.right)) or
            (isIsomorphic(n1.left, n2.right) and 
            isIsomorphic(n1.right, n2.left)) 
            ) 

Time Complexity: The above solution does a traversal of both trees. So time complexity is O(m + n) where m and n are number of nodes in given trees.

Follow up: general tree?
If swap with either two siblings, then we can compare level by level using permutation of node values.

LC 226 Invert Binary Tree 二叉树的镜像(Symmetric Tree)
Recursion:

class Solution:
    def Mirror(self, root):
        if root == None:
            return 
        self.Mirror(root.left)
        self.Mirror(root.right)
        root.left,root.right = root.right,root.left

Iterative way:
The idea is that we need to swap the left and right child of all nodes in the tree. So we create a queue to store nodes whose left and right child have not been swapped yet. Initially, only the root is in the queue. As long as the queue is not empty, remove the next node from the queue, swap its children, and add the children to the queue. Null nodes are not added to the queue. Eventually, the queue will be empty and all the children swapped, and we return the original root.

class Solution:
    def invertTree(self, root):
        """
        :type root: TreeNode
        :rtype: TreeNode
        """
        if not root:
            return root
        level=[root]
        while level:
            for node in level:
                node.left,node.right = node.right,node.left
            level = [kid for node in level for kid in (node.left,node.right) if kid]
        return root

LC 102Binary Tree Level Order Traversal

class Solution:
    def levelOrder(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        if not root:
            return []
        ans,level = [],[root]
        while level:
            ans.append([node.val for node in level])
            level = [ kid for n in level for kid in (n.left,n.right) if kid]
        return ans

LC 105. Construct Binary Tree from Preorder and Inorder Traversal

class Solution:
    def buildTree(self, preorder, inorder):
        """
        :type preorder: List[int]
        :type inorder: List[int]
        :rtype: TreeNode
        """
        if inorder:
            root_ind = inorder.index(preorder.pop(0))
            root = TreeNode(inorder[root_ind])
            root.left = self.buildTree(preorder, inorder[0:root_ind])
            #preorder now only contains nodes in right sub-tree of root
            root.right = self.buildTree(preorder, inorder[root_ind+1:])
            return root

LC 106. Construct Binary Tree from Inorder and Postorder Traversal

class Solution:
    def buildTree(self, inorder, postorder):
        if inorder:
            root_ind = inorder.index(postorder.pop())
            root = TreeNode(inorder[root_ind])
            root.right = self.buildTree(inorder[root_ind+1:],postorder)
            root.left = self.buildTree(inorder[:root_ind],postorder)
            return root

[骨骼清奇] LC 96 Unique Binary Search Trees
转移关系:1到n中选定某个i作为root!

class Solution: #beat 100%
    def numTrees(self, n):
        """
        :type n: int
        :rtype: int
        """
        if n<1: return 0
        F = [0]*(n+1)
        F[0] = F[1] = 1
        for i in range(2,n+1):
            for j in range(i):
                F[i] += F[j]*F[i-j-1]
        return F[n]

LC95 unique binary search tree II
需要返回所有不同BST的根节点list. 用Recursion做。

class Solution:
    def generateTrees(self, n):
        """
        :type n: int
        :rtype: List[TreeNode]
        """
        def generate_trees(start, end):
            if start > end:
                return [None,]
            
            all_trees = []
            for i in range(start, end + 1):  # pick up a root
                # all possible left subtrees if i is choosen to be a root
                left_trees = generate_trees(start, i - 1)
                
                # all possible right subtrees if i is choosen to be a root
                right_trees = generate_trees(i + 1, end)
                
                # connect left and right subtrees to the root i
                for l in left_trees:
                    for r in right_trees:
                        current_tree = TreeNode(i)
                        current_tree.left = l
                        current_tree.right = r
                        all_trees.append(current_tree)
            
            return all_trees
        
        return generate_trees(1, n) if n else []

[骨骼清奇] LC 834 Sum of Distances in Tree
Input: N = 6, edges = [[0,1],[0,2],[2,3],[2,4],[2,5]]
Output: [8,12,6,10,10,10]
Nodes的数值是0-N-1,构成一颗树,ans[i]表示从i出发到其他所有nodes的edges数之和。ans[0] = 1+1+2+2+2 = 8
重点是找到关系edge AB在最终答案里的关系:ans[B] = ans[A] + Nodes_A - Nodes_B。因为AB是直接相连的,那么从B出发,对于以B为根节点的nodes而言,ans[A]里面每一个都多加了1,那个1就是edgeAB,因此要减掉Nodes_B。同样的,ans[A]还需要加上Nodes_A, 因为从B出发需要经过BA,而从A出发不用。

class Solution:
    def sumOfDistancesInTree(self, N, edges):
        """
        :type N: int
        :type edges: List[List[int]]
        :rtype: List[int]
        """
        graph = self.buildGraph(N,edges)
        seen = set()
        cnts = [1]*N
        dist = [0]*N
        self.dfs(graph,0,dist,cnts,seen)
        #dist[0] is the chosen root and it is answered now!
        seen = set() 
        self.dfs2(graph,0,dist,cnts,seen,N)
        return dist

    def buildGraph(self,N,edges):
        from collections import defaultdict
        graph = defaultdict(list)
        for i,j in edges:
            graph[i].append(j)
            graph[j].append(i)
        return graph


    def dfs(self,graph,i,dist,cnts,seen):
        seen.add(i)
        for j in graph[i]:
            if j in seen:continue
            self.dfs(graph,j,dist,cnts,seen)
            cnts[i] += cnts[j]
            dist[i] += dist[j] + cnts[j]
            #cnts[j] means node i is one edge further
 
    def dfs2(self,graph,i,dist,cnts,seen,n):
        seen.add(i)
        for j in graph[i]:
            if j in seen:continue
            dist[j] = dist[i] - cnts[j] + (n - cnts[j])
            self.dfs2(graph,j,dist,cnts,seen,n)

https://blog.csdn.net/tinkle181129/article/details/79326023

[Uber] LC 314 Binary Tree Vertical Order Traversal
分析:如何判断nodes属于同一层vertical Order?其实是相对于root这个symmetric axis的位置,只要turn right就加一,turn left减一,再把这个表示相对位置的Index放入一个hash table,然后按照index从小打到输出即可!

from collections import deque, defaultdict

class Solution(object):
    def verticalOrder(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        if not root:
            return []

        table = defaultdict(list)
        queue = deque()

        # put node and the level that it belongs to
        queue.append((root, 0))
        Gmin = Gmax = 0
        while queue:
            node, index = queue.popleft()
            if index<Gmin:Gmin = index
            if index>Gmax:Gmax = index
            table[index].append(node.val)

            if node.left:
                queue.append((node.left, index-1))

            if node.right:
                queue.append((node.right, index+1))

        # The keys of the table are the indices, sort it min to max
        # return [table[index] for index in sorted(table)]

        return [table[index] for index in range(Gmin,Gmax+1)]

LC 101 Symmetric Tree
Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).
General Tree:
left = arr[:len(arr)//2]
right = arr[:len(left):-1]

[骨骼清奇]考察二叉树,自己定义tree node,然后自己把二叉树各种遍历方法写一下,递归的和非递归的。

LC 94 Binary Tree Inorder Traversal
Recursion:

def inorderTraversal1(self, root):
    res = []
    self.helper(root, res)
    return res
    
def helper(self, root, res):
    if root:
        self.helper(root.left, res)
        res.append(root.val)
        self.helper(root.right, res)

Iterative (stack):从root出发,left child不停的入栈,直到遇到一个Node没有left child(可能是leaf也可能不是),这就是我们in-order traversal的第一站,然后以它的left child作为root,重复刚刚那一套流程。For each leaf, its left null child will help print the value of itself, and its null right child will help print the correspondent successor (could be an ancestor far above).

class Solution:
    def inorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        stk = []
        ans = []
        node = root    
        while (node is not None) or stk:  # empty lists are falsy
            if node is not None:
                stk.append(node)
                node = node.left
            else:
                node = stk.pop()
                ans.append(node.val)
                node = node.right
        return ans

LC 230 Kth Smallest Element in a BST

class Solution:

    def kthSmallest(self, root, k):
        self.k = k
        self.in_order(root)
        return self.result

    def in_order(self, node):
        if not node:
            return None
        self.in_order(node.left)
        self.k -= 1
        if self.k == 0:
            self.result=node.val
            return
        self.in_order(node.right)

Iterative:

class Solution:
    def kthSmallest(self, root, k):
        """
        :type root: TreeNode
        :type k: int
        :rtype: int
        """
        cnt,stack = 0,[]
        node = root
        while node is not None or stack:
            if node is not None:
                stack.append(node)
                node=node.left
            else:
                node=stack.pop()
                cnt += 1
                if cnt==k: return node.val
                node=node.right

LC 144 Binary Tree Preorder Traversal
Beat 100%

class Solution:
    def preorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        ans,stack = [],[]
        node = root
        while node is not None or stack:
            if node is not None:
                ans.append(node.val)
                #get value before going to children
                stack.append(node)
                node = node.left
            else:
                node = stack.pop()
                node=node.right
        return ans

LC 145 Binary Tree Postorder Traversal

class Solution:
    def postorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """

        ans,stack = [],[]
        node = root
        while node is not None or stack:
            if node is not None:
                #ans.insert(0,node.val) #reverse preorder
                ans.append(node.val)
                stack.append(node)
                node = node.right #reverse preorder
            else:
                node = stack.pop()
                node = node.left #reverse preorder
        return ans[::-1]

[Uber]LC 450 Delete Node in a BST

1.When found the node, put right child of the node to the right of [the right most leaf node of left child][max value of left sub-tree but still smaller then any value in right sub tree]. That way the values are still in order.
2.Return the left child of the node(skip root, a.k.a delete it). If the node doesn't have left child, return right child.
3.Otherwise do binary search. If key < root.val, change left child to the returned new root. Do right child if key > root.val.

This solution always runs in O(log(n)) time since when it finds the node to delete, it goes to the right most leaf of the left sub-tree to put right sub-tree of the node there.

Modify and not return any node in recursion, beat 100%!

class Solution:
    def deleteNode(self, root, key):
        dummy = TreeNode(float('INF'))
        dummy.left = root
        self.replace(dummy,root,key)
        return dummy.left

    def replace(self,prev,cur,key):
        if not cur: return
        if cur.val<key:
            self.replace(cur,cur.right,key)
        elif cur.val>key:
            self.replace(cur,cur.left,key)
        else:#FOUND
            if cur.left:
                left_right_most = cur.left
                while left_right_most.right:
                    left_right_most = left_right_most.right
                left_right_most.right=cur.right
            
            if prev.val<key:
                prev.right = cur.left or cur.right
            else:
                prev.left = cur.left or cur.right

Slower Version without prev

class Solution(object):
    def deleteNode(self, root, key):
        if not root: return None
        
        if root.val == key:
            if root.left:
                # Find the right most leaf of the left sub-tree
                left_right_most = root.left
                while left_right_most.right:
                    left_right_most = left_right_most.right
                # Attach right child to the right of that leaf
                left_right_most.right = root.right
                # Return left child instead of root, a.k.a delete root
                return root.left
            else:
                return root.right
        # If left or right child got deleted, the returned root is the child of the deleted node.
        elif root.val > key:
            root.left = self.deleteNode(root.left, key)
        else:
            root.right = self.deleteNode(root.right, key)
            
        return root

[GoogleCall]Delete Treenode, all are put in an array. parent 0 has children 1 and 2.

LC 428 N-ary tree

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • rljs by sennchi Timeline of History Part One The Cognitiv...
    sennchi阅读 7,279评论 0 10
  • 时间总是感觉一转眼,每天早早起床做早餐,无论一家人持多少,总是希望孩子的记忆中一直有妈妈做早餐的情景,记住妈妈做饭...
    俩宝的妈咪阅读 114评论 0 0
  • 《孙子兵法》第二篇作战篇核心思想是速战。 孙子的逻辑顺序,先是庙算、“五事七计”,看有没有胜算。胜算在握,决定打了...
    潘武阅读 1,403评论 0 3
  • 姓名:潘亚平 公司:福建起步儿童用品有限公司 日精进打卡第59天 【知~学习】 《六项精进》2遍共60遍 《大学》...
    徒手敬岁月_114e阅读 83评论 0 0
  • 旧文新发呀,去年关于内存结构分析的学习笔记,今年再看清楚了很多,发粗来~ 1. 堆、栈、池 首先来段代码: 可以发...
    公子七阅读 925评论 2 4