算法与数据结构实验题 4.8 干净的序列

★实验任务

有一个长度为 n 的序列,第 i 个的数为 a[i]。我们定义如果它的一个连续的子串为“没有进行过干净的交易”,那么这个子串的最大值与最小值之差在[m,k]中。

现在,你的任务是找到一条最长的“没有进行过干净的交易”的子串。

★数据输入

第一行输入三个正整数 n m k (0<n<=10000),m(0 =< m =< k =< n)。

接下去一行有 n 个正整数,第 i 个数表示 a[i]的值。

★数据输出

输出一个数,表示这个子串的长度。

输入示例1
5 0 0
1 1 1 1 1
输出示例1
5
输入示例2
6 0 3
3 1 2 3 4 5
输出示例2
5

题解:
网上关于这道题只有 O ( n 2 ) O(n^2) O(n2)的暴力解法,事实上,用两个单调队列可在 O ( n ) O(n) O(n)复杂度内解决。下面上代码:

#include<iostream>
using namespace std;
class Node{
	public:
		int pos,data;
		Node(){}
		Node(int pos,int data):pos(pos),data(data){}
		Node(Node& other){
			this->pos=other.pos;
			this->data=other.data;
		}
};
class Queue{
	public:
		int head,tail;
		const int maxlen;
		Node *queue;
		Queue(int maxlen=(int)1e5+5):maxlen(maxlen){
			this->head=0;
			this->tail=0;
			this->queue=new Node[maxlen];
		}
		~Queue(){
			delete []this->queue;
		}
		bool empty(){
			return this->head==this->tail;
		}
		int size(){
			return (this->tail-this->head+this->maxlen)%this->maxlen;
		}
		Node& operator[](int index){
			if(index<0){
				return this->queue[(this->tail+index+this->maxlen)%this->maxlen];
			}
			else{
				return this->queue[(this->head+index)%this->maxlen];
			}
		}
		int append(Node& elem){
			this->queue[this->tail]=elem;
			this->tail=(this->tail+1)%this->maxlen;
			return this->size();
		}
		Node& pop_left(){
			Node &tmp=this->queue[this->head];
			this->head=(this->head+1)%this->maxlen;
			return tmp;
		}
		Node& pop(){
			Node &tmp=this->queue[(this->tail-1+this->maxlen)%this->maxlen];
			this->tail=(this->tail-1+this->maxlen)%this->maxlen;
			return tmp;
		}
		friend ostream& operator<<(ostream& out,Queue& q);
};
ostream& operator<<(ostream& out,Queue& q){
	for(int i=0;i<q.size();i++)
	{
		out<<q[i].data<<' ';
	}
	out<<endl;
	return out;
} 
int diff(Queue& maxq,Queue& minq){
	return maxq.empty()||minq.empty()?0:maxq[0].data-minq[0].data;
}
int main(){
	Queue maxq,minq;
	int n,m,k,data[(int)1e5+5];
	cin>>n>>m>>k;
	int l=0,r=0,sub=0;
	while(true){
		//change sub
		int tmp=diff(maxq,minq);
		if(tmp<=k&&tmp>=m&&sub<r-l){
			sub=r-l;
		}
		if(l==n-1)break;
		//choose l++ or r++
		if(tmp<=k&&r<=n-1){
			cin>>data[r++];
			Node elem(r-1,data[r-1]);
			//minq
			while(!minq.empty()&&minq[-1].data>data[r-1])minq.pop();
			minq.append(elem);
			//maxq
			while(!maxq.empty()&&maxq[-1].data<data[r-1])maxq.pop();
			maxq.append(elem);
		}
		else{
			l++;
			//minq
			while(!minq.empty()&&minq[0].pos<l)minq.pop_left();
			//maxq
			while(!maxq.empty()&&maxq[0].pos<l)maxq.pop_left();
		}
		cout<<"-------l="<<l<<";r="<<r<<"--------"<<endl;
		cout<<minq<<endl;
		cout<<maxq<<endl;
	}
	cout<<sub;
	return 0;	
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值