UVa 11572
2015-07-20 11:30
337 查看
题目:输入一个长度为n的序列A,找到一个尽量长的连续子序列,使得该序列中没有相同的元素。
代码:
方法一
方法二
分析:以上是书(算法竞赛经典入门)中的两中解决方法,方法一用的是集合容器来解决重复问题,方法二使用的是存储下标来处理重叠。可见使用适合的数据结构不仅能简化代码,还能高效地解决问题。
借助这些作为启发,我对后面的一道题进行了解答。
题目是:输入一个正整数k和一个长度为n的整数序列,定义f(i)表示从元素i开始的连续k个元素的最小值,从f(i开始一直到f(n-k+1)输出。
这个题在书上作为思考题是没有答案的,以下是我的代码:
这道题采用的是滑动窗口的形式来改变范围,并使其进入准备好的单调序列。正是因为不知道最小值什么时候被丢出序列,所以要保存好上一状态的单调序列。其时间复杂度比理想的O(n)大(此处没有使用书上建议的单调队列,考虑到内存问题,用时间去换内存),但是比每次检索最小值的复杂度O((n-k)log(k))一般要小。
如有疑问或对代码的改进有建议,请给我留言,谢谢。
代码:
方法一
#include<iostream> #include<set> #include<algorithm> #define max(a,b) ((a)>(b)?(a):(b)) using namespace std; const int Max=1000000+5; int A[Max]; int main(){ int T; while(cin>>T){ while(T--){ int n; cin>>n; for(int i=0;i<n;i++){ cin>>A[i]; } set<int> s; int L=0,R=0,ans=0; while(R<n){ while(R<n&&!s.count(A[R])){ s.insert(A[R++]); } ans=max(ans,R-L); s.erase(A[L++]); } cout<<ans<<endl; } } return 0; }
方法二
#include<iostream> #include<map> #define max(a,b) ((a>b)?(a):(b)) using namespace std; const int Max=1000000+5; int a[Max],last[Max]; map<int,int> cur; int main(){ int T; while(cin>>T){ while(T--){ int n; cin>>n; for(int i=0;i<n;i++){ cin>>a[i]; if(!cur.count(a[i])) last[i]=-1; else last[i]=cur[a[i]]; cur[a[i]]=i; } int L=0,R=0,ans=0; while(R<n){ while(R<n&&last[R]<L){ R++; } ans=max(ans,R-L); L++; } cout<<ans<<endl; cur.clear(); } } return 0; }
分析:以上是书(算法竞赛经典入门)中的两中解决方法,方法一用的是集合容器来解决重复问题,方法二使用的是存储下标来处理重叠。可见使用适合的数据结构不仅能简化代码,还能高效地解决问题。
借助这些作为启发,我对后面的一道题进行了解答。
题目是:输入一个正整数k和一个长度为n的整数序列,定义f(i)表示从元素i开始的连续k个元素的最小值,从f(i开始一直到f(n-k+1)输出。
这个题在书上作为思考题是没有答案的,以下是我的代码:
#include<iostream> #include<cstdio> #include<memory.h> using namespace std; const int Max=1000+5; int main(){ int T; while(cin>>T){ while(T--){ int a[Max],b[Max]; int n,k; cin>>n>>k; for(int i=0;i<n;i++){ cin>>a[i]; } memset(b,0,sizeof(b)); int front,rear,num=0; for(int j=0;j<k;j++){ if(b[0]==0) b[0]=a[j]; else{ if(a[j]<b[0]){ b[0]=a[j]; for(int j=1;j<num;j++) b[j]=0; num=0; }else if(a[j]>b[num]&&b[num]!=0) b[++num]=a[j]; } } cout<<b[0]<<endl; front=0;rear=k-1; while(rear<n-1){ if(a[front]==b[0]){ for(int i=0;i<num;i++) b[i]=b[i+1]; num--; } front++; if(a[rear+1]>b[num]){ b[++num]=a[rear+1]; 4000 }else{ if(a[rear+1]<b[0]) { for(int i=0;i<=num;i++) b[i]=0; b[0]=a[rear+1]; num=0; } } rear++; cout<<b[0]<<endl; } } } return 0; }
这道题采用的是滑动窗口的形式来改变范围,并使其进入准备好的单调序列。正是因为不知道最小值什么时候被丢出序列,所以要保存好上一状态的单调序列。其时间复杂度比理想的O(n)大(此处没有使用书上建议的单调队列,考虑到内存问题,用时间去换内存),但是比每次检索最小值的复杂度O((n-k)log(k))一般要小。
如有疑问或对代码的改进有建议,请给我留言,谢谢。
相关文章推荐
- android 代码实现控件之间的间距
- [Android]在代码里运行另一个程序的方法
- 肯特·贝克:改变人生的代码整理魔法
- 网页恶意代码的预防
- 高手写的Tracer-Flash代码调试类代码下载
- CSS代码缩写技巧
- 非主流Q-zOne代码代码搜集第1/2页
- CreateWeb.vbs 代码
- Lua中编译执行代码相关的函数详解
- 更有效率的css代码编写第1/3页
- 代码中到底应不应当写注释?
- SQL语言查询基础:连接查询 联合查询 代码
- 论坛头像随机变换代码
- .NET 常用功能和代码小结
- C#实现压缩HTML代码的方法
- asp编程中常用的javascript辅助代码第1/2页
- C#超实用代码段合集
- Javascript代码在页面加载时的执行顺序介绍
- JS实现图片无间断滚动代码汇总
- 我的论坛源代码(二)