关于队列的一些题目
关于队列的一些题目
1、滑动窗口平均值
- 描述:给定一个整数数据流和一个窗口大小,根据该滑动窗口的大小,计算滑动窗口里所有数字的平均值。
- 解法:设置一个 sum,计算总和,在数值个数达到给定最大容量之前,一直添加,用 sum/que.size() 计算平均值。达到最大容量后,弹出最开始的那个,加入新的值,sum减去最开始的值,加上最后加入的值。sum/que.size() 计算平均值
- 注意:sum 的类型用double,不然计算出来的值不会带小数
class MovingAverage {
Queue<Integer> que;
double sum = 0;
int size = 0;
/** Initialize your data structure here. */
public MovingAverage(int size) {
que = new LinkedList<Integer>();
this.size = size;
}
public double next(int val) {
if(que.size() == size){
sum -= que.poll();
}
que.add(val);
sum += val;
return sum/que.size();
}
}
2、最近请求次数
-
描述:
写一个 RecentCounter 类来计算特定时间范围内最近的请求。请实现 RecentCounter 类:RecentCounter() 初始化计数器,请求数为 0 。 int ping(int t) 在时间 t 添加一个新请求,其中 t 表示以毫秒为单位的某个时间,并返回过去 3000 毫秒内发生的所有请求数(包括新请求)。确切地说,返回在 [t-3000, t] 内发生的请求数。 保证 每次对 ping 的调用都使用比之前更大的 t 值。
-
解法:与上面近似,加入新值时要判断 前面的值和这个值之间的差值是否大于 3000,大于就要while 弹出
class RecentCounter {
Queue<Integer> que;
public RecentCounter() {
que = new LinkedList<>();
}
public int ping(int t) {
while(que.size()!=0 && (t-que.peek())>3000){
que.poll();
}
que.add(t);
return que.size();
}
}
3、完全二叉树插入值
-
描述:
完全二叉树是每一层(除最后一层外)都是完全填充(即,节点数达到最大,第 n 层有 2n-1 个节点)的,并且所有的节点都尽可能地集中在左侧。 设计一个用完全二叉树初始化的数据结构 CBTInserter,它支持以下几种操作: CBTInserter(TreeNode root) 使用根节点为 root 的给定树初始化该数据结构; CBTInserter.insert(int v) 向树中插入一个新节点,节点类型为 TreeNode,值为 v 。使树保持完全二叉树的状态,并返回插入的新节点的父节点的值; CBTInserter.get_root() 将返回树的根节点。
-
解法:使用两个队列,普通队列用来遍历给定链表的节点,如果有空子节点的,就加入双端队列,先进去的编号最小,最接近 root 节点。双端队列用来给这些没孩子的加孩子。先要把这个新的节点加入到双端队列的尾部(他也莫得孩子),加孩子的顺序是:从最先进来双端队列的节点开始,先看左节点,如果左节点为空,就给这个节点的左孩子赋值,再看右节点,如果右节点为空,就给这个节点的右孩子赋值,赋值之后这个节点就左右孩子都有了,直接从双端队列里面删除。
class CBTInserter {
TreeNode root;
Deque<TreeNode> deque;
public CBTInserter(TreeNode root) {
this.root = root;
deque = new LinkedList<>();
Queue<TreeNode> que = new LinkedList<>();
que.offer(root);
while(!que.isEmpty()){
TreeNode node = que.poll();
if(node.left==null || node.right==null) deque.offerLast(node);
if(node.left != null) que.offer(node.left);
if(node.right != null) que.offer(node.right);
}
}
public int insert(int val) {
TreeNode node = deque.peekFirst();
deque.offerLast(new TreeNode(val));
if(node.left == null) node.left=deque.peekLast();
else{
node.right=deque.peekLast();
deque.pollFirst();
}
return node.val;
}
public TreeNode get_root() {
return root;
}
}
4、二叉树每层的最大值
-
描述:
给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。
-
解法:
使用队列进行广度优先遍历,每一层都加入队列,对着一层的值寻找最大值,加入结果数组
-
源码
class Solution { public List<Integer> largestValues(TreeNode root) { if(root == null) return new ArrayList<Integer>(); Queue<TreeNode> que = new LinkedList<>(); List<Integer> res = new ArrayList<>(); que.add(root); while(!que.isEmpty()){ int queSize = que.size(); int max = Integer.MIN_VALUE; while(queSize > 0){ TreeNode node = que.poll(); max = node.val>max ? node.val : max; if(node.left != null) que.add(node.left); if(node.right != null) que.add(node.right); queSize--; } res.add(max); } return res; } }
5、二叉树最底层最左边的值
-
描述:
给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。
-
解法:
对左右两边都进行深度优先遍历,维护一个深度值与遍历的左右子树的深度值进行比较,保留更大的值
-
源码:
class Solution { public int findBottomLeftValue(TreeNode root) { dfs(root,1); return max.val; } int height = 0; TreeNode max = null; public void dfs(TreeNode root,int h){ if(root == null) return; if(h > height){ height = h; max = root; } dfs(root.left,h+1); dfs(root.right,h+1); } }
6、二叉树的右侧视图
-
描述:
给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
-
解法:
1、仍然可以使用 4 中的广度优先遍历,先判断左边,在判断右边。只不过将每一层的最后一个数据放到结果数组里面。刚好就是最右边的数据了。 2、深度优先:对于每一个深度总是先访问右子树,那么每层访问到的第一个节点就是我们要的结果了
-
源码:
广度优先: class Solution { public List<Integer> rightSideView(TreeNode root) { List<Integer> res = new ArrayList<Integer>(); if(root == null) return res; Queue<TreeNode> que = new LinkedList<>(); que.add(root); while(!que.isEmpty()){ int queSize = que.size(); while(queSize>0){ TreeNode node = que.poll(); queSize --; if(queSize == 0) { res.add(node.val); } if(node.left != null) que.add(node.left); if(node.right != null) que.add(node.right); } } return res; } } 深度优先: class Solution { public List<Integer> rightSideView(TreeNode root) { Map<Integer, Integer> rightmostValueAtDepth = new HashMap<Integer, Integer>(); int max_depth = -1; Deque<TreeNode> nodeStack = new ArrayDeque<TreeNode>(); Deque<Integer> depthStack = new ArrayDeque<Integer>(); nodeStack.push(root); depthStack.push(0); while (!nodeStack.isEmpty()) { TreeNode node = nodeStack.pop(); int depth = depthStack.pop(); if (node != null) { // 维护二叉树的最大深度 max_depth = Math.max(max_depth, depth); // 如果不存在对应深度的节点我们才插入 if (!rightmostValueAtDepth.containsKey(depth)) { rightmostValueAtDepth.put(depth, node.val); } nodeStack.push(node.left); nodeStack.push(node.right); depthStack.push(depth + 1); depthStack.push(depth + 1); } } List<Integer> rightView = new ArrayList<Integer>(); for (int depth = 0; depth <= max_depth; depth++) { rightView.add(rightmostValueAtDepth.get(depth)); } return rightView; } }