239:滑动窗口最大值
队列“维护有可能成为窗口里最大值的元素”,该队列是单调队列,如果队列为空,那么直接把元素加入队列,如果队列非空,则需要考虑待加入的元素是否比队尾大,如果比队尾元素大,那么移除队尾元素,将该元素添加到队列,如果比队尾元素小,直接添加到队尾。首先把第一个滑动窗口的元素入队,之后从滑动窗口外的第一个元素开始遍历,每次把当前滑动窗口覆盖范围的第一个元素出列(前提是能够在队列中找到这个元素),再把遍历元素入队,而对头元素正好是滑动窗口的最大值。所以出队就是将遍历前滑动窗口的第一个元素出队,如果当前指针位置为i,滑动窗口大小为k的话,那么i-k就是所要移除的元素。
对头元素就是当前滑动窗口的局部最大值,因为队列维护的就是滑动窗口的这么一个范围,如果m为当前滑动窗口的最大值,当滑动窗口右移的时候会出现几种情况:1、新加入窗口的元素不比最大值大,那么最大值保持不变;2、新加入窗口的元素比最大值大,那么按照入队的规则,它将会比队中此前的元素都大,它将取代原来的队头,成为队头,成为新的最大值。
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if (nums.length==1) {
return nums;
}
MyQueue2 queue = new MyQueue2();
int len = nums.length;
int[] res = new int[len-k+1];
for (int i = 0; i < k; i++) {
queue.add(nums[i]);
}
int j = 0;
res[j++] = queue.peek();
for (int i = k; i < len; i++) {
queue.pop(nums[i-k]);
queue.add(nums[i]);
res[j++] = queue.peek();
}
return res;
}
}
class MyQueue2{
LinkedList<Integer> queue = new LinkedList<>();
public void add(int val) {
while ((!queue.isEmpty())&&(val>queue.getLast())) {
queue.removeLast();
}
queue.add(val);
}
public void pop(int val) {
if ((!queue.isEmpty())&&(val==queue.peek())) {
queue.poll();
}
}
public int peek() {
return queue.peek();
}
}
347:前K个高频元素
在于对大顶堆和小顶堆的理解。
大顶堆:
class Solution {
public int[] topKFrequent(int[] nums, int k) {
HashMap<Integer, Integer> map = new HashMap<>();
int[] res = new int[k];
for (int i : nums) {
if (map.containsKey(i)) {
map.put(i, map.get(i)+1);
}else {
map.put(i, 0);
}
}
//大顶堆
PriorityQueue<int[]> queue = new PriorityQueue<int[]>(new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o2[1]-o1[1];
}
});
//队列中维持k个元素,大根堆,队头元素最大
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
Integer key = entry.getKey();
Integer val = entry.getValue();
queue.add(new int[] {key,val});
}
//取前k个元素
for (int i = 0; i < k ; i++) {
res[i] = queue.poll()[0];
}
return res;
}
}
小顶堆:
class Solution {
public int[] topKFrequent(int[] nums, int k) {
HashMap<Integer, Integer> map = new HashMap<>();
int[] res = new int[k];
for (int i : nums) {
if (map.containsKey(i)) {
map.put(i, map.get(i)+1);
}else {
map.put(i, 0);
}
}
PriorityQueue<int[]> queue = new PriorityQueue<int[]>(new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[1]-o2[1];
}
});
//队列中维持k个元素,小根堆,队头元素最小
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
Integer key = entry.getKey();
Integer val = entry.getValue();
//当超过k个元素时,必须考虑新加入的元素,如果其val值(出现频率)大于队头(出现频率最低的)
//则将队头元素移除,将新元素加入
if (queue.size()<k) {
queue.add(new int[] {key,val});
}else {
if (val>queue.peek()[1]) {
queue.poll();
queue.add(new int[] {key,val});
}
}
}
for (int i = k-1; i >= 0 ; i--) {
res[i] = queue.poll()[0];
}
return res;
}
}