zoukankan      html  css  js  c++  java
  • 边工作边刷题:70天一遍leetcode: day 103

    这两天开始重温leetcode经典题,发现再回过头来看很多问题都会有新的心得体会,leetcode的题真是要多过几遍才能融会贯通

    Symmetric Tree Problem

    这题是道easy题 (曾经linkedin电面时候秒过),但是如果没想清楚只背下题很快就会忘了。下面是题解的code (java)

    • 基本的思路是递归配对。之所以可以用递归的方法是因为镜面对称的二叉树任意配对的node的left和right children是镜面对称的。这个条件可以作为invariant对整个树遍历。递归的基点是当前层两个已经配对的node,recurive function要以两个node的左右children作为参数
    • 对于两个node的比较一共有4种情况,both not null, both null, only left null, only right null. 只有前两种case才有可能true (都不为null还要比较value)
    • 递归里还是递归外?当前两个待比较node在递归里,只有两个node都不为null。才找对称点blindly进下一层

    几乎完全一样code结构的还有Same Tree,不过因为两棵树,递归好想多了

    # Definition for a binary tree node.
    # class TreeNode(object):
    #     def __init__(self, x):
    #         self.val = x
    #         self.left = None
    #         self.right = None
    
    class Solution(object):
        def isSymmetric(self, root):
            """
            :type root: TreeNode
            :rtype: bool
            """
            def symmetric(left, right):
                if not left and not right:
                    return True
                    
                if not left or not right:
                    return False
                    
                if left.val!=right.val:
                    return False
                
                return symmetric(left.left, right.right) and symmetric(left.right, right.left)
            
            if not root: return True
            return symmetric(root.left, root.right)
    

    Binary Tree Level Order Traversal

    基本题中的基本,这题的衍生题leetcode上就有一坨(比如臭名昭著的word laddar II),用bfs很直观,也可以用dfs。另外注意bfs有至少三种方式:2个queue,用一个queue+2个counter,一个queue+delimiter。曾经在亚麻的面试中被要求搞了三种。dfs看似效率不高,但是时间复杂度实际和bfs是一样的(O(n))。也要会,目测有衍生题会考这个点(隐约记得看过一个狗家的面经上有)

    注意现在要求做到bug-free,有巨量的问题是有关循环的边界case是不是要额外处理。以2 counters的bfs为例,code里采用了前置循环,就是说起始值在循环外初始化(cur=1,root node入queue)。queue不为空,继续遍历当前层同时将下一层入queue。每一步出queue后检查是否当前层已经遍历结束来重置counter

    # Definition for a binary tree node.
    # class TreeNode(object):
    #     def __init__(self, x):
    #         self.val = x
    #         self.left = None
    #         self.right = None
    
    class Solution(object):
        def levelOrder(self, root):
            """
            :type root: TreeNode
            :rtype: List[List[int]]
            """
            res = []
            if not root: return res
            q = []
            q.append(root)
            curr = 1
            while q:
                next = 0
                res.append([])
                for i in range(curr):
                    cur = q.pop(0)
                    res[-1].append(cur.val)
                    if cur.left:
                        q.append(cur.left)
                        next+=1
                    if cur.right:
                        q.append(cur.right)
                        next+=1
                
                curr = next
            
            return res
    
    

    Binary Tree Zigzag Level Order Traversal

    算法结构类似level order traversal,根据题意下一层和当前层的遍历顺序是相反的,所以在展开阶段要顺序push下一层到stack里,这样下一层出栈的顺序就反过来了。另外,展开当前node是左到右还是右到左是每层交替的,所以要用一个变量来track。
    错误点

    • reverse是如何定的?因为reverse决定的是push的顺序。所以当前层如果是从左到右访问,那么下一层是从右向左(reverse),但是出stack的方向是反的,综上,reverse是False
    • 这题因为是stack,所以不能用2层公用一个stack counting的方法做level traversal,必须用两个stack
    # Definition for a binary tree node.
    # class TreeNode(object):
    #     def __init__(self, x):
    #         self.val = x
    #         self.left = None
    #         self.right = None
    
    class Solution(object):
        def zigzagLevelOrder(self, root):
            """
            :type root: TreeNode
            :rtype: List[List[int]]
            """
            res = []
            if not root: return res
            reverse = False
            stk = []
            stk.append(root)
            curr = 1
            while stk:
                next = []
                res.append([])
                while stk:
                    cur = stk.pop()
                    res[-1].append(cur.val)
                    if reverse:
                        if cur.right:
                            next.append(cur.right)
                        if cur.left:
                            next.append(cur.left)
                    else:
                        if cur.left:
                            next.append(cur.left)
                        if cur.right:
                            next.append(cur.right)
                reverse = not reverse
                stk = next
            return res
    

    Maximum Depth of Binary Tree

    简单一题,但是递归结构可以用在很多Binary Tree的题目上(比如LCA):递归左右子树,然后比较左右返回结果取一返回

     # Definition for a binary tree node.
    # class TreeNode(object):
    #     def __init__(self, x):
    #         self.val = x
    #         self.left = None
    #         self.right = None
    
    class Solution(object):
        def maxDepth(self, root):
            """
            :type root: TreeNode
            :rtype: int
            """
            def depth(root):
                if not root: return 0
                return 1+max(depth(root.left), depth(root.right))
                
            return depth(root)
    

    Construct Binary Tree from Preorder and Inorder Traversal

    Construct Binary Tree from Inorder and Postorder Traversal

    这两道题都是一个思路,比较tricky。以preorder/inorder为例,对于preorder遍历,一个子树对应一个连续的子数组,而首个元素就是root。问题就变成如何在子数组中进一步确定左右子树的边界,这样就可以进一步递归构建左右子树。inorder的序列可以用来找到边界:具体来说,因为无论是inorder还是preorder,子树都是数组中连续的元素,inorder的左右子树的分界点在root,这样如果能找到root的index,就能确定左子树的大小,进而确定在preorder序列里左子树的大小。这就是为什么我们要提前做invert index来存储value到index的map。而offset是用来跟踪当前在inorder序列里的左边界。

    # Definition for a binary tree node.
    # class TreeNode(object):
    #     def __init__(self, x):
    #         self.val = x
    #         self.left = None
    #         self.right = None
    
    class Solution(object):
        def buildTree(self, preorder, inorder):
            """
            :type preorder: List[int]
            :type inorder: List[int]
            :rtype: TreeNode
            """
            def build(inmap, preorder, low, high, offset):
                if low>high: return None
                rootVal = preorder[low]
                m = inmap[rootVal]-offset
                root = TreeNode(rootVal)
                root.left = build(inmap, preorder, low+1, low+m, offset)
                root.right = build(inmap, preorder, low+m+1, high, offset+m+1)
                return root
                
            inmap = {}
            for i in xrange(len(inorder)):
                inmap[inorder[i]]=i
                
            return build(inmap, preorder, 0, len(preorder)-1, 0)```
    
    
    

    Definition for a binary tree node.

    class TreeNode(object):

    def init(self, x):

    self.val = x

    self.left = None

    self.right = None

    class Solution(object):
    def buildTree(self, inorder, postorder):
    """
    :type inorder: List[int]
    :type postorder: List[int]
    :rtype: TreeNode
    """
    def build(inmap, postorder, low, high, offset):
    if low>high: return None
    # if low==high: return TreeNode(postorder[high])

            m = inmap[postorder[high]]-offset
            root = TreeNode(postorder[high])
            root.left = build(inmap, postorder, low, low+m-1, offset)
            root.right = build(inmap, postorder, low+m, high-1, offset+m+1)
            return root
        
        inmap = {}
        for i in range(len(inorder)):
            inmap[inorder[i]]=i
    
        return build(inmap, postorder, 0, len(postorder)-1, 0)
    
  • 相关阅读:
    P3746 [六省联考2017]组合数问题 矩阵乘法
    P3322 [SDOI2015]排序 暴搜
    P2877 [USACO07JAN]Cow School G 斜率优化+分数规划
    P3283 [SCOI2013]火柴棍数字 DP
    AT2005 [AGC003E] Sequential operations on Sequence 单调栈+二分+差分
    CF568C New Language 2-SAT
    P4410 [HNOI2009]无归岛 仙人掌图
    CF505D Mr. Kitayuta's Technology 并查集 拓扑排序
    Algorithms: Design and Analysis, Part 1
    双目测距项目
  • 原文地址:https://www.cnblogs.com/absolute/p/5983288.html
Copyright © 2011-2022 走看看