【优选算法】专题十三——队列+宽搜(BFS)

文章目录

一、二叉树的锯齿形层序遍历

Leetcode链接

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

解题思路

  • 正常的层序遍历,使用队列来帮助我们记录每层的节点,只是本题要求我们偶数层的节点值要反着存。那那么在正常记录偶数层的节点值之后使用 把值反转一下就行了

代码实现及解析

java 复制代码
class TreeNode {
      int val;
      TreeNode left;
      TreeNode right;
      TreeNode() {}
      TreeNode(int val) { this.val = val; }
      TreeNode(int val, TreeNode left, TreeNode right) {
          this.val = val;
          this.left = left;
          this.right = right;
      }
  }
  
class Solution {
    public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        Queue<TreeNode> queue=new LinkedList<>();
        List<List<Integer>> ret=new ArrayList<>();
        if(root==null) return ret;

        queue.offer(root);
        boolean flag=false;//代表奇数层
        while(!queue.isEmpty()){
            int size=queue.size();//记录本层的节点数
            List<Integer> list=new ArrayList<>();
            for(int i=0;i<size;i++){//for循环结束后只提取一层的节点
                TreeNode node=queue.poll();
                list.add(node.val);
                //将该节点的孩子节点入队列
                if(node.left!=null) queue.offer(node.left);
                if(node.right!=null) queue.offer(node.right);
            }
            if(flag) Collections.reverse(list);//偶数层的节点值需要反转
            ret.add(list);
            flag=!flag;//变换奇偶层记录
        }
        return ret;
    }
}

总结

  • 复习解题思路

二、二叉树最大宽度

Leetcode链接

给你一棵二叉树的根节点 root ,返回树的 最大宽度 。

树的 最大宽度 是所有层中最大的 宽度 。

每一层的 宽度 被定义为该层最左和最右的非空节点(即,两个端点)之间的长度。将这个二叉树视作与满二叉树结构相同,两端点间会出现一些延伸到这一层的 null 节点,这些 null 节点也计入长度。

题目数据保证答案将会在 32 位 带符号整数范围内。

提示:

树中节点的数目范围是 1, 3000

-100 <= Node.val <= 100

解题思路

方法一(不可取):

  • 我们可能会想到像正常层序遍历那样把空节点也入队列,只要处理好空节点的操作问题理论上可以达到要求,但是当根节点两边的子树都呈现单分支树的状态时(也就是每边都有1500个节点),最后一层的节点数可以达到恐怖的21500-1个,这个数目连double都存不下,所以该方法不可取。

方法二(采用节点编号):

  • 我们仍然是使用层序遍历,将存在的节点入队列,但是我们要像堆结构那样对节点进行编号,并与对应节点一起储存,这样最后就可以使用两端节点的编号直接计算出该层的宽度。
  • 有两种编号方式,一种是根节点编号为0,一种是根节点编号为1,这两种方式的孩子节点的计算公式是不一样的,但是忘了可以直接推导。
  1. 根节点编号为1:leftChild=parent*2 ,rightChild=parent*2+1;
  2. 根节点编号为0:leftChild=parent*2 +1,rightChild=parent*2+2;
  • 我们使用ArrayList来模拟队列,更容易精准地定位到第一个和最后一个节点(两端节点来计算宽度),在代码中要着重熟悉一下如何使用ArrayList来模拟队列更新数据的方式(也就是将本层节点弹出并将它们的孩子节点入队列),我们使用的是每层创建一个新的ArrayList来储存下一层的节点,然后更新ArrayList。

小细节:方法一中列举的情况,即使为节点下标编号,下标也会溢出。但是当两下标相减后,即使溢出,结果也是正确的。

代码实现及解析

java 复制代码
class Solution {
    public int widthOfBinaryTree(TreeNode root) {
        List<Pair<TreeNode,Integer>> queue=new ArrayList<>();//用ArrayList模拟队列
        Pair<TreeNode,Integer> pair=new Pair<>(root,1);//将节点与它的编号绑定(也可以使用Map.Entry)
        queue.add(pair);//将root入队列
        int ret=0;//记录最大宽度
        while(!queue.isEmpty()){
            int k=queue.size();
            //1.计算宽度
            int wide=queue.get(k-1).getValue()-queue.get(0).getValue()+1;
            ret=Math.max(ret,wide);
            //2.放入下一层节点
            List<Pair<TreeNode,Integer>> tmpQue=new ArrayList<>();//每层节点放入一个新的ArrayList中(ArrayList方法有限,这是最合适的一种模拟队列更新数据的方式)
            for(Pair<TreeNode,Integer> x:queue){
                TreeNode node=x.getKey();
                if(node.left!=null){
                    Pair<TreeNode,Integer> tmp=new Pair<>(node.left,x.getValue()*2);
                    tmpQue.add(tmp);
                }
                if(node.right!=null){
                    Pair<TreeNode,Integer> tmp=new Pair<>(node.right,x.getValue()*2+1);
                    tmpQue.add(tmp);
                }
            }
            queue=tmpQue;//更新队列
        }
        return ret;
    }
}

注:Java标准库自身没有提供 Pair 通用公共类, 通常需要使用第三方库或特定JDK模块中的类。Leetcode可以直接使用,但是IDE中用不了,可以改使用Map.Entry

  • 或者我们也可以直接自己现场实现一个自定义包装类(代码也不多,很实用):
java 复制代码
class Wrapper {
    TreeNode node;
    int index;

    public Wrapper() {
    }

    public Wrapper(TreeNode node, int index) {
        this.node= node;
        this.index = index;
    }

		public TreeNode  getKey() {
        return node;
    }
    
    public int getValue() {
        return index;
    }
}

总结

  • 复习解题思路和代码实现及解析
相关推荐
倒头就睡的小比特1 天前
算法竞赛C++常用的STL
c++·算法
小羊没烦恼!1 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
猎头南楼1 天前
知识社区推荐系统实践:新用户冷启动与长短期兴趣建模的挑战 资深推荐算法工程师
人工智能·深度学习·算法·机器学习
旖旎夜光1 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
wzdark1 天前
大规模并行计算中的负载均衡算法研究4
算法
Because_of_Her11 天前
并查集-听课笔记
笔记·算法·并查集
码流子1 天前
高速公路安全监测实践:碰撞监测预警+物联网底座,从感知到处置的闭环
大数据·人工智能·物联网·算法·架构
another heaven1 天前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法
wzdark1 天前
从算法设计模式看编程思维的抽象能力4
算法
2601_962218611 天前
万象生鲜系统称重自动多退少补算法解决生鲜非标品痛点
大数据·数据库·人工智能·python·算法