文章目录
513.找树左下角的值
思路
层次遍历找到每层最左边的节点,最后一层的值就是所要求的左下角的值。
时间复杂度On
空间复杂度On
代码
func findBottomLeftValue(root *TreeNode) int {
q:=[]*TreeNode{}
q=append(q,root)
res:=0
for len(q)>0{
isfirst:=true
lenth:=len(q)
for i:=0;i<lenth;i++{
cur:=q[0]
if isfirst{
res=cur.Val
isfirst=false
}
q=q[1:]
if cur.Left!=nil{
q=append(q,cur.Left)
}
if cur.Right!=nil{
q=append(q,cur.Right)
}
}
}
return res
}
困难
使用两层循环区分每一层的节点。
112. 路径总和
思路
递归:
递归参数返回值:参数节点和目标值,返回值能否有到根节点路径为目标值的路径。
终止条件:节点为空,节点为叶子节点
单层递归逻辑:判断左右子节点能否找到路径总和为目标值减去当前节点值的路径。
时间复杂度On
空间复杂度Oh
代码
func hasPathSum(root *TreeNode, targetSum int) bool {
if root==nil{
return false
}
if root.Left==nil&&root.Right==nil&&root.Val==targetSum{
return true
}
return hasPathSum(root.Left,targetSum-root.Val)||hasPathSum(root.Right,targetSum-root.Val)
}
113.路径总和ii
思路
递归回溯
前序遍历递归,记录路径,要记得回溯。
时间复杂度On
空间复杂度On
代码
func pathSum(root *TreeNode, targetSum int) [][]int {
res:=[][]int{}
path:=[]int{}
var dfs func(root *TreeNode, targetSum int)
dfs=func(root *TreeNode, targetSum int){
if root==nil{
return
}
path=append(path,root.Val)
if root.Left==nil&&root.Right==nil&&root.Val==targetSum{
temp:=[]int{}
temp=append(temp,path...)
res=append(res,temp)
}
dfs(root.Left,targetSum-root.Val)
dfs(root.Right,targetSum-root.Val)
path=path[:len(path)-1]
}
dfs(root,targetSum)
return res
}
困难
考虑回溯,同时由于切片是引用类型,要记得copy。
106.从中序与后序遍历序列构造二叉树
106.从中序与后序遍历序列构造二叉树
思路
后序遍历是左右中,中序遍历是左中右
所以可以根据后序遍历的末尾在中序遍历数组中找到对应位置,从而在后序遍历数组中区分左右子树。而对子树的处理又和原来一样,所以可以采用递归的方式。
时间复杂度On
空间复杂度On
官方题解
代码
func buildTree(inorder []int, postorder []int) *TreeNode {
imap:=make(map[int]int)
res:=&TreeNode{}
for k,v:=range inorder{
imap[v]=k
}
var build func(node *TreeNode,i,l,r int)
build = func(node *TreeNode, i,l,r int){
node.Val=postorder[r]
in:=imap[node.Val]
if in-i>l{
node.Left=&TreeNode{}
build(node.Left,i,l,in-1-i)
}
if in-i<r{
node.Right=&TreeNode{}
i++
build(node.Right,i,in-i+1,r-1)
}
}
build(res,0,0,len(postorder)-1)
return res
}
困难
后序遍历对应子树在中序遍历数组的位置是会不断发生偏移的,每判断一次右子树,中序遍历就会往右偏移一位,所以要统计右子树的判断次数,同时将对应位置减去偏移的位数。
if in-i<r{
node.Right=&TreeNode{}
i++
build(node.Right,i,in-i+1,r-1)
}
要注意i++应该放在末尾,防止影响其他递归的参数。
105.从前序与中序遍历序列构造二叉树
105.从前序与中序遍历序列构造二叉树
思路
前序遍历是中左右,中序遍历是左中右
所以可以根据前序遍历的开头在中序遍历数组中找到对应位置,从而在前序遍历数组中区分左右子树。而对子树的处理又和原来一样,所以可以采用递归的方式。
时间复杂度On
空间复杂度On
代码
func buildTree(preorder []int, inorder []int) *TreeNode {
imap:=make(map[int]int)
res:=&TreeNode{}
for k,v:=range inorder{
imap[v]=k
}
var build func(node *TreeNode,i,l,r int)
build = func(node *TreeNode,i,l,r int){
node.Val=preorder[l]
in:=imap[node.Val]
if in+i<r{
node.Right=&TreeNode{}
build(node.Right,i,in+i+1,r)
}
if in+i>l{
node.Left=&TreeNode{}
i++
build(node.Left,i,l+1,in+i-1)
}
}
build(res,0,0,len(preorder)-1)
return res
}
困难
前序遍历对应子树在中序遍历数组的位置是会不断发生偏移的,每判断一次左子树,中序遍历就会往左偏移一位,所以要统计左子树的判断次数,同时将对应位置加上偏移的位数。
if in+i>l{
node.Left=&TreeNode{}
i++
build(node.Left,i,l+1,in+i-1)
}
要注意i++应该放在末尾,防止影响其他递归的参数。
今日收获
对数的递归回溯有了更深刻的认识。
了解了根据前中后序数组递归构造二叉树的算法。