2823:スライディングウィンドウ:スライディングウィンドウの問題:モノトーンキュー原理+ +テンプレートを使用〜

タイトル

トピックリンクの
最小値と最大値を解決するためのスライディングウィンドウアレイ
ここに画像を挿入説明

アイデア解析

RMQセグメントツリーと明らかに行うことができますが、ツリーラインの戦いあまりにも面倒、簡単に学ぶための方法は、常に良いです。

モノトーンキューはキュー(ナンセンス)です

キューの要素が単調増加または単調に減少することが保証されており

そして、キュー要素のヘッドは、最小(または最大)ではないのですか?

もちろん、我々は間隔を計算するとき [ - K + 1 ] [I-K + 1、i]は の最大値ではなく、

それは間隔です [ - K + 1 - 1 ] [I-K + 1、I-1] 私たちは前にあることを計算していますか?だから我々はそれ(主に最大)の最後の結果を保存しようとしていませんか?

このとき、単調キューデビュー -

頭と尾削除:二つの操作の単調キューがあります。

頭の削除1.

キューの要素ヘッド場合は、当社の現在の操作の範囲を残して、この要素には使用できなくなり、私たちは頭が古いデータを削除するために削除されていること、それを削除したいです。

尾に2

仮定は、キュー要素に入ろうとしています バツ バツ 、キューのテールポインタ トン A リットル

その後、我々は両方の大きさを比較する必要が

  • バツ Q [ トン A リットル ] X \当量Q [尾] :まだ回帰Qを確保このとき、キューテールXに直接挿入されています
  • バツ > = Q [ トン A リットル ] X> = Q [尾] :この場合、キューの減少は、この時点で、我々はいくつかの操作を行い、壊れている:
    ①は、尾の要素を取り出す:現在ので、 Q [ トン A リットル ] Q [尾] の最大値ではないだけでなく、将来のためのケースを超えることはできません バツ バツ より良いです。これは、キューのポップ最後に現在の要素のようなものですので、当然の若い、より多くの戦いに参加する能力のベテランと新人の欠如、ベテランんです
    ②を繰り返して、①会議まで、 バツ < Q [ トン A リットル ] X <Q [尾] またはキューが空になるまで
    エンキュー③XX

の点ではサンプルの場合:

[1 3 -1] -3 5 3 6 7 
q={1},{3},{3,-1} output:3//分别为每次操作的结果
1 [3 -1 -3] 5 3 6 7 
q={3,-1,-3} output:3
1 3 [-1 -3 5] 3 6 7
q={-1,-3},{-1,5},{5} output:5
1 3 -1 [-3 5 3] 6 7
q={5,3} output:5
1 3 -1 -3 [5 3 6] 7 
q={5,6},{6} output:6
1 3 -1 -3 5 [3 6 7]
q={7} output:7

最大で最初のチームに各要素以来、チーム(なぜ?)一度、だから、時間複雑です ザ・ n個 O(N) もちろん、この問題は、STセグメントツリーとテーブルで行われますが、単調便利キューではありませんすることができます

実装:
原因は私たちが使用する必要がある、キューと尾の頭にメンテナンスを実行します

両端キュー

STLを使用することができdeque、手書きのかもしれ

2 d.front():返回的一个元素的引用。
3 d.back():返回最后一个元素的引用。
4 d.pop_back():删除尾部的元素。不返回值。
5 d.pop_front():删除头部元素。不返回值。
6 d.push_back(e):在队尾添加一个元素e。
7 d.push_front(e):在对头添加一个元素e。

利便性は、我々はの使用排除、配列インデックス単調キューを維持するpair面倒なまたは構造を:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<deque>
#include<vector>
#include<algorithm>
using namespace std;
int n,m;
int a[1000001];
int b[1000001];
int c[1000001];
deque<int> qx,qn;
int cnt;
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        while(!qx.empty()) qx.pop_front();
        while(!qn.empty()) qn.pop_front();
        for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
        for(int i=0;i<n;i++)
        {
            while(!qx.empty()&&a[i]>=a[qx.back()])//判断是否新加得数比前面得大,大的话我们就要把最大值放最前,
                 qx.pop_back();
            qx.push_back(i);
            while(!qn.empty()&&a[i]<=a[qn.back()])
                 qn.pop_back();
            qn.push_back(i);
            if(i>=m-1)
            {
                while(!qx.empty()&&qx.front()<=i-m) qx.pop_front();//我们把出了区间的数踢出队列
                b[cnt]=a[qx.front()];
                while(!qn.empty()&&qn.front()<=i-m) qn.pop_front();
                c[cnt++]=a[qn.front()];
            }
        }
        for(int i=0;i<cnt;i++)
        {
            if(i==0)
            printf("%d",c[i]);
            else printf(" %d",c[i]);
        }
        printf("\n");
        for(int i=0;i<cnt;i++)
        {
            if(i==0)
            printf("%d",b[i]);
            else printf(" %d",b[i]);
        }
        printf("\n");
    }


}
公開された186元の記事 ウォン称賛13 ビュー9291

おすすめ

転載: blog.csdn.net/csyifanZhang/article/details/105257494
おすすめ