12月4日总结

        今天收获还是有点的,做了几道题,也算是在做题的过程进一步了解了一下栈的用途了吧。

比如这道题:

Farmer John的奶牛在风中凌乱了它们的发型……
每只奶牛都有一个身高hi(1 ≤ hi ≤ 1,000,000,000),现在在这里有一排全部面向右方的奶牛,一共有N只(1 ≤ N ≤ 80,000)。对于奶牛i来说,如果奶牛i+1,i+2,……,N这些奶牛的身高严格小于奶牛i,则奶牛i可以看到它们凌乱的发型。
比如下面这个例子:

* * * * = *
= * * * = *
= * - * = * 奶牛面向这边-->
= * = * = *
= - = = = *
= = = = = =
1 2 3 4 5 6
('*'表示空的,这是译者为了格式特意弄的,原题没有)

令ci表示第i只奶牛能够看到的发型数量,请计算c1 + c2 + c3 + … + cN的值
对于上面这个例子,答案为3 + 0 + 1 + 0 + 1 + 0=5。

输入

第一行:奶牛数量N
第二到N+1行:第i+1行输入奶牛i的身高

输出

第一行:一个整数即c1到cN的和

样例输入

6
10
3
7
4
12
2

样例输出

5

最开始的想法就是暴力枚举,即每到一个数就往后找,直到找到比他大的数停下,看本题的数据就知道时间肯定会超限。于是我们可以考虑用一种叫单调栈的方法去做(我也是在网上找了找)。这题就是构建递减栈去做。保证栈的数据都是单调递减的,用sum去记录每次递减的个数,举个例子。比如样例,第一次将6入栈,第二次发现10比6大,于是6弹出栈,10入栈;第三次3入栈,此时栈中有10,3。满足递减顺序(3对10有贡献),于是sum+1,接下来7入栈将3弹出此时栈中有10,7.满足递减顺序,sum+1(7对10有贡献),第四次4入栈,此时栈中有10,7,4,sum+2(4对10和7有贡献),依次类推。其实我们不难发现每次sum要加上的数就是栈中的数据的个数减1。规律找出,话不多说,上代码!!!

#include<stdio.h>

int main()
{
	int a[80010],stack[80010];
	int i,n,top=0;
	long long sum=0;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	scanf("%d",&a[i]);
	for(i=1;i<=n;i++)
	{
		if(top==0||stack[top]>a[i]){
		sum += top; 
		stack[++top] = a[i];
	    }
		else
		{
			while(stack[top]<=a[i]&&top>0)
			top--;
			sum += top;
			stack[++top] = a[i];
		}
	}
	printf("%lld",sum);
	return 0;
}

注意我上面是先加上递减栈个数,再把当前数入栈的,所以不用-1。

关于思考和总结:经过改进后,可以看到时间复杂度已经将到了O(n),有人可能会疑惑,明明for循环里还有个while循环为什么是O(n)呢?我们可以知道while循环的操作就是将数弹出栈的操作,n个数最多只能弹n-1次,那么复杂度还是O(n)(注意n前的系数能忽略)。

有关栈的知识我还是在做题目中理解的,也初步见识到了栈的便利之处。(初步有了个以空间换时间的思想)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值