题目描述
A公司准备对他下面的N个产品评选最差奖,
评选的方式是首先对每个产品进行评分,然后根据评分区间计算相邻几个产品中最差的产品。
评选的标准是依次找到从当前产品开始前M个产品中最差的产品,请给出最差产品的评分序列。
输入描述
第一行,数字M,表示评分区间的长度,取值范围是0<M<10000
第二行,产品的评分序列,比如[12,3,8,6,5],产品数量N范围是-10000 < N <10000
输出描述
评分区间内最差产品的评分序列
用例
输入 | 3 12,3,8,6,5 |
输出 | 3,3,5 |
说明 | 12,3,8 最差的是3 3,8,6 最差的是3 8,6,5 最差的是5 |
滑动窗口最小值问题详解
一、核心解题思路
问题分析
题目要求计算产品评分序列中每个长度为M的连续子序列(滑动窗口)的最小值。具体来说:
- 给定一个长度为N的产品评分序列
- 对于每个位置i(起始位置),计算从i开始连续M个产品中的最低评分
- 最终输出所有窗口最小值组成的序列
关键特性
- 滑动窗口:窗口大小固定为M,每次向右移动一个位置
- 实时计算:需要高效获取每个新窗口的最小值
- 边界处理:当窗口超出序列边界时停止计算
暴力解法的问题
直接遍历每个窗口找最小值的时间复杂度是O(N×M),当N和M较大时(最大10000),计算量可达1亿次,效率低下。
优化方案:单调队列
使用双端队列维护一个单调递增序列:
- 队列中存储元素索引,对应值保持递增关系
- 队首元素始终是当前窗口的最小值
- 添加新元素时,从队尾移除比它大的元素
- 移动窗口时,检查队首元素是否过期
算法流程
初始化空队列
遍历序列中的每个评分:1. 移除过期元素(不在当前窗口的)2. 移除队尾比当前元素大的元素3. 将当前元素加入队尾4. 记录当前窗口最小值(队首元素)
二、完整代码实现
from collections import dequedef main():# 读取输入M = int(input().strip())scores = list(map(int, input().split(',')))# 边界检查if M <= 0 or M > len(scores):print("")returnresult = [] # 存储结果dq = deque() # 双端队列(存储索引)for i in range(len(scores)):# 1. 移除过期元素(不在当前窗口内)if dq and dq[0] <= i - M:dq.popleft()# 2. 移除队尾比当前元素大的元素while dq and scores[dq[-1]] >= scores[i]:dq.pop()# 3. 添加当前元素索引dq.append(i)# 4. 记录窗口最小值(当窗口完全形成时)if i >= M - 1:result.append(str(scores[dq[0]]))# 输出结果print(",".join(result))if __name__ == "__main__":main()
代码解析:
-
输入处理:
- 读取窗口大小M
- 读取评分序列并转为整数列表
- 边界检查:M必须合法(0<M≤序列长度)
-
数据结构:
- 结果列表
result
存储最小值序列 - 双端队列
dq
存储元素索引
- 结果列表
-
核心算法:
- 移除过期元素:检查队首索引是否在窗口外(索引 ≤ i-M)
- 维护单调性:从队尾移除比当前元素大的值
- 添加新元素:将当前索引加入队尾
- 记录结果:当窗口完全形成(i ≥ M-1)时记录队首值
-
输出处理:
- 将结果列表转为逗号分隔字符串
三、示例解析
输入:M=3, 序列=[12,3,8,6,5]
执行过程:
当前索引 | 当前值 | 操作步骤 | 队列状态 | 窗口范围 | 最小值 |
---|---|---|---|---|---|
i=0 | 12 | 添加索引0 | - | ||
i=1 | 3 | 移除比3大的12 → 添加索引1 | [0-1] | - | |
i=2 | 8 | 添加索引2 | [1,2] | [0-2] | 3 |
i=3 | 6 | 移除比6大的8 → 添加索引3 | [1,3] | [1-3] | 3 |
i=4 | 5 | 移除过期索引1 → 移除比5大的6 → 添加索引4 | [2-4] | 5 |
队列状态变化:
i=0: 队列=[0] → 对应值[12]
i=1: 队列=[1] → 对应值[3](移除12)
i=2: 队列=[1,2] → 对应值[3,8]
i=3: 队列=[1,3] → 对应值[3,6](移除8)
i=4: 队列=[4] → 对应值[5](移除3和6)
输出:3,3,5
窗口最小值计算:
- 窗口[12,3,8] → 最小值3
- 窗口[3,8,6] → 最小值3
- 窗口[8,6,5] → 最小值5
四、总结
关键要点:
- 单调队列维护:确保队列中元素对应值单调递增
- 索引存储:通过索引同时获取元素值和位置信息
- 过期检查:每次迭代检查队首是否在窗口内
- 及时清理:添加新元素时移除无效的较大元素
适用场景:
- 需要高效计算滑动窗口最小值的场景
- 实时数据流中的统计分析
- 序列处理中的连续区间计算
此解法完全满足题目要求,通过维护单调队列高效解决了滑动窗口最小值问题,适合处理大规模数据序列。