新人写文,出现错误还请各位大佬轻批
题目如下
方法一:简单易懂双循环,就不发了,自己写的还超时了
方法二:官方题解一,优先队列,在该方法中用到了堆(Java PriorityQueue - Java教程 - 菜鸟教程 (cainiaojc.com)),堆是完全二叉树可自动排序(时间复杂度NlogN)。思路很简单,先将前k个放入大根堆(既最大值为跟节点)里,堆顶就是最大值,堆会自动排序,随着模块移动,不断插入新元素,如果出现插入大于最大值则会自动插入到根节点,所以每次只用获取根节点即可,如果最大值不在模块里就把他扔出去,代码注释如下:
public static int[] maxSlidingWindow(int[] nums, int k) {
int n= nums.length;
PriorityQueue<int[]> pq=new PriorityQueue<int[]>(new Comparator<int[]>() {
@Override //默认由小到大,本题需要由大到小
public int compare(int[] o1, int[] o2) {
return o1[0]!=o2[0]?o2[0]-o1[0]:o2[1]-o1[1];
}
});
//将前k个数放入堆
for (int i = 0; i < k; ++i) {
pq.offer(new int[]{nums[i],i});
}
int[] ans=new int[n-k+1];
ans[0]=pq.peek()[0];//获取前k个数的最大值
for (int i = k; i < n; ++i) {
pq.offer(new int[]{nums[i],i});
while (pq.peek()[1]<=i-k){ //如果最大值已经不在滑动模块里,则将其移出堆
pq.poll();
}
ans[i-k+1]=pq.peek()[0];//将堆里的最大值放入数组
}
return ans;
}
方法三:单调队列
用到双向队列(Java Deque 接口 - Java教程 - 菜鸟教程 (cainiaojc.com)),队列中存的是从左往右单调递增的数的下标,如果不符合则将队列中的数一个个从后移出,直到符合,同时还要判断队列中的最大值既头元素的值是不是移出了移动模块,如果是则将头元素从头移出
int n= nums.length;
Deque<Integer> deque=new LinkedList<>();
for (int i = 0; i < k; ++i) {
//队列里面会留下一个从左往右单调递增的数的下标,队首是最大值,队尾是最小值
while (!deque.isEmpty() && nums[i]>=nums[deque.peekLast()]){
deque.pollLast();
}
deque.offerLast(i);
}
int[] ans=new int[n-k+1];
ans[0]=nums[deque.peekFirst()];//获取前k个数的最大值
for (int i = k; i < n; ++i) {
//模块开始移动,开始判断新进来的值是否符合队列
while (!deque.isEmpty() && nums[i]>=nums[deque.peekLast()]){
deque.pollLast();
}
deque.offerLast(i);
//判断头元素是否还在移动模块中
while (deque.peekFirst()<=i-k){
deque.pollFirst();
}
ans[i-k+1]=nums[deque.peekFirst()];
}
return ans;