1、题目
2、题解
思路一:首先想到的就是通过前序遍历将节点存入列表中,然后依次遍历列表构建满足要求的单链表。借助栈的数据结构,实现代码如下:
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func flatten(root *TreeNode) {
if root!=nil{
var n *TreeNode
l, s:=[]*TreeNode{}, []*TreeNode{root}
for len(s)>0{
n=s[len(s)-1]
s=s[:len(s)-1]
l=append(l, n)
if n.Right!=nil{s=append(s, n.Right)}
if n.Left!=nil{s=append(s, n.Left)}
}
for i:=1; i<len(l); i++{
l[i-1].Left, l[i-1].Right=nil, l[i]
}
}else{
return
}
}
提交结果如下
思路二:基于思路一进行改进,不再将结果存储在列表中然后再构建重新排序后的列表,而是在先序遍历的过程中完成列表节点的重新排序,始终记录上一节点,遍历到当前节点时与上一节点重新链接,实现代码如下:
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func flatten(root *TreeNode) {
if root!=nil{
var last *TreeNode
stack:=[]*TreeNode{root}
for len(stack)>0 {
now:=stack[len(stack)-1]
stack=stack[:len(stack)-1]
if last!=nil { last.Left, last.Right = nil, now }
if now.Right!=nil { stack=append(stack, now.Right) }
if now.Left!=nil { stack=append(stack, now.Left) }
last=now
}
}else{ return }
}
提交结果如下,空间消耗略有提升
思路三:看题解后感觉到新的解法,寻找节点的前驱节点,当前节点的右子树的前驱节点必然是左子树最右端的节点,实际的过程如下所示
1 1 1 1 1
/ \ (1) / (2) \ (3) \ (4) \
2 5 ————> 2 ————> 2 ————> 2 ————> 2
/ \ \ / \ / \ / \
3 4 6 3 4 3 4 3 3
\ \ \ \
5 5 4 4
\ \ \ \
6 6 5 5
\ \
6 6
按如上方式实现代码如下,中间踩了一个无语的坑,把cur=cur.Right放在了if中,导致运行时一直死循环。
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func flatten(root *TreeNode) {
if root!=nil {
var pre, cur *TreeNode
cur=root
for cur!=nil {
if cur.Left!=nil {
pre=cur.Left
for pre.Right!=nil { pre=pre.Right }
pre.Right=cur.Right
n:=cur.Left
cur.Left, cur.Right=nil ,n
}
cur=cur.Right
}
}else{ return }
}
提交结果如下,空间消耗明显降低
总结:在针对树的遍历中,根据节点的进出顺序确定需要的数据结构是队列或者栈。