DFS-special

    1. Validate Binary Search Tree
    1. Same Tree (基础)
  • 101.symmetric tree (基础)
    1. Maximum Depth of Binary Tree
    1. Construct Binary Tree from Preorder and Inorder Traversal
  • 106、 中序后序构建二叉树
    1. Convert Sorted Array to Binary Search Tree
    1. Convert Sorted List to Binary Search Tree
    1. Balanced Binary Tree
    1. Minimum Depth of Binary Tree
    1. Path Sum (重要)
  • 113.path sum II (重要)
    1. Flatten Binary Tree to Linked List (理解)
    1. Populating Next Right Pointers in Each Node
    1. Populating Next Right Pointers in Each Node II
    1. Sum Root to Leaf Numbers
  • 130 . Surrounded Regions
    1. Clone Graph
    1. Binary Tree Right Side View
    1. Number of Islands
    1. Course Schedule (重要)
    1. Binary Tree Paths
    1. Reconstruct Itinerary
    1. House Robber III (重要)

98. Validate Binary Search Tree

验证是否是二叉搜索树。采用DFS思想。

class Solution(object):
    def isValidBST(self, root):
        return self.isValidBSTRecu(root, float("-inf"), float("inf"))
    
    def isValidBSTRecu(self, root, low, high):
        if root is None:
            return True
        
        return low < root.val and root.val < high \
            and self.isValidBSTRecu(root.left, low, root.val) \
            and self.isValidBSTRecu(root.right, root.val, high)

100. Same Tree

Given two binary trees, write a function to check if they are the same or not.
Two binary trees are considered the same if they are structurally identical and the nodes have the same value.

最暴力直接的方法:

class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution(object):
    def isSameTree(self, p, q):
        """
        :type p: TreeNode
        :type q: TreeNode
        :rtype: bool
        """
        res1, res2 = [], []
        self.preOrdersort(p, res1)
        self.preOrdersort(q, res2)
        if len(res1) != len(res2):
            return False
        for i in xrange(0, len(res1)):
            if res1[i] != res2[i]:
                return False
        return True
    
    def preOrdersort(self, node, res):
        if node == None:
            res.append(None)
        else:
            res.append(node.val)
            self.preOrdersort(node.left, res)
            self.preOrdersort(node.right,res)

但比较简单的方法如下:


class Solution2:
    # @param p, a tree node
    # @param q, a tree node
    # @return a boolean
    def isSameTree(self, p, q):
        if p is None and q is None:
            return True

        if p is not None and q is not None:
            return p.val == q.val and self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)

        return False

101.symmetric tree

判断树是否是对称树

Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).
For example, this binary tree [1,2,2,3,4,4,3] is symmetric:

    1
   / \
  2   2
 / \ / \
3  4 4  3
But the following [1,2,2,null,3,null,3] is not:
    1
   / \
  2   2
   \   \
   3    3

肯定是使用递归求解,从左右两个支树出发

class Solution(object):
    def isSymmetric(self, root):
        """
        :type root: TreeNode
        :rtype: bool
        """
        if root is None:
            return True
        return self.symmetric(root.right,root.left)
    
    def symmetric(self, p, q):
        if p is None and q is None:
            return True
        
        if p is None or q is None or p.val != q.val:
            return False
        return self.symmetric(p.left, q.right) and self.symmetric(p.right, q.left)

另一种思路:

class Solution:
    # @param root, a tree node
    # @return a boolean
    def isSymmetric(self, root):
        if root is None:
            return True
        stack = []
        stack.append(root.left)
        stack.append(root.right)
        
        while stack:
            p, q = stack.pop(), stack.pop()
            
            if p is None and q is None:
                continue
            
            if p is None or q is None or p.val != q.val:
                return False
            
            stack.append(p.left)
            stack.append(q.right)
            
            stack.append(p.right)
            stack.append(q.left)
            
        return True

104. Maximum Depth of Binary 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 maxDepth(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        if root is None:
            return 0
        return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right))

105. Construct Binary Tree from Preorder and Inorder Traversal

Given preorder and inorder traversal of a tree, construct the binary tree.
给定一个树的前序和中序遍历,构建这个树。

思路如下:
先序遍历的第一个数一定是根节点,而中序遍历中根据根节点可以将树分为左右两个子树,依次递归既可以得到这个完整的树。

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
        """
        lookup = {}
        for i, item in enumerate(inorder):
            lookup[item] = i
        return self.constrctTree(lookup, preorder, inorder, 0, 0, len(inorder))

    def constrctTree(self, lookup, preorder, inorder,pre_start,in_start,in_end):
        if in_start == in_end:
            return None
        node = TreeNode(preorder[pre_start])    # root node
        i = lookup[preorder[pre_start]]
        node.left = self.constrctTree(lookup, preorder, inorder, pre_start+1, in_start, i)
        node.right = self.constrctTree(lookup, preorder, inorder, pre_start + 1 + i - in_start, i+1, in_end)
        return node

还是有很多疑问,constrctTree(self, lookup, preorder, inorder,pre_start,in_start,in_end)中每个参数代表的含义是什么。
更符合常规理解的解法为:

class Solution(object):
    def buildTree(self, preorder, inorder):
        """
        :type preorder: List[int]
        :type inorder: List[int]
        :rtype: TreeNode
        """
        if inorder:
            index = inorder.index(preorder[0])
            del preorder[0]
            root = TreeNode(inorder[index])
            root.left = self.buildTree(preorder, inorder[:index])
            root.right = self.buildTree(preorder, inorder[index + 1:])
            return root

106、 中序后序构建二叉树

class Solution(object):
    def buildTree(self, inorder, postorder):
        """
        :type inorder: List[int]
        :type postorder: List[int]
        :rtype: TreeNode
        """
        if inorder:
            index = inorder.index(postorder.pop())
            root = TreeNode(inorder[index])
        # 下面两行调换位置就不可以,为什么
            root.right = self.buildTree(inorder[index+1:], postorder)
            root.left = self.buildTree(inorder[:index], postorder)
            return root
class Solution:
    # @param inorder, a list of integers
    # @param postorder, a list of integers
    # @return a tree node
    def buildTree(self, inorder, postorder):
        lookup = {}
        for i, num in enumerate(inorder):
            lookup[num] = i
        return self.buildTreeRecu(lookup, postorder, inorder, len(postorder), 0, len(inorder))
    
    def buildTreeRecu(self, lookup, postorder, inorder, post_end, in_start, in_end):
        if in_start == in_end:
            return None
        node = TreeNode(postorder[post_end - 1])
        i = lookup[postorder[post_end - 1]]
        node.left = self.buildTreeRecu(lookup, postorder, inorder, post_end - 1 - (in_end - i - 1), in_start, i)
        node.right = self.buildTreeRecu(lookup, postorder, inorder, post_end - 1, i + 1, in_end)
        return node

总结105和106两个题,有两种思路,但主思想都是根据先序或后序遍历找到根节点,在由根节点找到中序遍历中序号,由序号确定左右子树,重复这个过程,直到二叉树构建完毕。
对第一种,思路比较简单,找到序号后,重复这个过程,但是要注意对preorder的处理。对先序遍历[1,2,4,5,3,6,7]来说,1是整个树的根节点,2是左子树的根节点,但如何确定右子树呢,采用动态弹出方式,因为构建左子树时先序中确定的是[4,2,5],因此,构建完左子树后先序遍历变为[3,6,7],再执行构建右子树。需要明确的有:

1、由于对先序列表执行删除操作,左右子树先后顺序十分重要,需要明确105和106的区别
2、在python中传递的是变量的引用。

第二种方法整体流程没有大问题,通过使用字典提高查找速度,由于对列表不删除,因此对根节点的定位比较关键。对左子树来说根节点位置是pre_start+1没问题,但是右子树中为什是是pre_start + 1 + i - in_start,这个表达式分为2个部分,第一个是pre_start+1,第二是i-in_start
留作进一步理解。

108. Convert Sorted Array to Binary Search Tree

Given an array where elements are sorted in ascending order, convert it to a height balanced BST.
For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differ by more than 1.

给定一个升序列表,转换为一个平衡二叉树。
初步想法分为两个步骤,一是找到中间节点作为根节点,然后递归

class Solution(object):
    def sortedArrayToBST(self, nums):
        """
        :type nums: List[int]
        :rtype: TreeNode
        """
        if nums:
            mid = len(nums) / 2
            node = TreeNode(nums[mid])
            node.left = self.sortedArrayToBST(nums[:mid])
            node.right = self.sortedArrayToBST(nums[mid+1:])
            return node

109. Convert Sorted List to Binary Search Tree

这道题和108的最大区别在于108的升序列表这里采用链表表示。

class ListNode(object):
    def __init__(self, x):
        self.val = x
        self.next = None

# 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 sortedListToBST(self, head):
        """
        :type head: ListNode
        :rtype: TreeNode
        """
        p_current = head
        val_lsit = []
        while p_current:
            val_lsit.append(p_current.val)
            p_current = p_current.next
        return self.sortedArrayToBST(val_lsit)
    
    def sortedArrayToBST(self, nums):
        """
        :type nums: List[int]
        :rtype: TreeNode
        """
        if nums:
            mid = len(nums) / 2
            node = TreeNode(nums[mid])
            node.left = self.sortedArrayToBST(nums[:mid])
            node.right = self.sortedArrayToBST(nums[mid+1:])
            return node

整体思路还是没有变。

110. Balanced Binary Tree

Given a binary tree, determine if it is height-balanced.
For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differ by more than 1.

这道题还是有点难度。

class Solution(object):
    def isBalanced(self, root):
        """
        :type root: TreeNode
        :rtype: bool
        """
        if root is None:
            return True
        left = self.getDepth(root.left)
        right = self.getDepth(root.right)
        if abs(left-right) > 1:
            return False
        else:
            return self.isBalanced(root.left) and self.isBalanced(root.right)
        
        
    def getDepth(self,root):
        if root is None:
            return 0  
        return 1 + max(self.getDepth(root.left), self.getDepth(root.right))

上面这种解法效率在24%,主要思路是从根节点开始,依次计算左右两边子树的最大深度,如果根节点平衡,在递归判断下面节点是否平衡。这样从上往下带来的最大问题就是造成大部分计算的重复。
如何进一步提升效率?
看看discuss 里最受欢迎的那个,我靠,不是和我一样嘛

public class Solution {
    public boolean isBalanced(TreeNode root) {
        if(null == root) {
            return true;
        }
 
        return Math.abs(height(root.left) - height(root.right)) < 2 && isBalanced(root.left) && isBalanced(root.right);
    }
 
    public int height(TreeNode root) {
        if(null == root) {
            return 0;
        }
 
        return 1 + Math.max(height(root.left), height(root.right));
    }
}

111. Minimum Depth of Binary Tree

Given a binary tree, find its minimum depth.
The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.

以下理解出现偏差,最短距离指的是从根节点到叶子节点的最短距离。
所以要先判断一个节点是不是叶节点,如果左右子树都为None,就是叶节点。

class Solution(object):
    def minDepth(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        if root is None:
            return 0
        if root.right is None and root.left is None:
            return 1
        if root.right and root.left:
            return min(self.minDepth(root.left), self.minDepth(root.right)) + 1
        if root.left:
            return self.minDepth(root.left) + 1
        if root.right:
            return self.minDepth(root.right) + 1

这写的还是随意了点,效率也比较低。但主要考虑的细节有:如果左右支树都有元素,则要取最小。如果只有某一子树有元素,则说明不是叶子节点,还需要继续寻找。

class Solution:
    # @param root, a tree node
    # @return an integer
    def minDepth(self, root):
        if root is None:
            return 0
        
        if root.left and root.right:
            return min(self.minDepth(root.left), self.minDepth(root.right)) + 1
        else:
            return max(self.minDepth(root.left), self.minDepth(root.right)) + 1

参考:

public class Solution {
    public int minDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }
        return getMin(root);
    }

    public int getMin(TreeNode root){
        if (root == null) {
            return Integer.MAX_VALUE;
        }

        if (root.left == null && root.right == null) {
            return 1;
        }

        return Math.min(getMin(root.left), getMin(root.right)) + 1;
    }
}

112. Path Sum

Given a binary tree and a sum, determine if the tree has a root-to-leaf path 
such that adding up all the values along the path equals the given sum.
For example:
Given the below binary tree and sum = 22,
              5
             / \
            4   8
           /   / \
          11  13  4
         /  \      \
        7    2      1
return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22.

给定一个数和一个值,确定是否存在一条路径使value之和等于该值。
最直观的做法就是将所有根节点到叶节点的路径计算一遍,再判断。

class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None
    
class Solution:
    # @param root, a tree node
    # @param sum, an integer
    # @return a boolean
    def hasPathSum(self, root, sum):
        if root is None:
            return False
        
        if root.left is None and root.right is None and root.val == sum:
            return True
        
        return self.hasPathSum(root.left, sum - root.val) or self.hasPathSum(root.right, sum - root.val)

113. Path Sum II

Given a binary tree and a sum, find all root-to-leaf paths where each path's sum equals the given sum.

For example:
Given the below binary tree and sum = 22,
              5
             / \
            4   8
           /   / \
          11  13  4
         /  \    / \
        7    2  5   1
return
[
   [5,4,11,2],
   [5,8,4,5]
]
class Solution(object):
    def pathSum(self, root, sum):
        """
        :type root: TreeNode
        :type sum: int
        :rtype: List[List[int]]
        """
        if not root: return []
        if root.left is None and root.right is None:
            if sum == root.val:
                return [[root.val]]
            else:
                return []
        a = self.pathSum(root.left, sum - root.val) + \
            self.pathSum(root.right, sum - root.val)
        return [[root.val] + i for i in a]

def pathSum(self, root, sum):
    if not root:
        return []
    if not root.left and not root.right and sum == root.val:
        return [[root.val]]
    tmp = self.pathSum(root.left, sum-root.val) + self.pathSum(root.right, sum-root.val)
    return [[root.val]+i for i in tmp]
class Solution:
    def pathSum(self, root, sum):
        if not root:
            return []
        val, kids = root.val, (root.left, root.right)
        if any(kids):
            return [[val] + path
                    for kid in kids
                    for path in self.pathSum(kid, sum - val)]
        return [[val]] if val == sum else []

114. Flatten Binary Tree to Linked List

Given a binary tree, flatten it to a linked list in-place.

For example,
Given

         1
        / \
       2   5
      / \   \
     3   4   6
The flattened tree should look like:
   1
    \
     2
      \
       3
        \
         4
          \
           5
            \
             6

If you notice carefully in the flattened tree, each node's right child points to the next node of a pre-order traversal.
主要思路是先用先序遍历整个树,然后依次重构成链状。

class Solution(object):
    def flatten(self, root):
        """
        :type root: TreeNode
        :rtype: void Do not return anything, modify root in-place instead.
        """
        res = []
        self.preorderSort(root,res)
        for i in xrange(1,len(res)):
            res[i-1].left = None
            res[i-1].right = res[i]

    def preorderSort(self,root,res):
        if root:
            res.append(root)
            self.inorderSort(root.left,res)
            self.inorderSort(root.right,res)

树的遍历比较基础,但值得注意的是还有用栈的方式,不用递归,如下:

def preorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        if root == None:return [] 
        stack = [root]
        result = []
 
        while len(stack) != 0:
            tmp_root = stack.pop()
            if tmp_root == None:continue
            result.append(tmp_root)
            stack.append(tmp_root.right)
            stack.append(tmp_root.left)
        return result

上面这种方法效率还不是很高。


image.png

上面思路还是有点没有理解。

class Solution1:
    # @param root, a tree node
    # @return nothing, do it in place
    def flatten(self, root):
        return self.flattenRecu(root, None)

    def flattenRecu(self, root, list_head):
        if root != None:
            list_head = self.flattenRecu(root.right, list_head)
            list_head = self.flattenRecu(root.left, list_head)
            root.right = list_head
            root.left = None
            return root
        else:
            return list_head


class Solution2:
    list_head = None

    # @param root, a tree node
    # @return nothing, do it in place
    def flatten(self, root):
        if root != None:
            self.flatten(root.right)
            self.flatten(root.left)
            root.right = self.list_head
            root.left = None
            self.list_head = root
            return root

116. Populating Next Right Pointers in Each Node

Given a binary tree
struct TreeLinkNode {
TreeLinkNode *left;
TreeLinkNode *right;
TreeLinkNode *next;
}
Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL.
Initially, all next pointers are set to NULL.
Note:
You may only use constant extra space.
You may assume that it is a perfect binary tree (ie, all leaves are at the same level, and every parent has two children).

For example,
Given the following perfect binary tree,
         1
       /  \
      2    3
     / \  / \
    4  5  6  7
After calling your function, the tree should look like:
         1 -> NULL
       /  \
      2 -> 3 -> NULL
     / \  / \
    4->5->6->7 -> NULL

这道题还是比较不直接,下面通过两层while循环,比较巧妙。

class Solution:
    # @param root, a tree link node
    # @return nothing
    def connect(self, root):
        if root is None:
            return 
        pre = root
        while pre.left:
            cur = pre
            while cur:
                cur.left.next = cur.right
                if cur.next:
                    cur.right.next = cur.next.left
                cur = cur.next           
            pre = pre.left

还一种递归的方法:

class Solution2:
    # @param root, a tree node
    # @return nothing
    def connect(self, root):
        if root is None:
            return
        if root.left:
            root.left.next = root.right
        if root.right and root.next:
            root.right.next = root.next.left
        self.connect(root.left)
        self.connect(root.right)

两个方法的关键其实就是如何将一个根节点的右子树指向相邻根节点的左子树。也就是下面一步很关键。

  if root.right and root.next:  # 不能写成 if root.next
            root.right.next = root.next.left

上面两种方法本质是一样的,也是递归和循环的相互转换。

117. Populating Next Right Pointers in Each Node II

在116的基础上由完全二叉树,变为一般二叉树。
这个题可以使用BFS。

class Solution:
    # @param root, a tree link node
    # @return nothing
    def connect(self, root):
        if root is None:
            return
        head = root
        while head:
            prev, cur, next_head = None, head, None
            while cur:
                if next_head is None:
                    if cur.left:
                        next_head = cur.left
                    elif cur.right:
                        next_head = cur.right
                if cur.left:
                    if prev:
                        prev.next = cur.left
                    prev = cur.left

                if cur.right:
                    if prev:
                        prev.next = cur.right
                    prev = cur.right

                cur = cur.next

            head = next_head

129. Sum Root to Leaf Numbers

Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number.
An example is the root-to-leaf path 1->2->3 which represents the number 123.
Find the total sum of all root-to-leaf numbers.
For example,

    1
   / \
  2   3

The root-to-leaf path 1->2 represents the number 12.
The root-to-leaf path 1->3 represents the number 13.

Return the sum = 12 + 13 = 25.

首先想到的思路就是将树所有的路径遍历一遍,并保存成一个数组。
代码实现为:

class Solution(object):
    def sumNumbers(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        res = 0
        path = self.allpath(root)
        for p in path:
            res += self.listToint(p)
        return res

    def listToint(self,path=[]):
        sum = 0
        for item in path:
            sum = sum*10 + item
        return sum

    def allpath(self,root):
        if root is None:
            return []
        if root.left is None and root.right is None:
            # warning not retrurn [root.val]
            return [[root.val]]
        a = self.allpath(root.left) + self.allpath(root.right)
        return [[root.val] + i for i in a]

上面的解法不够简练,参考别人:

# DFS
def sumNumbers(self, root):
    self.res = 0
    self.dfs(root, 0)
    return self.res

def dfs(self, root, value):
    if root:
        # if not root.left and not root.right:
        #    self.res += value*10 + root.val
        self.dfs(root.left, value * 10 + root.val)
        # if not root.left and not root.right:
        #    self.res += value*10 + root.val
        self.dfs(root.right, value * 10 + root.val)
        if not root.left and not root.right:
            self.res += value * 10 + root.val

# dfs + stack
def sumNumbers1(self, root):
    if not root:
        return 0
    stack, res = [(root, root.val)], 0
    while stack:
        node, value = stack.pop()
        if node:
            if not node.left and not node.right:
                res += value
            if node.right:
                stack.append((node.right, value*10+node.right.val))
            if node.left:
                stack.append((node.left, value*10+node.left.val))
    return res
    
# bfs + queue
def sumNumbers2(self, root):
    if not root:
        return 0
    queue, res = collections.deque([(root, root.val)]), 0
    while queue:
        node, value = queue.popleft()
        if node:
            if not node.left and not node.right:
                res += value
            if node.left:
                queue.append((node.left, value*10+node.left.val))
            if node.right:
                queue.append((node.right, value*10+node.right.val))
    return res

130 . Surrounded Regions

Given a 2D board containing 'X' and 'O' (the letter O), capture all regions surrounded by 'X'.
A region is captured by flipping all 'O's into 'X's in that surrounded region.

For example,
X X X X
X O O X
X X O X
X O X X
After running your function, the board should be:

X X X X
X X X X
X X X X
X O X X

以下是DFS常规解法:

class Solution(object):
    def solve(self, board):
        """
        :type board: List[List[str]]
        :rtype: void Do not return anything, modify board in-place instead.
        """
        m = len(board)
        if m == 0:
            return
        n = len(board[0])
        if n == 0:
            return
        for i in xrange(m):
            self.dfs(i,0,board,m,n)
            self.dfs(i,n,board,m,n)
        for j in xrange(n):
            self.dfs(0,j,board,m,n)
            self.dfs(m,j,board,m,n)
        for i in xrange(m):
            for j in xrange(n):
                if board[i][j] == '1':
                    board[i][j] = 'O'
                elif board[i][j] == 'O':
                    board[i][j] = 'X'


    def dfs(self,i,j,board,m,n):
        if i < 0 or i > m or j < 0 or j > n or board[i][j] != 'O':
            return
        board[i][j] = '1'
        self.dfs(i + 1, j, board, m, n)
        self.dfs(i - 1, j, board, m, n)
        self.dfs(i, j + 1, board, m, n)
        self.dfs(i, j - 1, board, m, n)

133. Clone Graph

# Method 1: BFS
# Definition for a undirected graph node
# class UndirectedGraphNode(object):
#     def __init__(self, x):
#         self.label = x
#         self.neighbors = []

import Queue

class Solution(object):
    def __init__(self):
        self.visited = {}
        
    def cloneGraph(self, node):
        """
        :type node: UndirectedGraphNode
        :rtype: UndirectedGraphNode
        """
        if not node:
            return None
            
        newHead = UndirectedGraphNode(node.label)
        self.visited[node] = newHead
        
        myQueue = Queue.Queue()
        myQueue.put(node)
        while myQueue.qsize():
            current = myQueue.get()
            for neighbor in current.neighbors:
                if neighbor not in self.visited:
                    newNode = UndirectedGraphNode(neighbor.label)
                    self.visited[current].neighbors.append(newNode)
                    self.visited[neighbor] = newNode
                    myQueue.put(neighbor)
                else: # turn directed graph to undirected graph
                    self.visited[current].neighbors.append(self.visited[neighbor])
                    
        return newHead

# Method 2: DFS
class Solution(object):
    def cloneGraph(self, node):
        """
        :type node: UndirectedGraphNode
        :rtype: UndirectedGraphNode
        """
        if not node:
            return None
            
        return self.dfs(node, {})
        
    def dfs(self, node, map):
        if node in map:
            return map[node]
        newNode = UndirectedGraphNode(node.label)
        map[node] = newNode
        for neighbor in node.neighbors:
            newNode.neighbors.append(self.dfs(neighbor, map))
            
        return newNode

作者:Jason_Yuan

BFS解法比较直观,DFS这样的递归一直比较绕,需要多理解理解。

199. Binary Tree Right Side View

Given a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom.
For example:
Given the following binary tree,

    1            <---
  /   \
 2     3         <---
  \     \
   5     4       <---
 You should return [1, 3, 4].

简单的思路应该是不断递归,并向下传递上一层的度,从右向左遍历。

class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution(object):
    def rightSideView(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        lookup = {}
        self.dfs(root,0,lookup)
        return lookup.values()


    def dfs(self,root,level,lookup):
        if root:
            if level not in lookup:
                lookup[level] = root.val
        
            self.dfs(root.right,level+1,lookup)
            self.dfs(root.left,level+1,lookup)

if __name__ == '__main__':
    root = TreeNode(1)
    root.right, root.left = TreeNode(2), TreeNode(3)
    s = Solution()
    print s.rightSideView(root)

讨论区提供的参考,思路和自己一样,但性能相差不大。

def rightSideView(self, root):
    def collect(node, depth):
        if node:
            if depth == len(view):
                view.append(node.val)
            collect(node.right, depth+1)
            collect(node.left, depth+1)
    view = []
    collect(root, 0)
    return view

200. Number of Islands

Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.
Example 1:
11110
11010
11000
00000
Answer: 1
Example 2:
11000
11000
00100
00011
Answer: 3

DFS和BFS的灵活使用问题。

class Solution(object):
    def numIslands(self, grid):
        """
        :type grid: List[List[str]]
        :rtype: int
        """
        m = len(grid)
        if m == 0:
            return 0
        n = len(grid[0])
        if n == 0:
            return 0
        res = 0
        for i in xrange(m):
            for j in xrange(n):
                if grid[i][j] == 0:
                    continue
                res += 1
                self.dfs(grid,m,n,i,j)
        return res
                
    def dfs(self,grid,m,n,i,j):
        if i < 0 or i >= m or j < 0 or j >= n:
            return 
        if grid[i][j]:
            grid[i][j] = 0
            self.dfs(grid, m, n, i-1, j)
            self.dfs(grid, m, n, i + 1, j)
            self.dfs(grid, m, n, i, j-1)
            self.dfs(grid, m, n, i, j+1)

上面的程序是最基本的DFS,但总是出现问题,递归深度超出限制。
膜拜下别人的程序

def numIslands(self, grid):
    def sink(i, j):
        if 0 <= i < len(grid) and 0 <= j < len(grid[i]) and grid[i][j] == '1':
            grid[i][j] = '0'
            map(sink, (i+1, i-1, i, i), (j, j, j+1, j-1))
            return 1
        return 0
    return sum(sink(i, j) for i in range(len(grid)) for j in range(len(grid[i])))

上面程序确实很妙,很简化,厉害。

207. Course Schedule (拓扑排序)(重要)

There are a total of n courses you have to take, labeled from 0 to n - 1.
Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]
Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?
For example:
2, [[1,0]]
There are a total of 2 courses to take. To take course 1 you should have finished course 0. So it is possible.
2, [[1,0],[0,1]]
There are a total of 2 courses to take. To take course 1 you should have finished course 0, and to take course 0 you should also have finished course 1. So it is impossible.

这道题的关键就是看这些关联课程有没有形成一个环,如果成了一个环就说明不可能。本质还是一个DFS搜索问题。关键还是问题的描述和建模。

class Solution(object):
    def canFinish(self, numCourses, prerequisites):
        """
        :type numCourses: int
        :type prerequisites: List[List[int]]
        :rtype: bool
        """
        if numCourses < 2 or len(prerequisites) < 2:
            return True
            # prerequisites.sort()
        while True:
            count = 0
            mark = [True] * numCourses
            for pre in prerequisites:
                mark[pre[0]] = False
            for pre in prerequisites:
                if mark[pre[1]]:
                    count += 1
                    prerequisites.remove(pre)
            if prerequisites == []:
                return True
            elif count == 0:
                return False

上面效率比较低

import collections

class Solution(object):
    def canFinish(self, numCourses, prerequisites):
        """
        :type numCourses: int
        :type prerequisites: List[List[int]]
        :rtype: bool
        """
        zero_in_degree_queue, in_degree, out_degree = collections.deque(), {}, {}
        
        for i, j in prerequisites:
            if i not in in_degree:
                in_degree[i] = set()
            if j not in out_degree:
                out_degree[j] = set()
            in_degree[i].add(j)
            out_degree[j].add(i)
        
        for i in xrange(numCourses):
            if i not in in_degree:
                zero_in_degree_queue.append(i)
        
        while zero_in_degree_queue:
            prerequisite = zero_in_degree_queue.popleft()
            
            if prerequisite in out_degree:
                for course in out_degree[prerequisite]:
                    in_degree[course].discard(prerequisite)
                    if not in_degree[course]:
                        zero_in_degree_queue.append(course)
            
                del out_degree[prerequisite]
        
        if out_degree:
            return False
        
        return True

257. Binary Tree Paths

这道题比较简单呀,常规题。

class Solution(object):
    def binaryTreePaths(self, root):
        """
        :type root: TreeNode
        :rtype: List[str]
        """
        if root is None:
            return []
        if root:
            if root.left is None and root.right is None:
                return [str(root.val)]
            a = self.binaryTreePaths(root.left) + self.binaryTreePaths(root.right)
            return [str(root.val) + '->' + i for i in a]

332. Reconstruct Itinerary

def findItinerary(self, tickets):
    targets = collections.defaultdict(list)
    for a, b in sorted(tickets)[::-1]:
        targets[a] += b,
    route = []
    def visit(airport):
        while targets[airport]:
            visit(targets[airport].pop())
        route.append(airport)
    visit('JFK')
    return route[::-1]
Iterative version:

def findItinerary(self, tickets):
    targets = collections.defaultdict(list)
    for a, b in sorted(tickets)[::-1]:
        targets[a] += b,
    route, stack = [], ['JFK']
    while stack:
        while targets[stack[-1]]:
            stack += targets[stack[-1]].pop(),
        route += stack.pop(),
    return route[::-1]

下面两个程序是神奇,基本上一样输出却不一样

from collections import defaultdict

class Solution(object):
    def findItinerary(self, tickets):
        """
        :type tickets: List[List[str]]
        :rtype: List[str]
        """
        ticket_map = defaultdict(list)
        for a,b in sorted(tickets)[::-1]:
            print a, b
            ticket_map[a] += b,
        route = []

        def visit(airport):
            while ticket_map[airport]:
                visit(ticket_map[airport].pop())
            route.append(airport)
            print route
        visit('JFk')
        return route[::-1]

    def findItinerary1(self, tickets):
        targets = defaultdict(list)
        for a, b in sorted(tickets)[::-1]:
            print a, b
            targets[a] += b,
        route = []

        def visit(airport):
            while targets[airport]:
                visit(targets[airport].pop())
            route.append(airport)
            print route

        visit('JFK')
        return route[::-1]

337. House Robber III

The thief has found himself a new place for his thievery again. There is only one entrance to this area, called the "root." Besides the root, each house has one and only one parent house. After a tour, the smart thief realized that "all houses in this place forms a binary tree". It will automatically contact the police if two directly-linked houses were broken into on the same night.

Determine the maximum amount of money the thief can rob tonight without alerting the police.

Example 1:
     3
    / \
   2   3
    \   \ 
     3   1

Maximum amount of money the thief can rob = 3 + 3 + 1 = 7.

Example 2:
     3
    / \
   4   5
  / \   \ 
 1   3   1

Maximum amount of money the thief can rob = 4 + 5 = 9.

class Solution(object):
    def rob(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        def robHelper(root):
            if not root:
                return (0, 0)
            left, right = robHelper(root.left), robHelper(root.right)
            return (root.val + left[1] + right[1], max(left) + max(right))
        
        return max(robHelper(root))

这道题还是要和之前I、II结合起来考虑,都需要考虑当前偷还是不偷,返回一个数组,第一个元素代表偷当前,第二个元素代表不偷。其他思路和之前一样,采用动态规划。
复习 : https://www.youtube.com/watch?v=-i2BFAU25Zk

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

推荐阅读更多精彩内容