给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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]}。
用一个双端队列保存滑动窗口最大值,保证里面的元素顺序是从大到小的,如果当前入队元素小于队列前一个数值,就入队,因为一会窗口滑出可能这个小的就变成了最大值,
但是如果当前元素大于之前的元素,说明之前元素已经不是窗口内最大得了,就把前一个元素出队,一直到队空或者有元素大于当前元素,入队当前元素。这样队列里第一个元素永远都是最大的。
这里队列里保存的元素下标,而不是真正的数值,可以用下标来判断窗口大小。超出窗口大小就要滑出一部分数值。
c++:
class Solution {
public:
vector<int> maxInWindows(const vector<int>& num, unsigned int size)
{
deque<int>dq;
vector<int>res;
for(unsigned int i=0;i<num.size();++i){
while((!dq.empty())&&num[dq.back()]<=num[i])
dq.pop_back();
while((!dq.empty())&&i-dq.front()+1>size)//不可以用dq.size>size,滑动窗口可以删掉了中间结点
dq.pop_front();
dq.push_back(i);
if(i>=size-1)
res.push_back(num[dq.front()]);
}
return res;
}
};
python:
def maxInWindows(num, size):# 按照行求滑动窗口
"""
maxqueue用来保存当前最大值的【索引】,这里保存索引主要为了和当前位置对比,可以计算出是否超出窗口大小,超出就弹出;
"""
maxqueue = []
maxlist = []
n = len(num)
if n == 0 or size == 0 or size > n:
return maxlist
for i in range(n):
# 滑出窗口队首出队
if len(maxqueue) > 0 and i - size >= maxqueue[0]:
maxqueue.pop(0)
# 每超出窗口只要比队尾小就存进去,比队尾大就出队
while len(maxqueue) > 0 and num[i] > num[maxqueue[-1]]:
maxqueue.pop()
maxqueue.append(i)
if i >= size - 1:
maxlist.append(num[maxqueue[0]])
return maxlist
用一个二维滑动窗口在一个矩阵上滑动,找到每个窗口的最大值,求这个矩阵或这些最大值的和
如:n =4,m=5,a=3, b=3,n和m为行列,a和b行列窗口大小,矩阵计算方式是 (i*j) mod 10, 矩阵为:[[1 2 3 4 5], [2 4 6 8 0], [3 6 9 2 5], [4 8 2 6 0]]
滑窗结果为:[[9, 9, 9],[9, 9, 9]],和为 54。
其实就是计算机视觉里的最大池化
1.直接用切片实现复杂度高
2.还用队列实现,先在行上做滑窗,用得到的结果在列上滑窗。
import numpy as np
n =4
m =5
a =3
b =3
# [[0, 0, 0, 0, 0],
# [0, 1, 2, 3, 4],
# [0, 2, 4, 6, 8],
# [0, 3, 6, 9, 2]]
# 4 8
# 6 9
nums = [[0 for j in range(m)] for i in range(n) ]
#print(nums)
for i in range(n):
for j in range(m):
nums[i][j] = (i+1)*(j+1)% 10 #从1开始
res = 0
nums = np.array(nums) # 转化成numpy矩阵才能多维度切片
#print(nums)
for i in range(0, n-a+1):
for j in range(0, m-b+1):
res += np.max(nums[i:i+a, j:j+b])
#print('*'*10)
#print(res)
#print(res.dtype)
print(res)
def maxInWindows(num, size):# 按照行求滑动窗口
"""
maxqueue用来保存当前最大值的【索引】,这里保存索引主要为了和当前位置对比
可以计算出是否超出窗口大小,超出就弹出;
"""
maxqueue = []
maxlist = []
n = len(num)
if n == 0 or size == 0 or size > n:
return maxlist
for i in range(n):
# 滑出窗口队首出队
if len(maxqueue) > 0 and i - size >= maxqueue[0]:
maxqueue.pop(0)
# 每超出窗口只要比队尾小就存进去,比队尾大就出队
while len(maxqueue) > 0 and num[i] > num[maxqueue[-1]]:
maxqueue.pop()
maxqueue.append(i)
if i >= size - 1:
maxlist.append(num[maxqueue[0]])
return maxlist
def maxInWindowsCol(num, size, n, m):#按照列求滑动窗口
maxlist = []
res = 0
if n == 0 or size == 0 or size > n:
return 0
maxlist = [[] for i in range(n-size+1)]
for i in range(m): #列
maxqueue = []
k = 0 # 列下标
for j in range(n): #行
if len(maxqueue) > 0 and j- size >= maxqueue[0]:
maxqueue.pop(0)
while len(maxqueue) > 0 and num[j][i] > num[maxqueue[-1]][i]:
maxqueue.pop()
maxqueue.append(j)
if j >= size - 1:
# maxlist.append(num[maxqueue[0]][i])
res += num[maxqueue[0]][i]
# print('k',k, 'num',num[maxqueue[0]][i])
maxlist[k].append(num[maxqueue[0]][i])
k += 1
return maxlist, res
#print(maxInWindows([1,2,3,4,5],3))
def main():
n =4
m =5
a =3
b =3
nums = [[0 for j in range(m)] for i in range(n)]
#print(nums)
#初始化数组
for i in range(n):
for j in range(m):
nums[i][j] = (i+1)*(j+1)% 10 #从1开始
#print(nums)
res = 0
# 先按行求
newnums=[]
for i in range(n):
newnums.append(maxInWindows(nums[i], a))
#print(maxInWindows(nums[i],a))
# 再用按行求得到结果按列求
print(maxInWindowsCol(newnums, b, n, m-a+1)) # 行没变,列变成m-a+1
if __name__ == '__main__':
main()