您当前的位置: 首页 > 

宝哥大数据

暂无认证

  • 3浏览

    0关注

    1029博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

112. 路径总和

宝哥大数据 发布时间:2019-10-22 15:01:35 ,浏览量:3

一、112. 路径总和

在这里插入图片描述

1.1、题目描述 1.2、题解 1.2.1、递归,

实际就是实现了深度优先搜索(DFS)

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def hasPathSum(self, root: TreeNode, sum: int) -> bool:
        if not root: return False
        
        if not root.left and not root.right and sum - root.val == 0:
            return True
        
        return self.hasPathSum(root.left, sum - root.val) or self.hasPathSum(root.right, sum - root.val)
1.2.2、DFS可以用栈去模拟。增加一个栈,去保存从根节点到当前节点累计的和就可以了。

此处使用中序遍历

class Solution:
    # 深度优先搜索(DFS)
    def hasPathSum(self, root: TreeNode, sum: int) -> bool:
        if not root: return False
        que = []
        queSum = []
        
        node = root
        curSum  = 0
        while len(que) > 0 or node:
            # 将该节点的左路径全部压入栈中
            while node: 
                que.append(node)
                curSum += node.val
                queSum.append(curSum)
                node = node.left
            
            node = que.pop()
            curSum = queSum.pop()
            
            # 叶子节点,路径和满足条件
            if curSum == sum and not node.left and not node.right:
                return True
            
            # 考虑右节点
            node = node.right
        return False
                
                
                
1.2.3、优化, 替换queSum栈,
class Solution:
    # 深度优先搜索(DFS)
    def hasPathSum(self, root: TreeNode, sum: int) -> bool:
        if not root: return False
        que = []
        
        node = root
        pre = None
        curSum  = 0
        # 后序遍历, 先遍历左子树, 再遍历右子树, 最后遍历根节点
        while len(que) > 0 or node:
            # 将该节点的左路径全部压入栈中
            while node: 
                que.append(node)
                curSum += node.val
                node = node.left
            
            node = que[-1]
            # print(node.val, curSum, node.left, node.right)
            
            # 叶子节点,路径和满足条件
            if curSum == sum and not node.left and not node.right:
                return True
            
            # 考虑右节点
            if not node.right or pre == node.right:
                pop = que.pop()
                curSum -= pop.val
                pre = node
                node = None
            else:
                node = node.right
           
        return False
1.2.4、BFS
class Solution:
    # 广度优先搜索(BFS)
    def hasPathSum(self, root: TreeNode, sum: int) -> bool:
        if not root: return False
        que = []
        queSum = []
        
        que.append(root)
        queSum.append(root.val)
        
        while len(que) > 0:
            queSize = len(que)
            # 层次遍历
            for i in range(queSize):
                node = que.pop(0)   # 模拟队首弹出
                curSum = queSum.pop(0) # 模拟队首弹出
                # 是叶子节点, 且路径和满足条件
                if not node.left and not node.right and curSum == sum : return True
                
                # 当前节点 和 累计和 压入队列
                if node.left:
                    que.append(node.left)
                    queSum.append(node.left.val + curSum)
                if node.right:
                    que.append(node.right)
                    queSum.append(node.right.val + curSum)
          
        return False
                
二、257. 二叉树的所有路径 2.1、题目描述

在这里插入图片描述

2.2.1、迭代

  层次遍历,使用队列存储待遍历的节点,另一个队列存储对应的路径,当遇到叶子节点,将路径存入列表中。(BFS)

class Solution:
    def binaryTreePaths(self, root: TreeNode) -> List[str]:
        if not root:
            return None
        que = []
        que.append(root)
        
        queStr = []
        queStr.append(str(root.val))
        ret = []
        while len(que) > 0:
            queSize = len(que)
            for i in range(queSize):
                # 模拟队列
                cur = que.pop(0)
                curStr = queStr.pop(0)
                # print(cur.val, curStr, queSize)
                
                # 叶子节点
                if not cur.left and not cur.right:
                    ret.append(curStr)
                    continue
                if cur.left:
                    que.append(cur.left)
                    queStr.append(curStr + "->" + str(cur.left.val))
                if cur.right:
                    que.append(cur.right)
                    queStr.append(curStr + "->" + str(cur.right.val))
            
            
        return ret
2.2.2、递归
class Solution:
    def binaryTreePaths(self, root: TreeNode) -> List[str]:
        if not root:
            return None
        
        retPaths = []
        self.nodePath(root, str(root.val), retPaths)
        return retPaths
    # 递归
    def nodePath(self, node: TreeNode, path: str, retPaths: List[str]) -> None:
        # 叶子节点
        if not node.left and not node.right:
            retPaths.append(path)
            
        if node.left:
            leftPath = path + '->' + str(node.left.val)
            self.nodePath(node.left, leftPath, retPaths)
        
        if node.right:
            rightPath = path + '->' + str(node.right.val)
            self.nodePath(node.right, rightPath, retPaths)
三、113. 路径总和 II 3.1、题目描述

在这里插入图片描述

3.3.1、相当于上两题的合并
class Solution:
    def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]:
        if not root:
            return []
        retPaths = []
        self.nodePath(root, [root.val], retPaths, sum-root.val)
        return retPaths
        
    # 递归, 从上向下
    def nodePath(self, node: TreeNode, path: List[int], paths: List[List[int]], sum: int) -> None:
        if not node.left and not node.right:
            if sum == 0:
                paths.append(path)
        else:
            if node.left:
                leftPath= path[:]
                leftPath.append(node.left.val)
                self.nodePath(node.left, leftPath, paths, sum-node.left.val)
            if node.right:
                rightPath =  path[:]
                rightPath.append(node.right.val)
                self.nodePath(node.right, rightPath, paths, sum-node.right.val)
            
四、437. 路径总和 III 4.1、题目描述

在这里插入图片描述

4.2、题解 4.2.1、以每一个节点作为根节点,计算路径和
class Solution:
    def pathSum(self, root: TreeNode, sum: int) -> int:
        if not root: return 0
        return self.nodeSum(root, sum) + self.pathSum(root.left, sum) + self.pathSum(root.right, sum)


    # 计算某个节点的路径和 
    def nodeSum(self, root: TreeNode, _sum: int) -> int:
        if not root: return 0
        _sum -= root.val
        
        count = 1 if _sum == 0 else 0

        return  count + self.nodeSum(root.left, _sum) + self.nodeSum(root.right, _sum)
4.2.2、DFS+回溯

  采取了类似于数组的前n项和的思路,比如sum[4] == sum[1],那么1到4之间的和肯定为0

  对于树的话,采取DFS加回溯,每次访问到一个节点,把该节点加入到当前的pathSum中 然后判断是否存在一个之前的前n项和,其值等于pathSum与sum之差 如果有,就说明现在的前n项和,减去之前的前n项和,等于sum,那么也就是说,这两个点之间的路径和,就是sum

最后要注意的是,记得回溯,把路径和弹出去


class Solution:
    def pathSum(self, root: TreeNode, sum: int) -> int:
        if not root: return 0

        return self.nodeSum(root, sum, 0)

    def __init__(self) -> None:
       self.map = {0:1}

    # 计算某个节点的路径和 
    def nodeSum(self, root: TreeNode, target: int, pathSum: int) -> int:
        if not root: return 0

        count = 0
        pathSum += root.val

        preSum = pathSum-target
        if preSum in self.map:
            count =  self.map[preSum] 

        if pathSum not in self.map:
            self.map[pathSum] = 0
        self.map[pathSum] += 1

        count = self.nodeSum(root.left, target, pathSum) + self.nodeSum(root.right, target, pathSum) + count
        # 回溯
        self.map[pathSum] -= 1
        
        return count
五、687. 最长同值路径 5.1、题目描述

在这里插入图片描述 在穿过左子树,根节点,右子树的一条路径中 在这里插入图片描述

5.2、题解

最长的路径可能有三种情况:

  • 1.在左子树内部
  • 2.在右子树内部
  • 3.在穿过左子树,根节点,右子树的一条路径中
5.2.1、递归
class Solution:
    def longestUnivaluePath(self, root: TreeNode) -> int:
        if not root: return 0
        self.__dfs(root, root.val)
        return self.maxLen

    def __init__(self) -> None:
        self.maxLen = 0

    def __dfs(self, root: TreeNode, preVal: int) -> int:
        if not root: return 0

        if preVal == root.val:
            left = self.__dfs(root.left, root.val)
            right = self.__dfs(root.right, root.val)
            self.maxLen = max(left + right, self.maxLen)

            return max(left, right) + 1
        else:
            self.__dfs(root, root.val)
            return 0
六、124. 二叉树中的最大路径和

与 687. 最长同值路径类似。

6.1、题目描述

在这里插入图片描述

6.2、题解 6.2.1、递归
class Solution:
    def maxPathSum(self, root: TreeNode) -> int:
        self.__dfs(root)
        return self.maxSum
    
    def __init__(self) -> None:
        self.maxSum = float('-inf')
    
    def __dfs(self, root: TreeNode) -> int:
        if not root: return 0
        
        # 另外结点有可能是负值,最大和肯定就要想办法舍弃负值(max(0, x))
        left = max(self.__dfs(root.left), 0)
        right = max(self.__dfs(root.right), 0)

        self.maxSum = max(self.maxSum, left+right+root.val)
        return max(left, right) + root.val
七、129. 求根到叶子节点数字之和 7.1、题目描述

在这里插入图片描述

7.2、题解 7.2.1、DFS
class Solution:
    def sumNumbers(self, root: TreeNode) -> int:
        self.__dfs(root, 0)
        return self._sum
    
    def __init__(self) -> None:
        self._sum = 0
    def __dfs(self, root: TreeNode, pSum) -> int:
        if not root: return 0
        
        # 叶子节点
        if not root.left and not root.right:
            self._sum += 10*pSum + root.val

        # 将父节点的值向下传递
        if root.left:
            self.__dfs(root.left, 10*pSum+root.val)
        if root.right:
            self.__dfs(root.right, 10*pSum+root.val)
7.2.2、分治法
class Solution:
    def sumNumbers(self, root: TreeNode) -> int:
        return self.__dfs(root, 0)
    
    def __dfs(self, root: TreeNode, pSum) -> int:
        if not root: return 0
        
        curSum = 10*pSum + root.val
        # 叶子节点
        if not root.left and not root.right:
            return curSum 

        ans = 0
        # 将父节点的值向下传递
        if root.left:
            ans += self.__dfs(root.left, curSum)
        if root.right:
            ans += self.__dfs(root.right, curSum)
        return ans 
7.7.3、先序迭代

class Solution:
    def sumNumbers(self, root: TreeNode) -> int:
        if not root: return 0
        
        _sum = 0
        # 双队列,记录子节点,以及父节点的累计数值
        nodeStack = [root]
        numStack = [0]
        while nodeStack:
            # 父节点
            curNode = nodeStack.pop(0)
            curSum = 10*numStack.pop(0) + curNode.val
            
            if not curNode.left and not curNode.right:
                _sum += curSum
            
            if curNode.left:
            	# 当前节点
                nodeStack.append(curNode.left)
                # 父节点的累计数值
                numStack.append(curSum)
            if curNode.right:
                nodeStack.append(curNode.right)
                numStack.append(curSum)
        
        return _sum
7.7.4、层次迭代
class Solution:
    def sumNumbers(self, root: TreeNode) -> int:
        if not root: return 0
        
        _sum = 0
        nodeStack = [root]
        numStack = [0]
        while nodeStack:
            for i in range(len(nodeStack)):
                # 父节点
                curNode = nodeStack.pop(0)
                curSum = 10*numStack.pop(0) + curNode.val
            
                if not curNode.left and not curNode.right:
                    _sum += curSum
            
                if curNode.left:
                    nodeStack.append(curNode.left)
                    numStack.append(curSum)
                if curNode.right:
                    nodeStack.append(curNode.right)
                    numStack.append(curSum)
        
        return _sum
八、988. 从叶结点开始的最小字符串 8.1、题目描述 8.2、题解

本题和129. 求根到叶子节点数字之和类似,只是129时比较数值大小,本题比较字典顺序

8.2.1、递归

class Solution:
    def smallestFromLeaf(self, root: TreeNode) -> str:
        self.__dfs(root, '')
        return self.path
    
    def __init__(self) -> None:
        self.path = None

    def __dfs(self, root: TreeNode, path: str) -> None:
        if not root: return 0
        
        # 叶子节点
        if not root.left and not root.right:
            s = chr(97+root.val) + path
            if not self.path:
                self.path = s
            self.path = min(s, self.path)

        # 将父节点的值向下传递
        if root.left:
            self.__dfs(root.left, chr(97+root.val) + path)
        if root.right:
            self.__dfs(root.right, chr(97+root.val) + path)
关注
打赏
1587549273
查看更多评论
立即登录/注册

微信扫码登录

0.0417s