这个是我完成的第一个 LintCode 上面的超难的题目,特此纪念一下,并分享一下结题的思路。
原题目链接:滑动窗口的最大值
问题描述:
给出一个可能包含重复的整数数组,和一个大小为 k 的滑动窗口, 从左到右在数组中滑动这个窗口,找到数组中每个窗口内的最大值。
样例说明:
给出数组 [1,2,7,7,8], 滑动窗口大小为 k = 3. 返回 [7,7,8].
解释:
最开始,窗口的状态如下:
[|1, 2 ,7| ,7 , 8], 最大值为 7;
然后窗口向右移动一位:
[1, |2, 7, 7|, 8], 最大值为 7;
最后窗口再向右移动一位:
[1, 2, |7, 7, 8|], 最大值为 8.
问题分析:
1.一开始的时候,我们将窗口置于最左边,遍历窗口中的值,得到最大值。
2.将窗口向右移动,在这个移动的过程中,我们会将上一个窗口的最左边一个元素移除,将紧邻窗口的右边的元素移入,
这时, 情况1: 如果我们移入的这个值是不小于上一个窗口的最大值,那么此时当前窗口的最大值就是新移入的这个值
情况2: 如果移入的这个值要小于上一个窗口的最大值,并且移除的这个元素正好就是上一个窗口的最大值,那么我们就要重新从当前窗口中选出最大值
情况3: 如果移入的这个值小于上一个窗口的最大值,并且移除的这个元素也不是上一个最大值,那么当前窗口的最大值也是上一个窗口的最大值
实现代码:
/**
* @author 作者 John L:
* @version 创建时间:May 11, 2018 8:46:36 PM
*/
public class TestMaxSlidingWindow {
public ArrayList<Integer> maxSlidingWindow(int[] nums, int k) {
ArrayList<Integer> result = new ArrayList<Integer>();
if(nums == null || nums.length == 0) return result;
//第一个窗口,先遍历窗口值选出最大值
int greatestNumInLastWindow = findGreatestNumBetween(nums, 0, k - 1);
result.add(greatestNumInLastWindow);
for(int i = 1; i < nums.length - k + 1; i ++){
//将窗口右移,start是窗口的最左边元素座标,end是窗口最右边元素座标
int start = i;
int end = start + k - 1;
if (nums[end] >= greatestNumInLastWindow) {
//对应情况1,将新移入的元素作为窗口最大值
greatestNumInLastWindow = nums[end];
} else if(nums[start - 1] == greatestNumInLastWindow){
//对应情况2, 重新从窗口中选出最大值
greatestNumInLastWindow = findGreatestNumBetween(nums, start, end);
}
//情况3则什么都不用做,直接使用上一个窗口的最大值
//将当前窗口的最大值加入result中
result.add(greatestNumInLastWindow);
}
return result;
}
/**
* 窗口位置从start到end, 遍历窗口中的值, 选出最大值
*/
private int findGreatestNumBetween(int[] nums, int start, int end) {
int temp = Integer.MIN_VALUE;
for (int i = start; i <= end; i++) {
temp = temp < nums[i] ? nums[i] : temp;
}
return temp;
}
}