第一题 二叉树的锯齿形层次遍历

题目

image.png

解题思路

题目为普通的树的层次遍历
用广搜可以轻松的完成该题
具体思路与该题类似 https://segmentfault.com/a/11...
区别只是在于
加入了对从左到右与从右到左的判断
image.png

代码

变量介绍

queue:双端队列
level:当前遍历所在的层次
q:保存当前队列的数据
val:数组切片,每遍历一层节点由它带回该层的数据,若为奇数,则反转

具体代码

func zigzagLevelOrder(root *TreeNode) (ans [][]int) {
    if root == nil {
        return
    }
    queue := []*TreeNode{root}
    for level := 0; len(queue) > 0; level++ {
        vals := []int{}
        q := queue
        queue = nil
        //遍历队列q生成下一层的节点队列,并且将当前队列的值加入val数组准备输出
        for _, node := range q {
            vals = append(vals, node.Val)
            if node.Left != nil {
                queue = append(queue, node.Left)
            }
            if node.Right != nil {
                queue = append(queue, node.Right)
            }
        }
        // 本质上和层序遍历一样,我们只需要把奇数层的元素翻转即可
        if level%2 == 1 {
            for i, n := 0, len(vals); i < n/2; i++ {
                vals[i], vals[n-1-i] = vals[n-1-i], vals[i]
            }
        }
        ans = append(ans, vals)
    }
    return
}

复杂度分析

时间复杂度:O(N),其中 N 为二叉树的节点数。每个节点会且仅会被遍历一次。

空间复杂度:O(N)。我们需要维护存储节点的队列和存储节点值的双端队列,空间复杂度为 O(N)。

第二题 从前序与中序遍历序列构造二叉树

题目

image.png

解题思路

由于先序遍历的顺序为根节点-左子树-右子树
先序遍历的第一个节点必然为根节点
preorder和inorder均无重复元素
中序遍历的顺序为左子树-根节点-右子树
因此我们可以在中序遍历序列中得到被根节点划分出来的两个子树
再回到先序遍历中找到这两个子树继续进行构造操作

由此可见
递归是解决这道题的最方便的办法

代码

func buildTree(preorder []int, inorder []int) *TreeNode {
    if len(preorder) == 0 {
        return nil
    }
    //根节点
    root := &TreeNode{preorder[0], nil, nil}
    i := 0
    //在中序遍历序列中找到根节点
    for ; i < len(inorder); i++ {
        if inorder[i] == preorder[0] {
            break
        }
    }
    //构造左子树和右子树
    root.Left = buildTree(preorder[1:len(inorder[:i])+1], inorder[:i])
    root.Right = buildTree(preorder[len(inorder[:i])+1:], inorder[i+1:])
    return root
}

复杂度分析

时间复杂度:O(n),其中 n 是树中的节点个数。

空间复杂度:O(n),除去返回的答案需要的 O(n) 空间之外,以及 O(h)(其中 h 是树的高度)的空间表示递归时栈空间。这里 h<n,所以总空间复杂度为 O(n)。

//有使用空间存储哈希映射吗,为什么官解的复杂度分析有提这个