【优选算法】专题十三——队列+宽搜(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;
    }
}

总结

  • 复习解题思路和代码实现及解析
相关推荐
ccLianLian2 小时前
算法·字符串哈希
算法·哈希算法
SongYuLong的博客2 小时前
Linux IPC进程通信几种方法
linux·运维·算法
像污秽一样2 小时前
算法设计与分析-习题6.1
数据结构·算法
北京地铁1号线2 小时前
8.2 对比学习的损失函数
算法·机器学习·损失函数·对比学习
样例过了就是过了3 小时前
LeetCode热题100 分割回文串
数据结构·c++·算法·leetcode·深度优先·dfs
带娃的IT创业者3 小时前
WeClaw 心跳与重连实战:指数退避算法如何让 WebSocket 在弱网环境下的连接成功率提升 67%?
python·websocket·网络协议·算法·fastapi·实时通信
Morwit3 小时前
【力扣hot100】 85. 最大矩形
c++·算法·leetcode·职场和发展
艾醒4 小时前
MiniMax M2.5:从黑马到全球顶流的"前世今生"与趣闻
算法
m0_528174454 小时前
C++中的代理模式变体
开发语言·c++·算法