集训第四周(高效算法设计)K题 (滑窗问题)

UVA 11572 唯一的雪花

 

题意:给你从1到n的数组,要求求得其中的最长连续不重复子序列,经典的滑窗问题,方法是维护一个窗口,设置左框和右框,然后不断的进行维护和更新

 

方法一:

#include"iostream"
#include"set"
#include"cstring"
#include"cstdio"
#include"algorithm"
using namespace std;
const int maxn=1000000+10;
set<int>book;
int a[maxn];
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int n,t,sum=0,ans=0;
        cin>>n;
        book.clear();
        for(int i=0;i<n;i++)
        {
            cin>>a[i];
        }
        int r=0,l=0;
        for(;r<n;)
          {
              while(!book.count(a[r])&&r<n)
              {
                  book.insert(a[r]);
                  r++;
              }
              ans=max(ans,r-l);
              book.erase(a[l]);
              l++;
           }
        cout<<ans<<endl;
    }
    return 0;
}

 方法二:

#include"iostream"
#include"set"
#include"cstring"
#include"cstdio"
#include"algorithm"
using namespace std;
const int maxn=1000000+10;
int pos[maxn];
int a[maxn];
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int n,t,sum=0,ans=0;
        cin>>n;
        memset(pos,-1,sizeof(pos));
        for(int i=0;i<n;i++)
        {
            cin>>a[i];
        }
        int r=0,l=0;
        a[n]=a[n-1];
        for(int i=0;i<=n;i++)
          {
             if(pos[a[i]]>=l)
             {
                 ans=max(ans,i-l);
                 l=pos[a[i]]+1;
             }
             pos[a[i]]=i;
          }
        cout<<ans<<endl;
    }
    return 0;
}

 刘汝佳紫书上还提到过滑动窗口的最小值问题,其中使用到了单调队列,贴个地址去学习学习:

http://m.blog.csdn.net/blog/lx417147512/24916441

 

#include <stdio.h>
#define MAX 1000001
int n,k;
int pre1,pre2,lst1,lst2,len_max,len_min; // 两个队列的头指针与尾指针,最大值的下标,最小值的下表
int num[MAX],Increase[MAX],Decrease[MAX],Max[MAX],Min[MAX]; // Num存数据,递增与递减队列,最大值,最小值的数组。
// 递减序列的压入操作
void in_min(int i)
{
while( pre1<=lst1 && num[ Decrease[lst1] ]<num[i] ) //一直到寻找到比当前待插入值更大的位置,这是维护一个递减序列
--lst1;
Decrease[++lst1]=i;

// 如果大于等于k个数,就需要向最大值数组赋值
if( i>=k )
{
if(Decrease[pre1]<=i-k)
pre1++;
Max[len_max++]=num[ Decrease[pre1] ]; //当前滑动窗口的最大值即为递减序列的队头
}
}
// 递增序列的压入操作
void in_max(int i)
{
while( pre2<=lst2 && num[ Increase[lst2] ]>num[i] ) //一直到寻找到比当前待插入值更小的位置,这是维护一个递增序列
--lst2;
Increase[++lst2]=i;

// 如果大于等于k个数,就需要向最小值数组赋值
if( i>=k )
{
if(Increase[pre2]<=i-k)
pre2++;
Min[len_min++]=num[ Increase[pre2] ]; //当前滑动窗口的最小值即为递增序列的队头
}
}
int main()
{
int i;
while( ~scanf("%d%d",&n,&k) )
{
// 初始化
pre1=pre2=len_max=len_min=0;
lst1=lst2=-1;

// 读入数据
for(i=1;i<=n;++i)
{
scanf("%d",&num[i]);
in_max(i);
in_min(i);
}

// 输出数据
for( i=0;i<len_min-1;++i )
printf("%d ",Min[i]);
printf("%d\n",Min[len_min-1]);
for( i=0;i<len_max-1;++i )
printf("%d ",Max[i]);
printf("%d\n",Max[len_max-1]);
}
return 0;
}

posted @ 2015-08-05 17:23  江南何采莲  阅读(349)  评论(0编辑  收藏  举报