• LeetCode 树 103. 二叉树的锯齿形层次遍历(双端队列 DFS的空间复杂度)


     这道题目乍一看很简单,而且也做出来了,但其实反应出了剑指offer中提出的两个问题

    第一个便是处理小错误和特殊输入的能力,这道题做的过程中出了很多小错误

    第二个是找寻更好算法的能力,这道题有更好的算法。

    首先说原本自己写的算法:
    一开始看到这种锯齿形算法,当然想到的是层序遍历,然后要改变队列先进先出的特性,弄一种能满足题目需要的数据结构(其实就是后面解法的双端队列)。

    但是后来又一想,那不如直接在层序遍历的基础上加一个flag,分奇数偶数层,然后偶数层翻转一下LIst不就行了。

    以下是代码:

    class Solution {
        public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
            Queue<TreeNode> queue=new ArrayDeque<>();
            List<List<Integer>> listReturn=new ArrayList<>();
            if(root==null)
            {return new ArrayList<>();}
            queue.add(root);
            int flag=0;
            while(queue.size()!=0)
            {
                int count=queue.size();
                List<Integer> list=new ArrayList<>();
                for(int i=0;i<count;i++)
                {
                    TreeNode node= queue.poll();
                    if(node.left!=null)
                    {queue.add(node.left);}
                    if(node.right!=null)
                    {queue.add(node.right);}
                    list.add(node.val);
                }
                if(flag==1)
                {
                    Collections.reverse(list);
                    listReturn.add(list);
                    flag=0;
                }
                else
                {
                    listReturn.add(list);
                    flag=1;
                }
            }
            return listReturn;
        }
    }

     写的时候出了几个问题:

    1. 如果树为空,返回什么。之前做了几个类似的题目,知道需要做这个特殊情况的判断,于是也写的是返回null。但这里的要返回的是分层的列表而不是根节点,所以应该直接返回一个空列表。
    2. if(node.left!=null)这个条件开始忘写了,也是够了。。。
    3. 当天写代码的之前写了一些Python的代码,这边一开始list的add都写成了append。看来基本的方法还是要记清楚。

    另外一种算法就很容易想到了,双端队列的方式,直接在数据结构层面就把功能实现了

    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    class Solution {
      public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        if (root == null) {
          return new ArrayList<List<Integer>>();
        }
    
        List<List<Integer>> results = new ArrayList<List<Integer>>();
    
        // add the root element with a delimiter to kick off the BFS loop
        Deque<TreeNode> node_queue = new LinkedList<TreeNode>();
        node_queue.addLast(root);
        node_queue.addLast(null);
    
        LinkedList<Integer> level_list = new LinkedList<Integer>();
        boolean is_order_left = true;
    
        while (node_queue.size() > 0) {
          TreeNode curr_node = node_queue.pollFirst();
          if (curr_node != null) {
            if (is_order_left)
              level_list.addLast(curr_node.val);
            else
              level_list.addFirst(curr_node.val);
    
            if (curr_node.left != null)
              node_queue.addLast(curr_node.left);
            if (curr_node.right != null)
              node_queue.addLast(curr_node.right);
    
          } else {
            // we finish the scan of one level
            results.add(level_list);
            level_list = new LinkedList<Integer>();
            // prepare for the next level
            if (node_queue.size() > 0)
              node_queue.addLast(null);
            is_order_left = !is_order_left;
          }
        }
        return results;
      }
    }

     这里是LeetCode的官方解法,用的是null分层,其实不如直接计数来的明白。

    更偏好这种解法的原因是,每次翻转列表肯定要消耗一定时间,但算法的时间复杂度会不会提升呢?在LeetCode判题中没有提升。。。

    再下一种就是深度优先搜索的办法

    这种算法的逻辑就是,建立一个索引和层数挂钩的List

    然后在DFS中,不需要按照逐层遍历嘛,反正把对应层的节点加入对应level的List节点就行了,当然要根据level的奇数偶数决定顺序插还是反序插。然后他的每一个节点还是用Deque Linkedlist实现的。

    优点在于空间复杂度

    之前层序遍历的空间复杂度是:

     DFS的优点等于是,调用堆栈的空间复杂度是logN级别的,调用队列是ON级别的

    递归调用栈的深度 = 所占空间 = O(H)

    所以这样看DFS在空间复杂度上还是有天然优势啊。。。

    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    class Solution {
      protected void DFS(TreeNode node, int level, List<List<Integer>> results) {
        if (level >= results.size()) {
          LinkedList<Integer> newLevel = new LinkedList<Integer>();
          newLevel.add(node.val);
          results.add(newLevel);
        } else {
          if (level % 2 == 0)
            results.get(level).add(node.val);
          else
            results.get(level).add(0, node.val);
        }
    
        if (node.left != null) DFS(node.left, level + 1, results);
        if (node.right != null) DFS(node.right, level + 1, results);
      }
    
      public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        if (root == null) {
          return new ArrayList<List<Integer>>();
        }
        List<List<Integer>> results = new ArrayList<List<Integer>>();
        DFS(root, 0, results);
        return results;
      }
    }
  • 相关阅读:
    vue学习6
    vue学习5
    vue学习3
    vue学习2
    vue学习1
    idea快速查找和替换快捷键
    mysql三元表达式
    1 Java Lambda表达式forEach无法跳出循环的解决思路
    6 Mybatis Plus and 和 or,分页Page使用
    4 Mybatis Plus使用redis作为二级缓存
  • 原文地址:https://www.cnblogs.com/take-it-easy/p/13321206.html
Copyright © 2020-2023  润新知