QUEUE

1. 优先级队列

1.1. LC 2182 构造限制重复的字符串

  1. 大根堆pq存储现有的字符种类
  2. 哈希表cnt存储每种字符的数量
  3. 每次弹出一种字符,直至没有字符可用
    1. 如果限制次数没被用完,使用,更新哈希表,剩余次数-1,把当前字符放回去
    2. 如果限制次数用完
      1. 如果此时没有另外的字符,结束
      2. 如果有另外的字符,弹出,使用,更新哈希表,剩余次数复位,把这两种字符全塞回去。
import java.util.Comparator;
import java.util.PriorityQueue;

class Solution {
    public String repeatLimitedString(String s, int repeatLimit) {
        char[] ch = s.toCharArray();
        int[] cnt = new int[26];
        PriorityQueue pq = new PriorityQueue<>((o1, o2) -> -Character.compare(o1,o2));
        for (char c : ch) {
            int dis = c - 'a';
            if(cnt[dis]==0){
                pq.offer(c);
            }
            cnt[dis]++;
        }

        StringBuilder sb = new StringBuilder();
        int lim = repeatLimit;
        while(!pq.isEmpty()){
            Character f = pq.poll();
            if(lim>0){
                sb.append(f);
                lim--;
                cnt[f-'a']--;
                if(cnt[f-'a']!=0){
                    pq.offer(f);
                }else{
                    lim = repeatLimit;
                }
            }else{
                if(pq.isEmpty()){
                    return sb.toString();
                }else{
                    Character se = pq.poll();
                    sb.append(se);
                    cnt[se-'a']--;
                    lim = repeatLimit;
                    if(cnt[se-'a']!=0){
                        pq.offer(se);
                    }
                    pq.offer(f);
                }
            }
        }
        return sb.toString();
    }
}

2. 单调队列

2.1. LC 862 和至少为K的最短子数组

子数组元素和显然要算前缀和。

维护一个单调增的单调队列。也就是如果队尾元素大于当前前缀和的话,就应该把队尾踢掉。这是因为:当后续前缀和查询队列中维护的前缀和时,如果当前前缀和与其之差≥k的话,那么与一个更小的前缀和之差也一定≥k。由于我们是正序的,所以踢走队尾的前缀和的索引一定更靠后。也就更接近日后查询时的索引。因此长度就更短。

对于查询,查询检查点直到查无可查为止。取最小值作为答案。

import java.util.ArrayDeque;

class Solution {
    public int shortestSubarray(int[] nums, int k) {
        ArrayDeque q = new ArrayDeque<>();
        long sum = 0;
        long ans = Long.MAX_VALUE;
        q.push(new long[]{0,-1});
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
            while(!q.isEmpty() && sum-q.peekFirst()[0]>=k){
                ans = Math.min(ans,i-q.pollFirst()[1]);
            }
            while(!q.isEmpty() && sum

之所以不用单调栈而是一个单调的双端队列,是因为栈没办法查询或操作栈底元素。我们想要最短区间,是肯定要查看之前最早的检查点的,也就是踢人的时候不能从队尾踢,队尾的前缀和要留给更后面的位置查询。栈满足不了这个需求。

你可能感兴趣的:(数据结构与算法,算法,leetcode,数据结构,java)