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

总结

  • 复习解题思路和代码实现及解析
相关推荐
脱氧核糖核酸__12 分钟前
LeetCode热题100——234.回文链表(两种解法)
c++·算法·leetcode·链表
IronMurphy12 分钟前
【算法四十二】118. 杨辉三角 198. 打家劫舍
算法
电科一班林耿超17 分钟前
第 16 课:动态规划专题(二)—— 子序列与子数组问题:面试最高频的 DP 题型
数据结构·算法·动态规划
生信研究猿42 分钟前
leetcode 416. 分割等和子集
算法·leetcode·职场和发展
狗哥哥1 小时前
面包屑自动推导的算法设计:从“最短路径匹配”到工程可落地
算法·架构
隔壁大炮2 小时前
Day07-RNN介绍
人工智能·pytorch·rnn·深度学习·神经网络·算法·numpy
WL_Aurora2 小时前
Python 算法基础篇之什么是算法
python·算法
墨染天姬2 小时前
[AI]DeepSeek-R1的GRPO算法
人工智能·算法·php
D_C_tyu2 小时前
JavaScript | 数独游戏核心算法实现
javascript·算法·游戏