边工作边刷题: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)
原文地址:https://www.cnblogs.com/absolute/p/5983288.html