1. 优先级队列
1.1. LC 2182 构造限制重复的字符串
- 大根堆pq存储现有的字符种类
- 哈希表cnt存储每种字符的数量
- 每次弹出一种字符,直至没有字符可用
- 如果限制次数没被用完,使用,更新哈希表,剩余次数-1,把当前字符放回去
- 如果限制次数用完
- 如果此时没有另外的字符,结束
- 如果有另外的字符,弹出,使用,更新哈希表,剩余次数复位,把这两种字符全塞回去。
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<Character> 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<long[]> 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<q.peekLast()[0]){q.pollLast();}q.add(new long[]{sum,i});}return ans==Long.MAX_VALUE?-1: (int) ans;}
}
之所以不用单调栈而是一个单调的双端队列,是因为栈没办法查询或操作栈底元素。我们想要最短区间,是肯定要查看之前最早的检查点的,也就是踢人的时候不能从队尾踢,队尾的前缀和要留给更后面的位置查询。栈满足不了这个需求。