import java.util.LinkedList;
/*
单调队列 滑动窗口
单调队列是这样的一个队列:队列里面的元素是有序的,是递增或者递减
题目:给定一个长度为N的整数数列a(i),i=0,1,...,N-1和窗长度k.
要求:f(i) = max{a(i-k+1),a(i-k+2),..., a(i)},i = 0,1,...,N-1
问题的另一种描述就是用一个长度为k的窗在整数数列上移动,求窗里面所包含的数的最大值
详情见
@陈利人 http://weibo.com/lirenchen
http://weibo.com/1915548291/z3T4HbRRr
该条微博下有人回复说:
@我是RickyYang:维护一个有k个元素大顶堆,如果每次移出堆的是堆顶,那么将新数替换堆顶,并对堆做调整,
如果移出不是堆顶,则只需将新数和堆顶比较,大的留在堆顶,小的替换移出的数,无需调整堆。最坏的话时间复杂度nlogk,最好n-k+logk (11月6日 08:22)
这应该也是可行的。我的刚开始想到的也是用最大堆。不过稍嫌麻烦的是:“如果移出不是堆顶,则只需将新数和堆顶比较,大的留在堆顶,小的替换移出的数”
这样的话,要记录窗口移动后被移出窗口的那个数,同时“替换移出的数”,要在最大堆执行搜索
单调队列的参考思路:
http://xuyemin520.is-programmer.com/posts/25964
1.首先看插入元素:为了保证队列的递减性,我们在插入元素v的时候,要将队尾的元素和v比较,
如果队尾的元素不大于v,则删除队尾的元素,然后继续将新的队尾的元素与v比较,直到队尾的元素大于v,这个时候我们才将v插入到队尾
2.队尾的删除刚刚已经说了,那么队首的元素什么时候删除呢?
由于我们只需要保存i的前k-1个元素中的最大值,所以当队首的元素的索引或下标小于 i-k+1的时候,
就说明队首的元素对于求f(i)已经没有意义了,因为它已经不在窗里面了。所以当index[队首元素]<i-k+1时,将队首 元素删除
在下面的代码里面,实现队列时,我直接用了LinkedList,因为手工用数组维护一个单调队列要考虑挺多的。现在把重点放在算法的思路上^_^
*/
public class SlidingWindow {
public static void main(String[] args) {
/*
int[] array = { 8, 7, 12, 5, 16, 9, 17, 2, 4, 6 };
int k = 3;
*/
int[] array = { 3, 4, 5, 7, 3, 5, 2, 9 };
int k = 3;
int[] max = maxInWindow(array, k);
for (int i : max) {
System.out.println(i);
}
}
public static int[] maxInWindow(int[] array, int k) {
if (k <= 0 || array == null || array.length == 0) {
System.out.println("invalid input");
return new int[0];
}
int len = array.length;
int[] max = new int[len];
if (k == 1) {
System.arraycopy(array, 0, max, 0, len); //复制一份,不影响原数组
} else {
LinkedList<Item> queue = new LinkedList<Item>();
for (int i = 0; i < len; i++) {
Item curItem = new Item(array[i], i);
if (queue.isEmpty()) {
queue.addLast(curItem);
} else {
Item head = queue.getFirst();
int headIndex = head.getIndex();
//如果队首元素已不在窗口内,则删除
if (headIndex < (i - k + 1)) {
queue.removeFirst();
}
//插入元素
while (!queue.isEmpty()) {
Item tail = queue.getLast();
int tailValue = tail.getValue();
if (tailValue < array[i]) {
queue.removeLast();
if (queue.isEmpty()) {
queue.addLast(curItem);
break;
}
} else if (tailValue > array[i]) {
queue.addLast(curItem);
} else {
break;
}
}
}
//每次操作后,队首元素为当前窗口的最大值
if (!queue.isEmpty()) {
max[i] = queue.getFirst().getValue();
}
}
}
return max;
}
}
class Item {
//数组元素值
private int value;
//数组元素对应的下标
private int index;
public Item(int value, int index) {
this.value = value;
this.index = index;
}
public int getValue() {
return value;
}
public int getIndex() {
return index;
}
}
分享到:
相关推荐
**例题**:给定一个序列,求长度固定的滑动窗口在各个位置时,区间内元素的最小值和最大值。 **核心思想**: 1. **加入操作**:当新元素加入队列时,如果队尾的元素不小于新元素,则不断删除队尾元素,直到队尾元素...
单调队列和单调栈是两种在算法和数据结构领域中常用的工具,它们是基于普通队列和栈的扩展,主要用于处理有序序列中的某些特定问题,如最值查询、滑动窗口最大值或最小值等。这里我们将深入探讨这两种数据结构及其...
- **POJ2823 Sliding Window**:该问题给出一个序列和一个窗口大小k,需要计算在每个位置时,窗口内的最大值或最小值。可以使用单调队列优化将时间复杂度从O(nk)降低至O(n)。 - **最大连续和**:这是一个经典的动态...
给定一个序列,求长度固定的一个滑动区间在各个位置时,区间内元素的最小值、最大值。 2. P1886 滑动窗口 给定一个序列,求长度固定的一个滑动区间在各个位置时,区间内元素的最小值、最大值。 优点 单调队列...
算法讲解054【必备】单调队列-上
算法讲解055【必备】单调队列-下
寻找窗口的最大值最小值,是一个局部的概念,可以使用单调队列。 如最小值(从队首到队尾单增):先装上前k-1个,如果队列不为空且要加入的元素值小于队列尾的值,则将队尾弹出,直到队尾小于要加入的元素或者队列为...
我们可以维护两个单调队列,一个用来存储从左到右遍历过程中的最大值,另一个存储最小值。每次我们向右移动窗口时,需要将队列头部元素与当前新元素比较,如果不再满足单调性,则将其移除。这样,队列始终保存着从左...
在解决滑动窗口最大值的问题时,我们可以用一个单调递减的队列来存储窗口内的元素值。初始时,将窗口内的所有元素都入队。然后,每次窗口向右移动一位,我们检查队首元素是否超出窗口范围,如果超出,则将其出队;...
这种数据结构常用于处理滑动窗口最值问题,例如求解数组在不同窗口大小下的最大值或最小值。 单调栈的应用实例: 1. 求解一个数组中的最长上升子序列(LIS):通过单调栈可以快速地找到每个位置上的最小上界,从而...
**定义:** 单调队列是一种特殊的数据结构,它维护了一个单调递增或递减的队列。这种队列允许我们在队尾添加元素,在队首删除元素,并保持队列中的元素始终处于递增或递减的状态。 **特性:** 1. **插入操作**:只...
- **解法:**维护两个单调队列,一个用于计算最大值,另一个用于计算最小值。通过在队尾入队新元素时保持队列的单调性,即可在O(n)时间内解决问题。 **实现代码片段:** ```cpp void get_min() { deque<int> q; ...
- 例如,在给定一个长度为\(k\)的滑动窗口内寻找最大值的问题中,单调队列可以保证队列头部始终是最优解。 **单调队列的维护**: - **单调递增队列**:当新元素\(x\)入队时,若队尾元素小于等于\(x\),则队尾元素出...
它与一维单调队列相似,都是维护一个递增(或递减)的队列,但不同之处在于队列中的元素是二维的,即每个元素包含两个坐标值。 #### 二、二维单调队列的应用场景 1. **最大子矩阵和问题**: - 给定一个二维矩阵,...
在计算完每个窗口的最值后,接下来通过一个双层循环遍历更新后的w和ww矩阵,通过比较相邻窗口的最大值和最小值之差,找到最小的差值。如果这个差值小于已知的最小值,则更新最小值。最后,输出这个最小的差值。 该...
在IT领域,尤其是在算法与数据结构的学习和应用中,“给定一个单调递增的整数序列,问某个整数是否在序列中”这个问题是极为常见的。这个问题的核心在于如何高效地在一个已排序的数组中查找特定元素的存在性。解决这...
单调队列优化动态规划是一种在动态规划算法中提高效率的技术,尤其适用于处理具有后继最优性质的问题。在信息学竞赛中,这种技术是解决复杂问题的关键。本章将深入探讨单调队列优化动态规划的概念、原理及其应用。 ...
4. **查询**(query):在单调队列中,当前队首元素就是区间内的最小(或最大)值。如果需要查询其他位置的最值,可能需要额外的数据结构辅助。 5. **调整**(adjust):在插入新元素或删除旧元素后,可能需要对...
为了在O(1)时间内找到这个最大值,我们使用一个单调队列B来存储F[i - 1][b + k * d] - k * w[i]的值。每次有新的元素M进入队列时,我们删除队列B中所有小于M的元素。当元素离开队列时,如果队列B的第一个元素与M相等...
该定理说明了对于任何实数域上的单调递增且上界数列,其必定会收敛到一个极限值。为了深入理解这个定理及其证明过程,我们需要明确几个数学概念: 1. 数列:数列是一个函数,其定义域为自然数集,值域为实数集或...