描述
给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
示例:
输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
--------------- -----
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
思路1
- 求出前k个数中的最大元素max
- 移动数组,从
k+1开始遍历,如果nums[k+1] > max此时`max = nums[k+1]
[3 -1 -3] 5
5 > 3
max = 5
- 如果
nums[k+1] <= max,需要判断当前的max是否位于窗口的开始位置, - 如果
max是否位于窗口的开始位置,则剔除max,重新在当前的窗口中确定最大值
[3, 2, 1] 2
3 > 2 但是 3位于窗口开始,需要剔除,重新确定最大值为2
- 如果
max不在窗口的开始位置,说明当前的max还是新的窗口中的最大值,继续遍历。
代码
// 求出start-end之间的最大值
int maxValue(int *array, int start, int end) {
int max = array[start];
for(int i = start+1; i <= end; i++) {
max = array[i] > max ? array[i] : max;
}
return max;
}
int* maxSlidingWindow(int* nums, int numsSize, int k, int* returnSize) {
*returnSize = numsSize-k+1;
int *res = (int*)malloc(sizeof(int)*(*returnSize));
// 先求出初始窗口的最大值max
int max = maxValue(nums, 0, k-1);
for(int i = 0; i < *returnSize-1; i++) {
// 赋值
res[i] = max;
// 和当前窗口的下一个值进行对比,求出新窗口的max值
if(max > nums[i+k]) {
if(max == nums[i]) {
max = maxValue(nums, i+1, i+k);
}
}else {
max = nums[i+k];
}
}
// 循环的结束只求出最后一个窗口的最大值,需要再执行一次赋值操作
res[*returnSize-1] = max;
return res;
}
思路2
维持一个递减的数组,数组中保存着当前窗口中递减的元素,每次拿最大的元素和当前窗口下一个元素对比,判断过程和思路1类似,只不过是求窗口最大值的方式不一样。
int* maxSlidingWindow1(int* nums, int numsSize, int k, int* returnSize){
int *queue = (int*)malloc(sizeof(int)*numsSize);
*returnSize = numsSize - k + 1;
int *res = (int*)malloc(sizeof(int)*(*returnSize));
int resIndex = 1;
int front = 0;
int rear = -1;
for(int i = 0; i < numsSize; i++) {
// 正常插入
while(rear >= front && nums[i] > queue[rear]) {
rear--;
}
queue[++rear] = nums[i];
if(i < k) {
// i<k的时候只是构建递减数组,只能得到res[0]的值
res[0] = queue[front];
}else {
// 如果需要删除的元素为当前窗口最大值,递减数组起始索引+1
if(queue[front] == nums[i-k]) {
front++;
}
// 新窗口的最大值为新数组的第一个元素
res[resIndex++] = queue[front];
}
}
return res;
}