资讯专栏INFORMATION COLUMN

[Leetcode] Binary Tree Traversal 二叉树遍历

RaoMeng / 3165人阅读

摘要:栈迭代复杂度时间空间递归栈空间对于二叉树思路用迭代法做深度优先搜索的技巧就是使用一个显式声明的存储遍历到节点,替代递归中的进程栈,实际上空间复杂度还是一样的。对于先序遍历,我们出栈顶节点,记录它的值,然后将它的左右子节点入栈,以此类推。

Binary Tree Preorder Traversal

Given a binary tree, return the preorder traversal of its nodes" values.

For example: Given binary tree {1,#,2,3},

   1
    
     2
    /
   3

return [1,2,3].

栈迭代 复杂度

时间 O(b^(h+1)-1) 空间 O(h) 递归栈空间 对于二叉树b=2

思路

用迭代法做深度优先搜索的技巧就是使用一个显式声明的Stack存储遍历到节点,替代递归中的进程栈,实际上空间复杂度还是一样的。对于先序遍历,我们pop出栈顶节点,记录它的值,然后将它的左右子节点push入栈,以此类推。

代码
public class Solution {
    public List preorderTraversal(TreeNode root) {
        Stack s = new Stack();
        List res = new LinkedList();
        if(root!=null) s.push(root);
        while(!s.isEmpty()){
            TreeNode curr = s.pop();
            res.add(curr.val);
            if(curr.right!=null) s.push(curr.right);
            if(curr.left!=null) s.push(curr.left);
        }
        return res;
    }
}
Binary Tree Inorder Traversal

Given a binary tree, return the inorder traversal of its nodes" values.

For example: Given binary tree {1,#,2,3},

   1
    
     2
    /
   3

return [1,3,2].

栈迭代 复杂度

时间 O(b^(h+1)-1) 空间 O(h) 递归栈空间 对于二叉树b=2

思路

用栈中序遍历没有先序遍历那么直观,因为我们不能马上pop出当前元素,而要先把它的左子树都遍历完才能pop它自己。所有我们先将将最左边的所有节点都push进栈,然后再依次pop并记录值,每pop一个元素后再看它有没有右子树,如果右的话,我们再将它的右节点和右子树中最左边的节点都push进栈,再依次pop。

代码
public class Solution {
    public List inorderTraversal(TreeNode root) {
        List res = new LinkedList();
        Stack s = new Stack();
        //先将最左边的节点都push进栈
        if(root!=null){
            pushAllTheLeft(s, root);
        }
        while(!s.isEmpty()){
            TreeNode curr = s.pop();
            res.add(curr.val);
            //如果有右子树,将右节点和右子树的最左边的节点都push进栈
            if(curr.right != null){
                pushAllTheLeft(s, curr.right);
            }
        }
        return res;
    }
    
    private void pushAllTheLeft(Stack s, TreeNode root){
        s.push(root);
        while(root.left!=null){
            root = root.left;
            s.push(root);
        }
    }
}
Binary Tree Postorder Traversal

Given a binary tree, return the postorder traversal of its nodes" values.

For example: Given binary tree {1,#,2,3},

   1
    
     2
    /
   3

return [3,2,1].

栈迭代 复杂度

时间 O(b^(h+1)-1) 空间 O(h) 递归栈空间 对于二叉树b=2

思路

后序遍历就不能简单的改变pop顺序来实现了,我们知道根节点(这里的根节点不是整个树的根,而是相对于左右节点的跟)是在左右节点都计算完才计算的,所以我们会遇到两次根节点,第一次遇到根节点时我们将左右节点加入栈,但不把根节点pop出去,等到处理完左右节点后,我们又会遇到一次根节点,这时再计算根节点并把它pop出去。为了判断是第一次还是第二次遇到这个根节点,我们可以用一个数据结构把这个信息封装进去,第一次遇到的时候将其设为已经访问了一次,这样第二次遇到时发现已经访问了一次,就可以直接pop了。

代码
public class Solution {
    public List postorderTraversal(TreeNode root) {
        Stack s = new Stack();
        List res = new LinkedList();
        if(root!=null) s.push(new PowerNode(root, false));
        while(!s.isEmpty()){
            PowerNode curr = s.peek();
            //如果是第二次访问,就计算并pop该节点
            if(curr.visited){
                res.add(curr.node.val);
                s.pop();
            } else {
            //如果是第一次访问,就将它的左右节点加入stack,并设置其已经访问了一次
                if(curr.node.right!=null) s.push(new PowerNode(curr.node.right, false));
                if(curr.node.left!=null) s.push(new PowerNode(curr.node.left, false));
                curr.visited = true;
            }
        }
        return res;
    }
    
    private class PowerNode {
        TreeNode node;
        boolean visited;
        public PowerNode(TreeNode n, boolean v){
            this.node = n;
            this.visited = v;
        }
    }
}
反向法 复杂度

时间 O(b^(h+1)-1) 空间 O(h) 递归栈空间 对于二叉树b=2

思路

还有一种更巧妙的方法,因为后序遍历的顺序是left - right - root,虽然我们不方便直接得到这个顺序,但是它的逆序还是很好得到的,我们可以用root - right - left的顺序遍历树,然后反向添加结果就行了。

代码
public class Solution {
    public List postorderTraversal(TreeNode root) {
        Stack stk = new Stack();
        if(root != null) stk.push(root);
        LinkedList res = new LinkedList();
        while(!stk.isEmpty()){
            TreeNode curr = stk.pop();
            // 先添加左后添加右,就是先访问右后访问左
            if(curr.left != null) stk.push(curr.left);
            if(curr.right != null) stk.push(curr.right);
            // 反向添加结果,每次加到最前面
            res.offerFirst(curr.val);
        }
        return res;
    }
}
Binary Tree Level Order Traversal I && II

Given a binary tree, return the bottom-up level order traversal of its nodes" values. (ie, from left to right, level by level from leaf to root).

For example: Given binary tree {3,9,20,#,#,15,7},

    3
   / 
  9  20
    /  
   15   7

return its bottom-up level order traversal as: (II)

[
  [15,7],
  [9,20],
  [3]
]

return its level order traversal as: (I)

[
  [3],
  [9,20],
  [15,7]
]
队列迭代 复杂度

时间 O(b^(h+1)-1) 空间 O(b^h)

思路

本题实质是广度优先搜索BFS,而用队列可以轻松的以迭代形式实现它。不过不同于BFS的是,层序遍历需要在队列中记住每一层的分割点,而BFS不关心层数只要遍历到指定元素就行了。为了记住这个分割点,我们在进入下一层之前先记下这一层的元素个数N(其实就是当前queue的大小),然后只遍历N个节点(展开下一层节点的同时queue中会新加入很多下下一层的节点)。遍历完N个节点后记录新的层数,再进入下一层。对于II,返回的层是逆序的,我们只要在结果中,每次把下面新一层加到当前这层的前面就行了

代码
public class Solution {
    public List> levelOrder(TreeNode root) {
        List> res = new LinkedList>();
        Queue q = new LinkedList();
        if(root != null) q.offer(root);
        while(!q.isEmpty()){
            int size = q.size();
            List level = new LinkedList();
            //控制当前层的遍历次数
            for(int i =0; i < size; i++){
                TreeNode curr = q.poll();
                level.add(curr.val);
                if(curr.left!=null) q.offer(curr.left);
                if(curr.right!=null) q.offer(curr.right);
            }
            res.add(level);
            //对于II, 我们要逆序加入
            //res.add(0, level)
        }
        return res;
    }
}
Binary Tree Zigzag Level Order Traversal

Given a binary tree, return the zigzag level order traversal of its nodes" values. (ie, from left to right, then right to left for the next level and alternate between).

For example: Given binary tree {3,9,20,#,#,15,7},

    3
   / 
  9  20
    /  
   15   7

return its zigzag level order traversal as:

[
  [3],
  [20,9],
  [15,7]
]
队列迭代 复杂度

时间 O(b^(h+1)-1) 空间 O(b^h)

思路

ZigZag遍历时,奇数层正序记录,偶数层逆序记录。可以通过结果中已有的层数来判断。

代码
public class Solution {
    public List> zigzagLevelOrder(TreeNode root) {
        List> res = new LinkedList>();
        Queue q = new LinkedList();
        if(root != null) q.offer(root);
        while(!q.isEmpty()){
            int size = q.size();
            List level = new LinkedList();
            for(int i =0; i < size; i++){
                TreeNode curr = q.poll();
                //根据结果中已有的层数控制正序还是逆序
                if(res.size() % 2 == 0){
                    level.add(curr.val);
                } else {
                    level.add(0,curr.val);
                }
                if(curr.left!=null) q.offer(curr.left);
                if(curr.right!=null) q.offer(curr.right);
            }
            res.add(level);
        }
        return res;
    }
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/64468.html

相关文章

  • LeetCode 之 JavaScript 解答第94题 —— 叉树的中序遍历

    摘要:小鹿题目二叉树中序遍历给定一个二叉树,返回它的中序遍历。通常递归的方法解决二叉树的遍历最方便不过,但是我还是喜欢增加点难度,用一般的迭代循环来实现。 Time:2019/4/25Title:Binary Tree Inorder TraversalDifficulty: MediumAuthor:小鹿 题目:Binary Tree Inorder Traversal(二叉树中序遍历...

    Jason 评论0 收藏0
  • leetcode-102-Binary Tree Level Order Traversal

    102. 二叉树的层次遍历 题目描述 给定一个二叉树,返回其按层次遍历的节点值。 (即zhucengde,从左到右访问)。 例如: 给定二叉树: [3,9,20,null,null,15,7], 3 / 9 20 / 15 7 返回其层次遍历结果为: [ [3], [9,20], [15,7] ] class Solution: def le...

    widuu 评论0 收藏0
  • LeetCode通关:连刷三十九道叉树,刷疯了!⭐四万字长文搞定叉树,建议收藏!⭐

    分门别类刷算法,坚持,进步! 刷题路线参考:https://github.com/youngyangyang04/leetcode-master 大家好,我是拿输出博客来督促自己刷题的老三,这一节我们来刷二叉树,二叉树相关题目在面试里非常高频,而且在力扣里数量很多,足足有几百道,不要慌,我们一步步来。我的文章很长,你们 收藏一下。 二叉树基础 二叉树是一种比较常见的数据结构,在开始刷二叉树...

    honhon 评论0 收藏0
  • leetcode讲解--94. Binary Tree Inorder Traversal

    摘要:题目地址嗯,经典的题目,中序遍历二叉树。代码如下中序遍历先序遍历后序遍历是不是简单的不要不要的,递归就是这么美。右孩子后压栈全部释放出来嗯,总的来说用迭代遍历确实烧脑,没什么性能上的特殊需求还是用递归写法吧,对程序员友好哦。 94. Binary Tree Inorder Traversal Given a binary tree, return the inorder travers...

    henry14 评论0 收藏0
  • leetcode-145-Binary Tree Postorder Traversal

    摘要:栈的意义价值具有时间性,先进后出。比如递归的后序遍历,先序遍历,二叉树的按层次打印。根据需求不同,在中暂时储存的元素单元也不同,元素的先后顺序也不同。应用对顺序有要求的数据。 stack 栈的意义价值: 具有时间性,先进后出。 所以具有时间关联顺序的元素可以通过这个时间。 比如递归的后序遍历,先序遍历, 二叉树的按层次打印。 根据需求不同,在stack中暂时储存的元素...

    Pandaaa 评论0 收藏0

发表评论

0条评论

RaoMeng

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<