leet-code 所有二叉树路径问题

参考总结

二叉树路径的问题大致可以分为两类:
1、自顶向下:
顾名思义,就是从某一个节点(不一定是根节点),从上向下寻找路径,到某一个节点(不一定是叶节点)结束
具体题目如下:

257 从根到叶所有路径

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
var res []string
var path []int
func binaryTreePaths(root *TreeNode) []string {
    //自顶向下,DFS前序遍历
    res=nil
    path=nil
    helper(root)
    return res
}
func helper(root *TreeNode){
    if root==nil{
        return 
    }
    path=append(path,root.Val)
    if root.Left==nil&&root.Right==nil{
        var finalRes string
        for i:=0;i<len(path)-1;i++{
            finalRes+=strconv.Itoa(path[i])+"->"
        }
        finalRes+=strconv.Itoa(path[len(path)-1])
        res=append(res,finalRes)
    }
    helper(root.Left)
    helper(root.Right)
    path=path[0:len(path)-1]//pop back
    return
}

112 从根到叶路径和满足目标值

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func hasPathSum(root *TreeNode, targetSum int) bool {
    if root==nil{
        return false
    }
    if root.Left==nil&&root.Right==nil{
        return root.Val==targetSum
    }
    return hasPathSum(root.Left,targetSum-root.Val)||hasPathSum(root.Right,targetSum-root.Val)
}

113 从根到叶路径和满足目标值的路径

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
var res [][]int
var path[]int
func pathSum(root *TreeNode, targetSum int) [][]int {
    res=nil
    path=nil
    dfs(root,targetSum)
    return res
}

func dfs(root *TreeNode, targetSum int){
    if root==nil{
        return 
    }
    path=append(path,root.Val)
    targetSum-=root.Val
    if root.Left==nil&&root.Right==nil{
        //fmt.Println(root.Val,path,targetSum)
        if targetSum==0{
            var finalPath []int
            finalPath=append([]int(nil),path...)
            res=append(res,finalPath)
        }
    }
    dfs(root.Left,targetSum)
    dfs(root.Right,targetSum)
    path=path[0:len(path)-1]//pop back
    return
}

437 路径总和3,任意节点到节点,从上到下

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func pathSum(root *TreeNode, targetSum int) int {
    if root==nil{
        return 0
    }
    //先调用dfs函数从root开始查找路径,再调用pathsum函数到root左右子树开始查找这样实现从任意节点开始
    res:=helper(root,targetSum)
    res+=pathSum(root.Left,targetSum)
    res+=pathSum(root.Right,targetSum)
    return res
}

func helper(root *TreeNode, targetSum int)int{
    if root==nil{
        return 0
    }
    innerRes:=0
    targetSum-=root.Val
    //如果找到了一个路径全局变量就+1
    if targetSum==0{
        //fmt.Println("s",res)
        //注意不要return,因为不要求到叶节点结束,所以一条路径下面还可能有另一条
        innerRes++
    }
    innerRes+=helper(root.Left,targetSum)
    innerRes+=helper(root.Right,targetSum)
    return innerRes
}

988 从叶节点到根节点的最小字符串

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
 var path[]string
var sliceStr= []string{"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o",
		"p","q","r","s","t","u","v","w","x","y","z"}
func smallestFromLeaf(root *TreeNode) string {
    path=nil
    dfs(root,"")
    //按小到大排序
    sort.Strings(path)
    return path[0]//字典序最小
}

func dfs(root *TreeNode, str string){
    if root==nil{
        return
    }
    str+=sliceStr[root.Val]
    if root.Left==nil&&root.Right==nil{
        //leave
        str=reverse(str)//题目要求从叶节点到根节点,因此反转
        path=append(path,str)
        return
    }
    dfs(root.Left,str)
    dfs(root.Right,str)
    return
}

func reverse(str string)string{
    var res string
    for i:=0;i<len(str);i++{
        res+=fmt.Sprintf("%c",str[len(str)-1-i])
    }
    return res
}

非自顶向下

这类题目一般解题思路如下:
设计一个辅助函数maxpath,调用自身求出以一个节点为根节点的左侧最长路径left和右侧最长路径right,那么经过该节点的最长路径就是left+right
接着只需要从根节点开始dfs,不断比较更新全局变量即可

这类题型DFS注意点:
1、left,right代表的含义要根据题目所求设置,比如最长路径、最大路径和等等

2、全局变量res的初值设置是0还是INT_MIN要看题目节点是否存在负值,如果存在就用INT_MIN,否则就是0

3、注意两点之间路径为1,因此一个点是不能构成路径的

124 二叉树中的最大路径和

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
 /*
 定义一个递归方法,从下到上递归,后续遍历。
 1. 每个节点的贡献:
    1.1 空节点的最大贡献值等于 0;
    1.2 非空节点的最大贡献值等于节点值与其子节点中的最大贡献值之和
 2. 每个接的的最大路径和:
    该节点的最大路径和取决于该节点的值与该节点的左右子节点的最大贡献值,如果子节点的最大贡献值为正,则计入该节点的最大路径和,否则不计入该节点的最大路径和。维护一个全局变量 maxSum 存储最大路径和,在递归过程中更新 maxSum 的值,最后得到的 maxSum 的值即为二叉树中的最大路径和
 参考:
    1.https://leetcode-cn.com/problems/binary-tree-maximum-path-sum/solution/cchao-jian-dan-li-jie-miao-dong-by-fengz-8l3m/
    2.https://leetcode-cn.com/problems/binary-tree-maximum-path-sum/solution/er-cha-shu-zhong-de-zui-da-lu-jing-he-by-leetcode-/ 
 */
var maxV int
func maxPathSum(root *TreeNode) int {
    if root==nil{
        return 0
    }
    maxV=INTMIN
    dfs(root)
    return maxV
}
//通过后序遍历的方式,先计算出左右子树的最大路径和,然后再计算当前树的最大路径和
func dfs(root *TreeNode)int {
    if root==nil{
        return 0
    }
    //计算左边分支最大值,左边分支如果为负数还不如不选择
    leftV:=max(0,dfs(root.Left))
    //计算右边分支最大值,右边分支如果为负数还不如不选择
    rightV:=max(0,dfs(root.Right))
    //一个子树内部的最大路径和 = 左子树提供的最大路径和 + 根节点值 + 右子树提供的最大路径和,作为路径与已经计算过历史最大值做比较
    maxV=max(maxV,root.Val+leftV+rightV)
    //返回当前子树对外提供的贡献
    return root.Val+max(leftV,rightV)
}

func max(x,y int)int {
    if x<y{
        return y
    }
    return x
}
const INTMAX=int(^uint(0)>>1)
const INTMIN=^INTMAX

687 最长同值路径

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
 var res int
func longestUnivaluePath(root *TreeNode) int {
    res=0
    if root==nil{
        return res
    }
    longestPath(root)
    return res
}
func longestPath(root *TreeNode)int {
    if root==nil{
        return 0
    }
    leftV:=longestPath(root.Left)
    rightV:=longestPath(root.Right)
    // 如果存在左子节点和根节点同值,更新左最长路径;否则左最长路径为0
    if root.Left!=nil&&root.Val==root.Left.Val{
        leftV++
    }else{
        leftV=0
    }
    // 如果存在右子节点和根节点同值,更新右最长路径;否则右最长路径为0
    if root.Right!=nil&&root.Val==root.Right.Val{
        rightV++
    }else{
        rightV=0
    }
    res=max(res,leftV+rightV)
    return max(leftV,rightV)
}
func max(x,y int)int {
    if x<y {
        return y
    }
    return x
}

543 二叉树直径

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
 var res int=0
func diameterOfBinaryTree(root *TreeNode) int {
    res=0
    if root==nil{
        return res
    }
    maxPath(root)
    return res
}

func maxPath(root *TreeNode)int{
    if root.Left==nil&&root.Right==nil{
        return 0
    }
    var leftV int
    //判断左子节点是否为空,从而更新左边最长路径
    if root.Left!=nil{
        leftV=maxPath(root.Left)+1
    }else{
        leftV=0
    }
    var RightV int
    if root.Right!=nil{
        RightV=maxPath(root.Right)+1
    }else{
        RightV=0
    }
    res=max(res,leftV+RightV)//全局最长路径
    return max(leftV,RightV)//返回以root点开始能提供的最长路径
}

func max(x, y int)int {
    if x<y {
        return y
    }
    return x
}

563 二叉树坡度

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
var res int
func findTilt(root *TreeNode) int {
    res=0
    postorder(root)
    return res
}
//root节点可以提供的子树节点和
func postorder(root *TreeNode)int{
    if root==nil{
        return 0
    }
    left:=postorder(root.Left)
    right:=postorder(root.Right)
    cur:=abs(left-right)//root节点的左右子树的坡度,更新全局变量
    res+=cur
    return root.Val+left+right//root节点可以提供的子树节点和
}

func abs(x int)int {
    if x<0{
        return -1*x
    }
    return x
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
探险家小扣的行动轨迹,都将保存在记录仪中。expeditions[i] 表示小扣第 i 次探险记录,用一个字符串数组表示。其中的每个「营地」由大小写字母组成,通过子串 -> 连接。例:"Leet->code->Campsite",表示到访了 "Leet"、"code"、"Campsite" 三个营地。expeditions[0] 包含了初始小扣已知的所有营地;对于之后的第 i 次探险(即 expeditions[i] 且 i > 0),如果记录中包含了之前均没出现的营地,则表示小扣 新发现 的营地。 请你找出小扣发现新营地最多且索引最小的那次探险,并返回对应的记录索引。如果所有探险记录都没有发现新的营地,返回 -1。注意: 大小写不同的营地视为不同的营地; 营地的名称长度均大于 0。用python实现。给你几个例子:示例 1: 输入:expeditions = ["leet->code","leet->code->Campsite->Leet","leet->code->leet->courier"] 输出:1 解释: 初始已知的所有营地为 "leet" 和 "code" 第 1 次,到访了 "leet"、"code"、"Campsite"、"Leet",新发现营地 2 处:"Campsite"、"Leet" 第 2 次,到访了 "leet"、"code"、"courier",新发现营地 1 处:"courier" 第 1 次探险发现的新营地数量最多,因此返回 1。示例 2: 输入:expeditions = ["Alice->Dex","","Dex"] 输出:-1 解释: 初始已知的所有营地为 "Alice" 和 "Dex" 第 1 次,未到访任何营地; 第 2 次,到访了 "Dex",未新发现营地; 因为两次探险均未发现新的营地,返回 -1
最新发布
04-23
我的理解是,你想让我编写一段 Python 代码,实现一个算法,用于在给定的探险记录中找到发现新营地最多且索引最小的探险记录。 那么首先,我需要解析题目中的输入输出要求。 输入要求: - expeditions:一个字符串数组,表示小扣第一次到访的所有营地,和之后的每次探险记录(一个记录就是一个字符串,其中营地通过子串 -> 连接)。 输出要求: - 如果所有的探险记录都没有发现新的营地,则返回 -1; - 否则,返回发现新营地最多且索引最小的探险记录的索引。注:探险记录的索引从 0 开始计数。 接下来,我可以考虑如何编写代码来解决这个问题。 我的思路是,首先用一个集合记录所有已知的营地名称,然后遍历每个探险记录,依次将其中的营地名称加入到集合中,并判断是否有新的营地被发现。 如果某个探险记录中发现了新的营地,那么我就记录下发现了多少个新营地,以及这个探险记录的索引。最后,遍历所有的探险记录,找到发现新营地最多且索引最小的记录。 代码如下: ```python def find_new_camp(expeditions): known_camps = set() # 已知的营地集合 max_new_camps = 0 # 最多的新营地数量 max_new_camps_index = -1 # 最多新营地数量的探险记录的索引 for i in range(len(expeditions)): sub_camps = expeditions[i].split("->") # 提取探险记录中所有的营地名称 num_new_camps = 0 # 记录这个探险记录发现的新营地数量 for camp in sub_camps: if camp not in known_camps: # 如果这个营地是新的,就记录一下 known_camps.add(camp) num_new_camps += 1 if num_new_camps > max_new_camps: # 如果发现了更多的新营地,就更新最大值和索引 max_new_camps = num_new_camps max_new_camps_index = i return max_new_camps_index if max_new_camps > 0 else -1 ``` 我使用了两个变量 `max_new_camps` 和 `max_new_camps_index` 来记录已经遍历过的探险记录中,发现了最多的新营地数量,以及具有最多新营地数量的探险记录的索引。然后我遍历所有的探险记录,统计其中发现的新营地数量,如果大于当前的最大值,就更新 `max_new_camps` 和 `max_new_camps_index` 变量。最后,如果发现了新的营地,就返回 `max_new_camps_index`。如果所有的探险记录都没有发现新营地,就返回 -1。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值