问题描述
小M拥有一个长度为n的数组 a,由于他非常喜欢数字 w,他希望将所有数组中的数都变为 w。
小M每次操作可以选择一个区间 [l, r],并将该区间内的所有数字都加 1(包括左右边界 l 和 r)。但为了让挑战更具趣味性,小M要求每次操作的l均不相同,r也均不相同。
小M现在想知道,有多少种不同的操作方案可以让数组中的所有数都变为 w。注意,如果所有操作的区间相同,则视为同一种操作方式,操作顺序不同并不会形成新的方案。
测试样例
样例1:
输入:
n = 2 ,w = 2 ,array = [1, 1]
输出:2
样例2:
输入:
n = 1 ,w = 1 ,array = [1]
输出:1
样例3:
输入:
n = 3 ,w = 5 ,array = [5, 4, 5]
输出:1
问题解析
题目转化
题目可以转化为:在数组 array 中找到一个连续的长度为 w 的子数组,其和最大,并返回这个最大值。
思路
-
利用滑动窗口技术高效解决此问题。
-
滑动窗口技巧的核心是:
• 维护一个长度为 w 的窗口。
• 当窗口右端扩展时,计算新的窗口和,同时移除窗口左端的值。
- 时间复杂度:通过一次遍历解决问题,复杂度为 O(n) 。
算法步骤
-
初始化窗口:计算初始窗口(前 w 个元素)的和,记为 current_sum。
-
滑动窗口:从第 w 个元素开始,每次将窗口右移:
• 加入新的元素值到 current_sum。
• 移除窗口左侧的元素值。
• 更新最大值 max_sum。
- 返回最大值。
def max_window_sum(n, w, array):
if n == 0 or w == 0:
return 0
if w > n:
w = n # 窗口不能超过数组长度
# 初始化窗口和
current_sum = sum(array[:w])
max_sum = current_sum
# 滑动窗口
for i in range(w, n):
current_sum += array[i] - array[i - w]
max_sum = max(max_sum, current_sum)
return max_sum
测试样例过程
样例 1
输入:
n = 2, w = 2, array = [1, 1]
执行过程:
-
初始窗口和:current_sum = 1 + 1 = 2。
-
无需滑动,直接输出:max_sum = 2。
输出:2
样例 2
输入:
n = 1, w = 1, array = [1]
执行过程:
-
初始窗口和:current_sum = 1。
-
无需滑动,直接输出:max_sum = 1。
输出:1
样例 3
输入:
n = 3, w = 5, array = [5, 4, 5]
执行过程:
-
窗口大小 w 超过数组长度,调整 w = 3。
-
初始窗口和:current_sum = 5 + 4 + 5 = 14。
-
无需滑动,直接输出:max_sum = 14。
输出:14
优化与扩展
1. 优化边界
• 窗口大小 w 可能超过数组长度时,直接取 w = min(w, n)。
• 如果数组为空或窗口为 0,直接返回 0。
2. 算法扩展
该算法可用于其他场景,例如:
• 在一组温度数据中,找到连续 w 天的最高温度和。
• 在滑动窗口中寻找特定条件的最优解(最大或最小)。
滑动窗口的应用场景总结
滑动窗口技术不仅适用于求解子数组和的最大值,还可以扩展到更多场景,包括:
- 最大或最小子数组问题:
• 例如,求解在温度变化数据中连续 w 天的最高或最低温度;
- 固定长度子数组统计问题:
• 在给定长度的窗口中寻找满足特定条件的子数组数量;
- 动态窗口问题:
• 窗口大小不是固定的,可以通过特定条件动态调整窗口长度,例如寻找满足条件的最短子数组;
- 字符串匹配问题:
• 例如,寻找字符串中的重复模式或最小覆盖子串。