题目:给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
思路:用一个双向链表存放数组的下标,让链表首的下标始终是当前窗口最大值的下标。下面以例子中的数组{2,3,4,2,6,2,5,1}解析一遍:
窗口大小为3,从数组第一个数字开始:
······当前下标为0,数字为2,当前链表为空,那么2一定是目前来说最大的值,将下标0放入链表,窗口还没有满,继续;
······当前下标为1,数字为3,当前链表首是0,下标0还在当前窗口中,不需要删除;当前链表尾部为0,下标为0的数小于当前数字,把链表尾部删除,链表为空,把当前下标1放入,窗口还没有满,继续;
······当前下标为2,数字为4,当前链表首是1,下标1还在当前窗口中,不需要删除;当前链表尾部为1,下标为1的数小于当前数字,把链表尾删除,链表为空,把当前下标2放入,窗口已满(下标2其实是第三个数字,窗口大小为3,那么以后都不需要判断窗口是否满了),将当前链表首的下标所在数字放入结果集中(因为我们保持了链表首的下标是当前窗口最大值所在的下标);
······当前下标为3,数字为2,当前链表首是2,下标2还在当前窗口中,不需要删除;当前链表尾为2,下标为2的数大于当前数字,但是下标为2的数字可能随着窗口移动而被抛弃,当前数字还是可能成为窗口中的最大值的,那么先把当前下标放入,此时链表中有下标2和3;将当前链表首的下标所在数字放入结果集中;
······当前下标为4,数字为6,当前链表首是2,下标2还在当前窗口中,不需要删除;当前链表尾为3,下标为3的数小于当前数字,把链表尾删除,链表中链表尾此时的下标是2,而下标2的数字依旧小于当前下标的数字6,继续删除链表尾,此时链表为空,把当前下标4放入,将当前链表首的下标所在数字放入结果集中;
······当前下标为5,数字为2,当前链表首是4,下标4还在当前窗口中,不需要删除;当前链表尾为4,下标为4的数大于当前数字,但是下标为4的数字可能随着窗口移动而被抛弃,当前数字还是可能成为窗口中的最大值的,把当前下标5放入,将当前链表首的下标所在数字放入结果集中;
······
经过一番推论,我们可以得到具体的思路,首先我们需要循环判断(用while进行判断)当前链表头部的下标是不是还在窗口中,如果不在就删除它;然后循环判断(用while进行判断)当前链表尾的下标位置的数字是否小于当前数字如果小于,那么这个下标所在的数字一定不是当前窗口的最大值,以后也不会是,那么删除,再次判断;如果当前链表尾的下标位置的数字大于当前数字,那么当前数字还是可能成为最大值的,因为前面的数字总要移出窗口的,把当前下标放入链表尾部;此时链表头部是当前窗口的最大值所在的下标,放入结果集中,继续遍历。
根据上面的思路,我们可以写出下面的代码:
代码:
public ArrayList<Integer> maxInWindows(int [] num, int size) {
ArrayList<Integer> list = new ArrayList<Integer>();
// 输入合法性判断
if (num == null || num.length < 1 || size < 1) {
return list;
}
// 双向链表,链表中存放的是下标,链表首存放的是当前窗口最大值所在的下标
LinkedList<Integer> queue = new LinkedList<Integer>();
for (int i = 0 ; i < num.length ; i++) {
// 链表尾部存放的值小于当前值,就去除
while (queue.size() > 0 && num[queue.getLast()] <= num[i]) {
queue.removeLast();
}
// 如果链表首的下标已经不在滑动窗口内,那么删除它
while (queue.size() > 0 && i - queue.getFirst() > size - 1) {
queue.removeFirst();
}
queue.add(i);
// 滑动窗口已满,放入最大的值,即链表首
if (i >= size - 1) {
list.add(num[queue.getFirst()]);
}
}
return list;
}