Leetcode 421~440

112. 路径总和

根结点到叶子结点的路径上值的和 :在叶子结点上判断。

方法一:递归 DFS

class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        if not root:return False
        if not root.left and not root.right: # 叶子结点
            return root.val == targetSum
        # 问题转化为左右子树递归
        return self.hasPathSum(root.right, targetSum - root.val) or self.hasPathSum(root.left, targetSum - root.val) 

方法二:广度优先搜索 BFS

class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        if not root: return False
        q = deque([(root, root.val)]) # 通过元组携带前缀和
        # q = [(root, root.val)] # DFS
        while q:
            cur, tem = q.popleft()
            # cur, tem = q.pop()
            if not cur.left and not cur.right: # 叶子结点
                if tem == targetSum: return True
                continue
                
            cur.left and q.append((cur.left, cur.left.val + tem))  
            cur.right and q.append((cur.right, cur.right.val + tem))      
        
        return False

113. 路径总和 II

方法一:DFS

cclaclass Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
        
        def dfs(cur, tmp):
            path.append(cur.val)
            tmp -= cur.val
            if not tmp and not cur.left and not cur.right:
                res.append(path[:]) # copy
            
            cur.left and dfs(cur.left, tmp)
            cur.right and dfs(cur.right, tmp)
            path.pop()  # 回溯

        if not root: return []
        res, path = [], []
        dfs(root, targetSum)

        return res

方法二:广度优先搜索

class Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
        if not root: return [] 
        res = []
        q = deque([(root, [], targetSum)])  # 结点,路径,路径和 bfs
        # q = [(root, [], targetSum)]  # dfs

        while q:
            cur, path, tmp = q.popleft() # bfs
            # cur, path, tmp = q.pop() # dfs
            # path += [cur.val]
            # path.append(cur.val) # 列表 +=,append 对象不变 !!! 
            path = path + [cur.val] # 对象变了,不再需要 copy path 以及回溯
            tmp -= cur.val
            # 如果是叶子节点,同时和为零。
            if not cur.left and not cur.right and not tmp: 
                    res.append(path) # 保存路径

            cur.left and q.append((cur.left, path, tmp))
            cur.right and q.append((cur.right, path, tmp))

        return res

437. 路径总和 III

方法一:深度优先搜索

统计以每个结点为「路径开头」的所有合法路径。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def pathSum(self, root: TreeNode, targetSum: int) -> int:
        
        # def dfs(cur, tmp):
        #     if not cur: return 0            
        #     tmp -= cur.val             
        #     return dfs(cur.left, tmp) + dfs(cur.right, tmp) + (0 if tmp else 1)

        # if not root: return 0
        # return dfs(root, targetSum) + self.pathSum(root.left, targetSum) + self.pathSum(root.right, targetSum)

        def dfs(cur, tmp): 
            return dfs(cur.left, tmp - cur.val) + dfs(cur.right, tmp - cur.val) + (0 if tmp != cur.val else 1) if cur else 0

        return dfs(root, targetSum) + self.pathSum(root.left, targetSum) + self.pathSum(root.right, targetSum) if root else 0

方法二: 前缀和

统计以每个结点为「路径结尾」的所有合法路径,即从根结点到当前结点的唯一路径中找有多少个结点的路径总和为 targetSum。

统计 sum[y] - sum[x] = targetSum 的数量,其中 x 始结点,y 尾结点 ,即 sum[x] = sum[y] - targetSum,统计 x 数量。
为了更快速的找到某个数值在路径中是否出现过,可以使用哈希表记录路径中每个数值出现的次数。
另外,为了处理包含根节点的情况,需要在哈希表中存储一个 (0,1) 的键值对。而且,并不需要一开始就把前缀和树计算出来,可以边遍历边计算,这里使用回溯来处理,因此这个点已经统计过了,防止影响树的其他分支的数量统计。

class Solution:
    def pathSum(self, root: TreeNode, targetSum: int) -> int:
        prefix = collections.defaultdict(int) # 记录路径中某个前缀和 : 出现的次数
        prefix[0] = 1 # 根节点前,前缀和为 0

        def dfs(cur, tmp):
            if not cur:  return 0            

            tmp += cur.val # 当前结点的前缀和
            res = prefix[tmp - targetSum] # 相当于找路径的起点,tmp - 起点的前缀和 = targetSum,即 tmp - targetSum 起点的前缀和。
            prefix[tmp] += 1 # 将当前前缀和个数记录下来
            res += dfs(cur.left, tmp) + dfs(cur.right, tmp)
            prefix[tmp] -= 1 # 回溯

            return res

        return dfs(root, 0)

方法三: 翻转列表的前缀和

class Solution:
    def pathSum(self, root: TreeNode, targetSum: int) -> int:
        def f(cur, prefix):
            if not cur: return 0
            prefix = [e + cur.val for e in prefix] + [cur.val]
            return prefix.count(targetSum) + f(cur.left, prefix) + f(cur.right, prefix)
            
            # tmp =  tmp + [cur.val]
            # prefix = list(accumulate(tmp[::-1]))
            # return prefix.count(targetSum) + f(cur.left, tmp) + f(cur.right, tmp)

        return f(root, [])

430. 扁平化多级双向链表

方法一:深度优先搜索

当遍历到某个节点 node 时,如果它的 child 成员不为空,就要先去处理 child 指向的链表结构,这就是一个「深度优先搜索」的过程。当完成了对 child 指向的链表结构的扁平化之后,就可以「回溯」到 node 节点。

为了能够将扁平化的链表插入 node 与 node 的下一个节点之间,需要知道扁平化的链表的最后一个节点 last,随后进行如下的三步操作:

将 node 与 node 的下一个节点 next 断开:
将 node 与 child 相连;
将 last 与 next 相连。

这样一来,就可以将扁平化的链表成功地插入。

在深度优先搜索完成后,返回给定的首节点即可。

需要注意的是,node.next 为空。此时,只需进行第二步操作。

此外,在插入扁平化的链表后,需要将 node 的 child 成员置为空。

class Solution:
    def flatten(self, head: "Node") -> "Node":
        def dfs(node: "Node") -> "Node":
            cur = node            
            last = None # 记录链表的最后一个节点

            while cur:
                nxt = cur.next
                # 如果有子节点,那么首先处理子节点
                if cur.child:
                    child_last = dfs(cur.child)
                    
                    nxt = cur.next
                    # 将 node 与 child 相连
                    cur.next = cur.child
                    cur.child.prev = cur

                    # 如果 nxt 不为空,就将 last 与 nxt 相连
                    if nxt:
                        child_last.next = nxt
                        nxt.prev = child_last

                    # 将 child 置为空
                    cur.child = None
                    last = child_last
                else:
                    last = cur
                cur = nxt

            return last

        dfs(head)
        return head

方法二:栈

"""
# Definition for a Node.
class Node:
    def __init__(self, val, prev, next, child):
        self.val = val
        self.prev = prev
        self.next = next
        self.child = child
"""

class Solution:
    def flatten(self, head: 'Node') -> 'Node':
        q = []
        cur = head
        while cur or q:
            if cur.child:
                if cur.next: q.append(cur.next) 
                cur.child.prev = cur
                cur.next = cur.child
                cur.child = None

            if q and not cur.next:
                node = q.pop()
                cur.next = node
                node.prev = cur

            cur = cur.next
        return head

版权声明:本文为weixin_43955170原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。