给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值。
这道题和239. 滑动窗口最大值
一样。
解法一
暴力破解
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if (nums.length == 0) return nums;
int[] arr = new int[nums.length - k + 1];
int index = 0;
for (int i = 0; i <= nums.length - k; i++) {
int max = Integer.MIN_VALUE;
// 找出区间的最大值
for (int j = i; j < i + k; j++) {
if (nums[j] > max) max = nums[j];
}
arr[index++] = max;
}
return arr;
}
}
只想到了暴力破解,解法二是对解法一的优化,去掉一些不必要的循环。
解法二
解法一的优化
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if (nums.length == 0) return nums;
int[] arr = new int[nums.length - k + 1];
int index = 0;
int max = Integer.MIN_VALUE, maxIndex = -1;
for (int i = 0; i <= nums.length - k; i++) {
//判断上一个max是否还在区间内,并且是否大于新的值
if (maxIndex >= i && maxIndex < i+k && max > nums[i+k - 1]) {
arr[index++] = max;
continue;
}
//上面判断不成功,重新找出区间的最大值
max = Integer.MIN_VALUE;
maxIndex = -1;
for (int j = i; j < i + k; j++) {
if (nums[j] > max) {
max = nums[j];
maxIndex = j;
}
}
arr[index++] = max;
}
return arr;
}
}
解法三
单调队列
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
//单调队列
//下面是要注意的点:
//队列按从大到小放入
//如果首位值(即最大值)不在窗口区间,删除首位
//如果新增的值小于队列尾部值,加到队列尾部
//如果新增值大于队列尾部值,删除队列中比新增值小的值,如果在把新增值加入到队列中
//如果新增值大于队列中所有值,删除所有,然后把新增值放到队列首位,保证队列一直是从大到小
if (nums.length == 0) return nums;
Deque<Integer> deque = new LinkedList<>();
int[] arr = new int[nums.length - k + 1];
int index = 0; //arr数组的下标
//未形成窗口区间
for (int i = 0; i < k; i++) {
//队列不为空时,当前值与队列尾部值比较,如果大于,删除队列尾部值
//一直循环删除到队列中的值都大于当前值,或者删到队列为空
while (!deque.isEmpty() && nums[i] > deque.peekLast()) deque.removeLast();
//执行完上面的循环后,队列中要么为空,要么值都比当前值大,然后就把当前值添加到队列中
deque.addLast(nums[i]);
}
//窗口区间刚形成后,把队列首位值添加到队列中
//因为窗口形成后,就需要把队列首位添加到数组中,而下面的循环是直接跳过这一步的,所以需要我们直接添加
arr[index++] = deque.peekFirst();
//窗口区间形成
for (int i = k; i < nums.length; i++) {
//i-k是已经在区间外了,如果首位等于nums[i-k],那么说明此时首位值已经不再区间内了,需要删除
if (deque.peekFirst() == nums[i - k]) deque.removeFirst();
//删除队列中比当前值大的值
while (!deque.isEmpty() && nums[i] > deque.peekLast()) deque.removeLast();
//把当前值添加到队列中
deque.addLast(nums[i]);
//把队列的首位值添加到arr数组中
arr[index++] = deque.peekFirst();
}
return arr;
}
}
因为本人是算法和数据结构的菜鸟,对各个算法,还有数据结构都了解的不全,所以没想到用队列做,写完前两个解法后,觉得题解区一定会有更优解,一看,果然,Krahets
的题解用到了单调队列,解法三跟着他的思路写了出来,做完这道题后,学到了单调队列,挺有收获的。