数据结构——单调队列

单调队列

        单调队列的概念和操作过程

        概念:

        单调队列和单调栈在操作上有相似之处,但因为单调队列是队列,所以多了一项特殊操作,即头部的元素可以出队,相当于滑动窗口向后滑动。这头部的出队操作就相当于淘汰,用以维护窗口的滑动。

以下通过图片来解释单调队列的操作:

数据结构——单调队列_第1张图片

        继续入队,直到入队索引2元素时,违反了队列里的单调性:

数据结构——单调队列_第2张图片

        现在就需要将违反单调性的元素进行从对位剔除,也就是tail指针向前,直到到不违反单调性或者与head指针相同;

数据结构——单调队列_第3张图片

        然后入队索引2元素:

数据结构——单调队列_第4张图片

        现在入队索引3,然后又违反了单调性,剔除索引2,入队索引3:

数据结构——单调队列_第5张图片

        由于上面没有发生淘汰的过程,我就没有说从头部淘汰的过程,现在经过操作到达图中情况:

数据结构——单调队列_第6张图片

        现在索引在6的位置,头部索引在3,6 - 3 = 3 = k,那么就需要从头部淘汰索引3的元素,那头指针向后移动一个,这就是淘汰的操作:

数据结构——单调队列_第7张图片

        那么整个的单调队列的操作,就是这样最终队列应该是这样:

数据结构——单调队列_第8张图片

单调队列的作用:  

单调队列的主要作用是在处理数据序列中,帮助解决需要维护一定单调性的问题,通常是查找滑动窗口内的最大或最小值。其作用包括:

  1. 查找滑动窗口内的最大值或最小值:单调队列可以在O(1)的时间复杂度内获取当前滑动窗口的最大值或最小值,而不需要遍历整个窗口,这在实时数据处理中非常有用。

  2. 优化数据流处理:当需要实时处理数据流并获取特定窗口内的信息时,单调队列可以提供高效的解决方案,减少不必要的计算和遍历。

  3. 优化某些动态规划问题:在一些动态规划问题中,需要维护满足特定条件的一系列元素,单调队列可以帮助高效地实现这种要求。

  4. 解决其他需要维护单调性的问题:除了滑动窗口问题,单调队列还可用于解决其他需要维护单调性的问题,如找到数组中连续子数组的最大或最小值。

总之,单调队列的主要作用是通过维护一个队列,使其中的元素保持一定单调性,以提高特定问题的解决效率,尤其在需要实时处理数据流或窗口数据的情况下,它具有显著的性能优势。

例题:

        力扣剑指offer59

数据结构——单调队列_第9张图片

int* maxSlidingWindow(int* nums, int numsSize, int k, int* returnSize){
    int q[numsSize];//创建队列
    memset(q, 0, sizeof(q));//初始化队列
    int head = 0, tail = 0;//初始化指针
    int *ret = (int *)calloc(sizeof(int), numsSize);//创建返回数组
    int cnt = 0;//记录返回数组元素个数
    for (int i = 0; i < numsSize; i++) {
        while (head != tail && nums[i] >= nums[q[tail - 1]]) tail--;//违反单调性就剔除
        q[tail++] = i;//将当前索引入队
        if (i - k >= q[head]) head++;//当头部元素不在窗口时,淘汰
        if (i < k - 1) continue; //没有达到窗口大小,继续入队
        ret[cnt++] = nums[q[head]];//头部元素就是窗口最大值,维护的是单调递减,所以头部就是最大值,反之就是最小值
    }
    *returnSize = cnt;
    return ret;
}
        这个过程就和上面的过程是完全一样的,只是题目是维护单调递减,而我上面的图片是维护的单调递增,思路都是一模一样的;

你可能感兴趣的:(数据结构,算法)