算法-数组 求数组中滑动窗口的最大数值列表

这个题目是在一个数组中,有一个滑动窗口,滑动窗口从数组的左边(i=0)开始,依次往右边滑动,获取每滑动一次的窗口内的最大值,得到一个列表进行返回

比如数组 int[] a = { 4, 3, 5, 4, 3, 3, 6, 7 };  滑动窗口 w = 3,那么返回值列表如下:

1. 滑动窗口在数组中的起始位置 i = 0, 滑动窗口 window是3 (w = 3), 所以窗口内元素是 {4,3,5}  => 获取窗口内最大元素 -> 5

2. 滑动窗口往右边滑动一个位置i=1,  滑动窗口内元素是 {3,5,4} => 获取窗口内最大元素 -> 5

3. 滑动窗口继续一个位置一个位置往右边滑动

i =2 => 滑动窗口 {5,4,3} => 获取窗口内最大元素 -> 5

i =3 => 滑动窗口 {4,3,3} => 获取窗口内最大元素 -> 4

i =4 => 滑动窗口 {3,3,6} => 获取窗口内最大元素 -> 6

i =5 => 滑动窗口 {3,6,7} => 获取窗口内最大元素 -> 7

i =6 => 滑动窗口 {6,7} 已经不到w=3的3个元素,所以结束

最终结果就是 [5,5,5,4,6,7]

从上面的过程中,我们可以得出

如果滑动窗口左边的位置是数组位置i,那么滑动窗口右边的位置就是 (i+w-1), 也就是说,滑动窗口的范围是 [i, i + w - 1]

如果滑动窗口右边的位置是数组位置i, 那么滑动窗口左边的位置就是 (i - w + 1), 也就是说,滑动窗口的范围是 [i-w+1, i]

最后得到的结果集数组的长度是  原始数组长度 n - 滑动窗口大小 w + 1 = n - w + 1

这道题目,我们需要使用双向队列来实现. 双向队列是这样的

 

image

 由于C#中并没有双向队列,所以我们使用C#中的 双向链表 LinkedList来模拟这个双向队列

image

image

image

image

image

 

滑动窗口这类型题目,我们一般都是使用双向列表来进行解答,双向队列可以快速地进行插入和删除操作,从而快速地计算出窗口内的最大值或者最小值。

public static int[] SlidingWindowMax(int[] nums, int windowSize)
{
    // 1.边界判断:数组为空、窗口非法,直接返回空数组
    if (nums == null || nums.Length == 0 || windowSize <= 0)
        return Array.Empty<int>();

    // 保存每个窗口的最大值结果
    List<int> result = new List<int>();
    // 双端队列:存放数组【下标】,不是数值!队列内对应数值单调递减
    LinkedList<int> deque = new LinkedList<int>();

    // 遍历数组 i 是当前元素下标
    for (int i = 0; i < nums.Length; i++)
    {
        // ==========① 清理队尾:维持单调递减队列==========
        // 如果队列不为空,并且当前数字 >= 队尾下标对应的数值
        // 队尾这个数,只要当前i还在窗口内,它永远不可能成为窗口最大值,直接删掉
        while (deque.Count > 0 && nums[i] >= nums[deque.Last.Value])
        {
            deque.RemoveLast();
        }
        // 当前下标加入队列尾部
        deque.AddLast(i);

        // ==========② 清理队首:把已经滑出窗口的下标移除==========
        // 当前窗口左边界 left = i - windowSize + 1
        // 队首下标 < left,代表这个元素已经不在当前窗口里,过期了
        while (deque.Count > 0 && deque.First.Value < i - windowSize + 1)
        {
            deque.RemoveFirst();
        }

        // ==========③ 窗口已满,开始记录最大值==========
        // i >= windowSize -1:窗口长度凑够windowSize,第一个窗口形成
        if (i >= windowSize - 1)
        {
            // 队首下标对应的数字就是当前窗口最大值
            result.Add(nums[deque.First.Value]);
        }
    }
    // List转数组返回
    return result.ToArray();
}

 

 

 

 

 

 

 

 

 

 

 

 

 

posted on 2026-09-26 14:01  新西兰程序员  阅读(1)  评论(0)    收藏  举报