[刷题之旅no3 奶牛排队]

奶牛排队问题:
给出数组大小
给出数组内容
求数组中符合要求的最长子数组(连续)
要求就是:前面最小,后面最大,中间奶牛不可以和两端相等
思路,对数组进行遍历:
分开头(长度为0)
记录开头数组,记录数组长度,长度和下标加一
中间
与前面相比
如果此时长度1
如果小于等于,归零,说明不成队列,比较记录最大值0,并且以这个元素为开头继续遍历
如果大于,长度加1,下标加1
此时长度大于1(看来结尾的判断有点问题,所以一定要思考)
如果大于
说明此时可以成为一个队列,长度加一,并且要进行max判断
如果等于(需要讨论)
等于,但不知道是否合理,所以长度加一,不进行max判断,直接不用管就好了。
如果小于前面的
不成队列,长度变为1,重新开始
好吧,这下惨了,我连题都没读懂额。
我的思想出现了问题,题目中没有要求奶牛的身高是递增的,也就是说,只要求队列两端,if前者小,后者最大即可,对于中间值的顺序并没有要求哦。
更改代码:
加入max,min,对队列两端进行标记
min标记数组首位,length+1,i+1
判断是否大于min
如果大于
{
进入队列
判断是否大于max
{
大于就更新max,同时记录length+1,判断是否最长,记录
小于等于则length+1,继续向后遍历
}
}
如果等于小于
{
更新min和max,同时length=1;
}
又错了,。。。
不过有进步,进步了40分,现在七十分
想一想又是哪里出了问题
逻辑出现严重问题,也就是说,在我设置最小值之后,如果此时队列中进入了一个特别大的数,那么会导致之后数字不会出现闭合,也就是说还不如不加入这个数字呢/
每当更新一次最大值之后,我都要对这个最大值进行记录,然后尝试将其后面的一个数字当作最小值,来进行处理。
实在不行,借鉴大佬思路,看到题目中的标签
要用到一个算法,名字叫:单调栈
对于这道题所要求的就是对于这个序列,需要保证:
对于这个序列的最左端的值,其右边第一个小于等于它的值一定在最右端值的右边
而对于这个序列最右端的值,其左边第一个大于等于它的值一定在最左端值得左边
分别对这个数组进行左右遍历,分别找到每个元素对应的:
1.其右端,第一个小于等于它的值的下标
2.其左端,第一个大于等于它的值的下标。
取出两个元素a,b(小标),且a<b,此时只需要判断
a的右端第一个小于它的值大于b,而b左端第一个大于它的值小于a即可,并且记录此时长度Length=b-a+1;
yes!
不过问题还是有,就是n方,时间复杂度还是蛮高的。
确实在我提交答案之后,TLE哥出现了,说明我还是要改进我的算法,但是单调栈用对了,我还是挺高兴的。
学习大佬的思想:
区别:单调栈的产生
最后遍历方式
自闭,解不出来,先放着。。。反正单调栈算是学会了
这道题直接用单调队列+单调栈解决即可。
先求出每个元素最左边第一个大于等于它的元素(单调栈)
然后让每个元素入栈判断当前元素是否小于队首元素
小于等于,则队首出列,一直到当前元素的位置,相当于重开
大于,那么就判断当前元素是否满足题意,也就是最左边的第一个大于等于他的元素是否在队首元素对应下标的左边
如果在,那么直接更新最大值,不在继续遍历
好的现在我们复习一下求数组每个值左边第一个大于他的下标
倒序遍历数组
栈空
入栈
栈不空
判断将其和栈顶元素相比
如果大于等于栈顶元素
栈顶元素对应下标,记录当前元素的下标
如果小于栈顶元素,
入栈
当遍历完毕的时候,即刻结束
好吧,万万么想到还是70分,这
麻了。无法想象自己到底错在哪里
三联错,到底是什么原因?
啊啊啊啊啊啊啊啊啊啊!气死我了,气死我了!!
哈哈哈、原来还是我的思路有问题啊!
试一试
1 8 2 6 7,按照我的思路,只有遇到比当前队首元素小的才可以更新,但是现在,这个这个最好情况,其实是2 6 7,但是在我的思路里面永远不会出现的
这样吧
判断当前队尾元素对应左边第一个大于他的元素是否在左边,如果在,直接更新最大值
如果不在,那么从他的第一个大于他的元素的右边开始,依次判断是否其右边第一个小于等于他的元素在当前队尾的右边
直到第一次判断成功,或者一直判断到他自己为止
相当于多了判断,时间复杂度会升高
拿下!
好好反思一下自己的思路问题吧!
多少有些致命了

#include<stdio.h>
int stack[100100]={0},cow[100100]={0},leftr[100100]={0},rightr[100100]={0};
int top=0,head=1,tail=0,n,maxlen=0;
//注意stack用来记录下标,而不是位置 
void scan()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&cow[i]);
	}
}
void stc()
{
	for(int i=n;i>0;i--)
	{
		if(top==0)
		{
			top++;
			stack[top]=i;
		}
		else
		{
			while(1)
			{
				if(cow[i]<cow[stack[top]]||top==0)//栈空//比他小,直接入
				{
					top++;
					stack[top]=i;
					break;
				}
				else//大于等于 
				{
					leftr[stack[top]]=i;
					top--;
				}
			}
		}
	}
	top=0;
	for(int i=1;i<=n;i++)
	{
		if(top==0)
		{
			top++;
			stack[top]=i;
		}
		else
		{
			while(1)
			{
				if(cow[i]>cow[stack[top]]||top==0)//栈空//比他小,直接入
				{
					top++;
					stack[top]=i;
					break;
				}
				else//小于等于 
				{
					rightr[stack[top]]=i;
					top--;
				}
			}	
		}
	}
}
void lin()
{
	while(1)
	{
		tail++;
		if(cow[tail]<=cow[head])
		{
			head=tail;
		}
		else
		{
			if(leftr[tail]<head)
			{
				if(tail-head+1>maxlen)
				{
					maxlen=tail-head+1;
				}
			}
			else
			{
				for(int i=leftr[tail]+1;i<tail;i++)
				{
					if(rightr[i]>tail)
					{
						if(tail-i+1>maxlen)
						{
							maxlen=tail-i+1;
						}
						break;
					}
				}
			}
		}
		if(tail==n)
		{
			break;
		}
	}
}
int main()
{
	scan();
	stc();
	lin();
	printf("%d",maxlen);
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值