参考总结
二叉树路径的问题大致可以分为两类:
1、自顶向下:
顾名思义,就是从某一个节点(不一定是根节点),从上向下寻找路径,到某一个节点(不一定是叶节点)结束
具体题目如下:
/**
* 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
}
/**
* 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)
}
/**
* 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
}
/**
* 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
}
/**
* 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,因此一个点是不能构成路径的
/**
* 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
/**
* 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
}
/**
* 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
}
/**
* 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
}