算法通关村—原来如此简单

1. 基本的层序遍历与变换

1.1 入门级

算法通关村—原来如此简单_第1张图片
输出结果为 3 9 20 15 7

    public static List<Integer> getResult(TreeNote root) {
        if (root == null) return new ArrayList<>();
        List<Integer> list = new ArrayList<>();
        LinkedList<TreeNote> queue = new LinkedList<>();
        // 放入根节点
        queue.add(root);
        // 只有当队列不为空的时候
        while (queue.size() > 0) {
            TreeNote treeNote = queue.remove();
            list.add(treeNote.val);
            if (treeNote.leftNode != null) {
                queue.add(treeNote.leftNode);
            }
            if (treeNote.rightNode != null) {
                queue.add(treeNote.rightNode);
            }
        }
        return list;
    }

2. 二叉树的层序遍历

二叉树的层序遍历
给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)

输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]

可以看出,基本的步骤都一样,唯一的差别在于,现在需要将每一层的节点元素放入单独的list集合里面去

 public List<List<Integer>> levelOrder(TreeNode root) {
        if(root == null) return new ArrayList<List<Integer>> ();
        // 记录结果
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        LinkedList<TreeNode> queue= new LinkedList<>();
        // 添加root
        queue.add(root);
        while(queue.size()>0){
            // 记录当前一行的节点条数
           int size = queue.size();
           ArrayList<Integer> list = new ArrayList<>();
           // 队列元素放入list
           for(int i =0;i<size;i++){
               TreeNode node =queue.remove();
               list.add(node.val);

               if(node.left!=null){
                   queue.add(node.left);
               }
               if(node.right!=null){
                   queue.add(node.right);
               }
           }

           res.add(list);
        }
        return res;
    }

3. 二叉树的层序遍历 II

107. 二叉树的层序遍历 II
给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
输入:root = [3,9,20,null,null,15,7]
输出:[[15,7],[9,20],[3]]

3.1 层序+逆序

初始想法就是依然正向添加元素,然后将List里面元素逆序排序list,但是不知道是否可行。

public List<List<Integer>> levelOrderBottom(TreeNode root) {
        if(root == null) return new ArrayList<List<Integer>>();
        ArrayList<List<Integer>> res = new ArrayList<List<Integer>>();
        LinkedList<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while(queue.size()>0){
            int size = queue.size();
            ArrayList<Integer> list = new ArrayList<>();
            for(int i=0;i<size;i++){
                TreeNode node = queue.remove();
                list.add(node.val);
                if(node.left!=null) queue.add(node.left);
                if(node.right!=null) queue.add(node.right);
            }
            res.add(list);
        }
        // 工具逆序
        Collections.reverse(res);
        return res;
    }

算法通关村—原来如此简单_第2张图片
实际发现,结果速度还是很快的,而且比第二题速度还快。

3.2 新列表添加到列表头部

这种思路就是一开始定义列表,将新列表添加至列表的头部,就完成了逆序。

public List<List<Integer>> levelOrderBottom(TreeNode root) {
        List<List<Integer>> levelOrder = new LinkedList<List<Integer>>();
        if(root == null) return levelOrder;
        LinkedList<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(queue.size()>0){
            int size = queue.size();
            List<Integer> level = new ArrayList<Integer>();
            for(int i=0;i<size;i++){
                TreeNode node = queue.poll();
                level.add(node.val);
                if(node.left!=null) queue.add(node.left);
                if(node.right!=null) queue.add(node.right);
            }

            levelOrder.add(0,level);
        }
        return levelOrder;
    }

算法通关村—原来如此简单_第3张图片

两种思路都差不多,都是将列表里面的列表元素逆序。

4. 二叉树的锯齿形层序遍历

103. 二叉树的锯齿形层序遍历
给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。

输入:root = [3,9,20,null,null,15,7]
输出:[[3],[20,9],[15,7]]

依然是先写出简单方法,只不过列表里面的列表元素需要根据左右左右进行排序,思路主要是先定义一个布尔状态标识现在是先左子树还是右子树。 添加列表元素的时候采用Deque来存储,因为里面有addFirst和addLast方法,当此时是从左往右遍历,那么就将其添加到last位置,最后需要转换为ArrayList。

Deque特点:双端队列,两端都可添加和删除元素。
Queue特点:单端队列,只能一段添加,另一端删除元素。
这一题主要考察的是树和双端队列。

public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        if(root == null)  return new ArrayList<List<Integer>>();
        List<List<Integer>> res = new LinkedList<List<Integer>>();
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        Boolean isOrderLeft = true;
        while(queue.size()>0){
            int size = queue.size();
            // 双端队列,存储元素
            Deque<Integer> list = new LinkedList<>();
            for(int i=0;i<size;i++){
                TreeNode node = queue.remove();
                //如果当前遍历方向为从右到左,则将当前节点值添加到双端队列的左侧。
                //如果当前遍历方向为从左到右,则将当前节点值添加到双端队列的右侧。
                if(!isOrderLeft){
                    list.addFirst(node.val);
                }else{
                    list.addLast(node.val);
                }
                
                if(node.left!=null) queue.add(node.left);
                if(node.right!=null) queue.add(node.right);
            }
                // 转换普通列表
               res.add(new ArrayList<>(list));
               // 切换遍历方向
               isOrderLeft = !isOrderLeft;
            
        }
        return res;
    }

算法通关村—原来如此简单_第4张图片
时间复杂度:O(n)n为节点个数
空间复杂度:O(n)使用双端队列存储n个元素

总结:关于一些常用的特性需要多留意

5. N 叉树的层序遍历

N 叉树的层序遍历
给定一个 N 叉树,返回其节点值的层序遍历。(即从左到右,逐层遍历)。
树的序列化输入是用层序遍历,每组子节点都由 null 值分隔(参见示例)
输入:root = [1,null,3,2,4,null,5,6]
输出:[[1],[3,2,4],[5,6]]

遍历子树

依然先写出简单的层序遍历,但是这一题是n叉树,意味着原来的左右子树是无法使用了,但是仔细思考一下,原来的左右子树也是子树,只不过现在采用List存储子树,只需要遍历子树,队列重新遍历添加子树即可。

 public List<List<Integer>> levelOrder(Node root) {
        if(root == null) return new ArrayList<List<Integer>>();
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        Queue<Node> queue = new LinkedList<>();
        queue.add(root);
        while(!queue.isEmpty()){
            int size = queue.size();
            List<Integer> list = new ArrayList<>();
            for(int i=0;i<size;i++){
                Node temp = queue.remove();
                list.add(temp.val);
                // 遍历子树
                if(temp.children!=null){
                    for(Node child:temp.children){
                        queue.add(child);
                    }
                } 
            }
            res.add(list);
        }
        return res;
    }

算法通关村—原来如此简单_第5张图片
时间复杂度:O(n)遍历每个子树
空间复杂度:O(n) 队列使用空间

总结

可以很清晰看出,对于层序遍历,无非就是在简单版本的基础上继续扩充,简单版本一定是需要会的。

你可能感兴趣的:(算法)