二叉树展开为链表——DFS

111 阅读2分钟
image.png

方法一

  1. 将右子树接到左子树的最右节点
  2. 左子树接到原右子树的位置
  3. 原左子树的位置变为nil
  4. 解决新右子树根节点

image.png

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
var pre *TreeNode
func flatten(root *TreeNode)  {
    pre = nil
    dfs(root)
}
func dfs(root *TreeNode){
    if root == nil {
        return 
    }
    dfs(root.Right)
    dfs(root.Left)
    root.Right = pre
    root.Left = nil
    pre = root
}

方法二

题目其实就是将二叉树通过右指针,组成一个链表。
我们知道题目给定的遍历顺序其实就是先序遍历的顺序,所以我们能不能利用先序遍历的代码,每遍历一个节点,就将上一个节点的右指针更新为当前节点。

先序遍历的顺序是 1 2 3 4 5 6。

遍历到 2,把 1 的右指针指向 2。1 -> 2 3 4 5 6。

遍历到 3,把 2 的右指针指向 3。1 -> 2 -> 3 4 5 6。

... ...

一直进行下去似乎就解决了这个问题。但现实是残酷的,原因就是我们把 1 的右指针指向 2,那么 1 的原本的右孩子就丢失了,也就是 5 就找不到了。

解决方法的话,我们可以逆过来进行。

我们依次遍历 6 5 4 3 2 1,然后每遍历一个节点就将当前节点的右指针更新为上一个节点。

遍历到 5,把 5 的右指针指向 6。6 <- 5 4 3 2 1。

遍历到 4,把 4 的右指针指向 5。6 <- 5 <- 4 3 2 1。

... ...

遍历方法 :

  1. 处理当前右节点
  2. 处理当前左节点
  3. 处理当前节点(记录当前节点)
var pre *TreeNode
func flatten(root *TreeNode)  {
    pre = nil
    dfs(root)
}
func dfs(root *TreeNode){
    if root == nil {
        return 
    }
    dfs(root.Right)
    dfs(root.Left)
    root.Right = pre
    root.Left = nil
    pre = root
}

便利方法:
如果直接使用前序遍历,必须记录返回值,当前的左子树有右节点返回右节点,没有则返回左节点,都没有则返回自身。

func flatten(root *TreeNode)  {
    if root == nil{
        return
    }
    dfs(root)
    return
}

func dfs (root *TreeNode) *TreeNode {
    var x,y *TreeNode
    if root.Left == nil && root.Right == nil {
        return root
    }
    if root.Left != nil && root.Right != nil{
        x = dfs(root.Left)
        y = dfs(root.Right)
        x.Right = root.Right
        root.Right = root.Left
        root.Left = nil
    }
    if root.Left == nil{
        y = dfs(root.Right)
    }
    if root.Right == nil{
        y = dfs(root.Left)
        root.Right = root.Left
        root.Left = nil
    }
    return y
}