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

总结

  • 复习解题思路和代码实现及解析
相关推荐
dialect_10 小时前
CODEFORCES ROUND 1127 DIV2
开发语言·c++·算法
Nuanyt11 小时前
LeetCode Hot 100 链表专题(四)· 3 题(Java)
java·算法·leetcode·链表·双指针
灯澜忆梦11 小时前
LeetCode 1861. 旋转盒子|Go 双指针解法
算法
软件派12 小时前
生产动态数据智能风控:阈值判别、趋势预测、异常识别算法工程落地实战
前端·数据库·算法
ZhengEnCi19 小时前
模型训练完整流程:从数据准备到模型上线的 10 个关键步骤(全文可跑)
后端·算法
吞下星星的少年·-·1 天前
Div.3 CF 1131A题(排序,模拟)
算法·模拟·排序
aichitang20241 天前
代数拓扑学与现代前沿视角
考研·算法·数学建模·ai·拓扑学·高考
二本咕咕-机械转码1 天前
FreeRTOS深入解析(一)_链表与并发保护——哨兵循环链表、排序键游标、临界区与关调度
单片机·算法·链表
-银雾鸢尾-1 天前
两数之和-C++实现
c++·算法