def naive(self, inorder, postorder): if inorder: # CAUTION root = TreeNode(postorder.pop()) i = inorder.index(root.val) root.left = self.buildTree(inorder[:i], postorder[:i]) root.right = self.buildTree(inorder[i + 1:], postorder[i:]) return root
def iterative(self, preorder, inorder): if not preorder: return None # 根节点入栈 root = TreeNode(preorder.pop(0)) stack = [root] # 建立倒排索引,方便比较各节点在中序意义下的 大小关系 m = {v: k for k, v in enumerate(inorder)} # 依次处理preorder中的后续各点 for value in preorder: node = TreeNode(value) # 观察上一次循环的最后一句发现:栈顶相对于node是preorder意义上的左邻居 # 而如果此时的node在中序意义上小于它,就说明node铁定是它的左孩子 if m[value] < m[stack[-1].val]: stack[-1].left = node else: # 否则node在中序意义上大于栈顶 # 说明当前元素可能位于栈顶元素或更高层元素的right位上 # 具体是哪一层的right位呢? # 应当介于 p 层和 p-1 层之间; # 条件: 比p层靠右,同时比p-1层靠左 while stack and m[stack[-1].val] < m[value]: parent = stack.pop() # 循环跳出的时刻,记录的是最后一次满足条件的parent,即分析中的 p层 # # 因为整体是按照preorder遍历的,而此时parent的左右孩子都已经入栈了 # 后面处理的各节点不可能上溯到该parent, parent不再需要(已抛出栈无妨) parent.right = node stack.append(node) return root
def pop_pre(self, preorder, inorder): # 不断抛preorder,而inorder不动,只是定位 if inorder: # 这一步反复调用index(),直接跑是O(n); 可以用hash缓存好 idx = inorder.index(preorder.pop(0)) root = TreeNode(inorder[idx]) # root已经抛掉了,preorder开头部分就是left root.left = self.pop_pre(preorder, inorder[:idx]) # root和left子树已经处理完,相应元素都已经抛空;preorder的头部仍然直接可用 root.right = self.pop_pre(preorder, inorder[idx + 1:]) return root
def mergeTrees(self, t1, t2): if t1 is None and t2 is None: return None elif t1 is None: return t2 elif t2 is None: return t1 else: node = TreeNode(t1.val + t2.val) node.left = self.mergeTrees(t1.left, t2.left) node.right = self.mergeTrees(t1.right, t2.right) return node
def build(stop): # 如果还没有处理到上一层认为的根 if inorder and inorder[0] != stop: # 找到这一层的根 root = TreeNode(preorder.pop(0)) # 直接在比较完整的inorder上处理直到遇到Stop为止 # 避免了index()操作的O(n) root.left = build(stop=root.val) inorder.pop(0) # 当前层的左子树处理完了,抛当前层的根 # 处理当前层的右子树;在上层的stop值之前的部分inorder可用 root.right = build(stop=stop) return root
def naive(self, preorder, inorder): if not preorder: return None # find root_val in inorder root_val = preorder[0] root_idx = inorder.index(root_val) # recurse L = self.naive(preorder[1:1 + root_idx], inorder[:root_idx]) R = self.naive(preorder[1 + root_idx:], inorder[root_idx + 1:]) # merge root = TreeNode(root_val) root.left, root.right = L, R return root
def iterative(self, inorder, postorder): if not postorder: # CAUTION return None m = {v: k for k, v in enumerate(inorder)} root = TreeNode(postorder.pop()) stack = [root] for v in postorder[::-1]: # 注意逆序 n = TreeNode(v) # CAUTION if m[v] > m[stack[-1].val]: stack[-1].right = n else: while stack and m[v] < m[stack[-1].val]: parent = stack.pop() parent.left = n stack.append(n) return root
class Solution(object): def bfs(self, root): if not root: return 0 row, depth = [root], 1 while row: nrow = [] for n in row: kids = tuple(e for e in (n.left, n.right) if e) if not kids: # 上一层的某个节点是叶子节点 return depth nrow += kids row, depth = nrow, depth + 1 assert False def dfs(self, root): if not root: return 0 l, r = self.dfs(root.left), self.dfs(root.right) # 如果两边都非零,就取min+1 ; 否则取较深那边+1 return (1 + min(l, r)) if (l and r) else (l + r + 1) def minDepth(self, root): return self.bfs(root) # return self.dfs(root) if __name__ == '__main__': root = TreeNode.from_json('[3,9,20,null,null,15,7]') print(Solution().bfs(root))
def bfs(self, root): res = [] q = [root] if root else [] while q: res.append(q[-1].val) # CAUTION q = [k for n in q for k in (n.left, n.right) if k] return res def dfs(self, root): rightmost_value_at_depth = [] stack = [(root, 0)] # tuple<node, depth> while stack: node, depth = stack.pop() if node: # 利用栈的性质,每个新层都是尽可能靠右的首次到达 if depth >= len(rightmost_value_at_depth): rightmost_value_at_depth.append(node.val) # 注意right后进先出;抛栈的时候才改记录;所以结果是尽量靠右 stack.append((node.left, depth + 1)) stack.append((node.right, depth + 1)) return rightmost_value_at_depth def rightSideView(self, root): # return self.bfs(root) return self.dfs(root) if __name__ == '__main__': res = Solution().rightSideView(TreeNode(1)) print(res)