队列的应用

41:滑动窗口的平均值

:::info 请实现如下类型MovingAverage,计算滑动窗口中所有数字的平均值,该类型构造函数的参数确定滑动窗口的大小,每次调用成员函数next时都会在滑动窗口中添加一个整数,并返回滑动窗口中所有数字的平均值。 :::

  1. public class MovingAverage {
  2. private Queue<Integer> queue = new LinkedList<>();
  3. int sum = 0;
  4. int capcity = 0;
  5. public MovingAverage(int capacity) {
  6. this.capcity = capacity;
  7. }
  8. public double next(int val) {
  9. if (queue.size() == capcity) {
  10. int deletedNum = queue.poll();
  11. sum -= deletedNum;
  12. }
  13. sum += val;
  14. queue.add(val);
  15. return (double) sum / queue.size();
  16. }
  17. public static void main(String[] args) {
  18. MovingAverage movingAverage = new MovingAverage(3);
  19. System.out.println(movingAverage.next(1));
  20. System.out.println(movingAverage.next(2));
  21. System.out.println(movingAverage.next(3));
  22. System.out.println(movingAverage.next(4));
  23. }
  24. }

42:最近请求次数

:::info 题目:请实现如下类型RecentCounter,它是统计过去3000ms内的请求次数的计数器。该类型的构造函数RecentCounter初始化计数器,请求数初始化为0;函数ping(int t)在时间t添加一个新请求(t表示以毫秒为单位的时间),并返回过去3000ms内(时间范围为[t-3000,t])发生的所有请求数。假设每次调用函数ping的参数t都比之前调用的参数值大。 :::

  1. public cleass RecentCounter {
  2. private int windowSize = 3000;
  3. private Queue<Integer> times = new LinkedList<>();
  4. public RecentCounter42() {
  5. }
  6. public int ping(int time) {
  7. times.offer(time);
  8. while(times.peek() + windowSize < time) {
  9. times.poll();
  10. }
  11. return times.size();
  12. }
  13. }

二叉树的广度优先搜索

BFS

:::info 二叉树的广度优先遍历 :::

  1. public class TreeNode {
  2. public int val;
  3. public TreeNode left;
  4. public TreeNode right;
  5. public TreeNode(int val) {
  6. this.val = val;
  7. }
  8. }
  1. public class BFS {
  2. public void bfd(TreeNode root) {
  3. List<Integer> result = new ArrayList<>();
  4. Queue<TreeNode> queue = new LinkedList<>();
  5. if(root == null) {
  6. return result;
  7. }
  8. queue.add(root);
  9. while(queue.isNotEmpty()) {
  10. TreeNode node = queue.poll();
  11. result.add(node.val);
  12. if(node.left != null) {
  13. queue.offer(left);
  14. }
  15. if(node.right != null) {
  16. queue.offer(right);
  17. }
  18. }
  19. return result;
  20. }
  21. public static void main(String[] args) {
  22. TreeNode node5 = new TreeNode(5);
  23. TreeNode node7 = new TreeNode(7);
  24. TreeNode node6 = new TreeNode(6, node5, node7);
  25. TreeNode node9 = new TreeNode(9);
  26. TreeNode node11 = new TreeNode(11);
  27. TreeNode node10 = new TreeNode(10, node9, node11);
  28. TreeNode node8 = new TreeNode(8, node6, node10);
  29. System.out.println(bfs(node8));
  30. }
  31. }

:::info 笔记:
队列的特点是先进先出,所以每一层的元素先进队列之后,一定会先被遍历到,才会开始遍历后进的子节点。 :::

43:在完全二叉树中添加节点

:::info 题目:在完全二叉树中,除最后一层之外其他层的节点都是满的(第n层有2n-1个节点)。最后一层的节点可能不满,该层所有的节点尽可能向左边靠拢。例如,图7.3中的4棵二叉树均为完全二叉树。实现数据结构CBTInserter有如下3种方法。
● 构造函数CBTInserter(TreeNode root),用一棵完全二叉树的根节点初始化该数据结构。
● 函数insert(int v)在完全二叉树中添加一个值为v的节点,并返回被插入节点的父节点。例如,在如图7.3(a)所示的完全二叉树中添加一个值为7的节点之后,二叉树如图7.3(b)所示,并返回节点3。在如图7.3(b)所示的完全二叉树中添加一个值为8的节点之后,二叉树如图7.3(c)所示,并返回节点4。在如图7.3(c)所示的完全二叉树中添加节点9会得到如图7.3(d)所示的二叉树并返回节点4。
● 函数get_root()返回完全二叉树的根节点。 :::

  1. public class CBTInserter {
  2. // 保存所有左右子节点不完全的节点
  3. private Queue<TreeNode> queue = new LinkedList<>();
  4. private TreeNode root;
  5. public CBTInserter(TreeNode treeNode) {
  6. this.root = treeNode;
  7. if (treeNode != null) {
  8. queue.offer(treeNode);
  9. // 遍历直到找到最后一层不满的节点
  10. while (queue.peek().left != null && queue.peek().right != null) {
  11. TreeNode node = queue.poll();
  12. queue.offer(node.left);
  13. queue.offer(node.right);
  14. }
  15. }
  16. }
  17. public int insert(TreeNode node) {
  18. queue.offer(node);
  19. TreeNode parent = queue.peek();
  20. if (parent.left == null) {
  21. parent.left = node;
  22. } else {
  23. parent.right = node;
  24. // 右节点补齐了,要把这个节点从queue里面删掉了
  25. queue.poll();
  26. queue.offer(parent.left);
  27. queue.offer(parent.right);
  28. }
  29. return parent.val;
  30. }
  31. public TreeNode getRoot() {
  32. return root;
  33. }
  34. public static void main(String[] args) {
  35. TreeNode node4 = new TreeNode(4);
  36. TreeNode node5 = new TreeNode(5);
  37. TreeNode node2 = new TreeNode(2, node4, node5);
  38. TreeNode node6 = new TreeNode(6);
  39. TreeNode node7 = new TreeNode(7);
  40. TreeNode node3 = new TreeNode(3, node6, node7);
  41. TreeNode node1 = new TreeNode(1, node2, node3);
  42. CBTInserter inserter = new CBTInserter(node1);
  43. System.out.println(inserter.insert(new TreeNode(8)));
  44. System.out.println(inserter.insert(new TreeNode(9)));
  45. System.out.println(inserter.insert(new TreeNode(10)));
  46. }
  47. }

44:二叉树中每层的最大值

:::info 题目:输入一棵二叉树,请找出二叉树中每层的最大值。例如,输入图7.4中的二叉树,返回各层节点的最大值[3,4,9]。

image.png :::

  1. public class LargestValues{
  2. public static List<Integer> findLargestValues(TreeNode root) {
  3. if (root == null) {
  4. return new ArrayList<>();
  5. }
  6. List<Integer> result = new ArrayList<>();
  7. Queue<TreeNode> queue = new LinkedList<>();
  8. queue.offer(root);
  9. int current = 1;
  10. int next = 0;
  11. int maxValue = Integer.MIN_VALUE;
  12. while (!queue.isEmpty()) {
  13. TreeNode node = queue.poll();
  14. maxValue = Math.max(maxValue, node.val);
  15. current--;
  16. if (node.left != null) {
  17. queue.offer(node.left);
  18. next++;
  19. }
  20. if (node.right != null) {
  21. queue.offer(node.right);
  22. next++;
  23. }
  24. // 这个if条件需要放在最后,否则next的计数会不准确
  25. if (current == 0) {
  26. result.add(maxValue);
  27. // 重置计数器
  28. maxValue = Integer.MIN_VALUE;
  29. current = next;
  30. next = 0;
  31. }
  32. }
  33. return result;
  34. }
  35. public static List<Integer> findLargestValuesWith2Queue(TreeNode root) {
  36. if (root == null) {
  37. return new ArrayList<>();
  38. }
  39. List<Integer> result = new ArrayList<>();
  40. // 用来存当前层
  41. Queue<TreeNode> queue1 = new LinkedList<>();
  42. queue1.offer(root);
  43. // 用来存下一层
  44. Queue<TreeNode> queue2 = new LinkedList<>();
  45. Integer maxValue = Integer.MIN_VALUE;
  46. while (!queue1.isEmpty()) {
  47. TreeNode node = queue1.poll();
  48. maxValue = Math.max(maxValue, node.val);
  49. if (node.left != null) {
  50. queue2.offer(node.left);
  51. }
  52. if (node.right != null) {
  53. queue2.offer(node.right);
  54. }
  55. // 这个if条件需要放在最后
  56. if (queue1.isEmpty()) {
  57. result.add(maxValue);
  58. queue1 = queue2;
  59. queue2 = new LinkedList<>();
  60. }
  61. }
  62. return result;
  63. }
  64. public static void main(String[] args) {
  65. TreeNode root = TreeNode.buildCBT();
  66. System.out.println(findLargestValues(root));
  67. System.out.println(findLargestValuesWith2Queue(root));
  68. }
  69. }

45:二叉树最低层最左边的值

:::info 题目:如何在一棵二叉树中找出它最低层最左边节点的值?假设二叉树中最少有一个节点。例如,在如图7.5所示的二叉树中最低层最左边一个节点的值是5。
image.png :::

  1. public class BottomLeft {
  2. public static TreeNode findBottomLeftNode(TreeNode root) {
  3. if (root == null) {
  4. return null;
  5. }
  6. List<Integer> result = new ArrayList<>();
  7. // 用来存当前层
  8. Queue<TreeNode> queue1 = new LinkedList<>();
  9. queue1.offer(root);
  10. // 用来存下一层
  11. Queue<TreeNode> queue2 = new LinkedList<>();
  12. TreeNode bottomLeftNode = root;
  13. while (!queue1.isEmpty()) {
  14. TreeNode node = queue1.poll();
  15. if (node.left != null) {
  16. queue2.offer(node.left);
  17. }
  18. if (node.right != null) {
  19. queue2.offer(node.right);
  20. }
  21. // 这个if条件需要放在最后
  22. if (queue1.isEmpty()) {
  23. if (!queue2.isEmpty()) {
  24. bottomLeftNode = queue2.peek();
  25. }
  26. queue1 = queue2;
  27. queue2 = new LinkedList<>();
  28. }
  29. }
  30. return bottomLeftNode;
  31. }
  32. public static void main(String[] args) {
  33. TreeNode root = TreeNode.buildCBT();
  34. System.out.println(findBottomLeftNode(root).val);
  35. }
  36. }

46:二叉树的右侧视图

:::info 题目:给定一棵二叉树,如果站在该二叉树的右侧,那么从上到下看到的节点构成二叉树的右侧视图。例如,图7.6中二叉树的右侧视图包含节点8、节点10和节点7。请写一个函数返回二叉树的右侧视图节点的值。
image.png :::

  1. public class RightView {
  2. public static List<Integer> rightView(TreeNode root) {
  3. if (root == null) {
  4. return new ArrayList<>();
  5. }
  6. List<Integer> result = new ArrayList<>();
  7. // 用来存当前层
  8. Queue<TreeNode> queue1 = new LinkedList<>();
  9. queue1.offer(root);
  10. // 用来存下一层
  11. Queue<TreeNode> queue2 = new LinkedList<>();
  12. while (!queue1.isEmpty()) {
  13. TreeNode node = queue1.poll();
  14. if (node.left != null) {
  15. queue2.offer(node.left);
  16. }
  17. if (node.right != null) {
  18. queue2.offer(node.right);
  19. }
  20. // 这个if条件需要放在最后
  21. if (queue1.isEmpty()) {
  22. result.add(node.val);
  23. queue1 = queue2;
  24. queue2 = new LinkedList<>();
  25. }
  26. }
  27. return result;
  28. }
  29. public static void main(String[] args) {
  30. TreeNode root = TreeNode.buildCBT();
  31. System.out.println(rightView(root));
  32. }