填坑Ⅰ | C++ | 栈

一、题目描述

Description

假设北湖的地面是一维的,每一块宽度都为1,高度是非负整数,用一个数组来表示。

现提供不限量的 1 × 2 规格的石头,问是否可以将北湖填平。(所有地面到达同一高度即为填平)

注:石头只能水平或垂直填放。

Input
样例有多组输入至文件末尾;

每组用例占两行;

第一行输入1个整数 n (1 ≤ n ≤ 2×1e5 )表示北湖地面总宽度;

第二行输入 n 个整数 a( 0 ≤ a ≤ 1e9 ) ,用空格间隔,表示地面高度。

Output
若能填平则输出“YES”,否则输出“NO”。

测试输入期待的输出时间限制内存限制额外进程
测试用例 1以文本方式显示
  1. 5↵
  2. 2 1 1 2 5↵
  3. 3↵
  4. 4 5 3↵
  5. 3↵
  6. 1 2 3↵
以文本方式显示
  1. YES↵
  2. YES↵
  3. NO↵
1秒64M0

二、思路过程

        需要考虑的主要问题就是:怎么填平?

        因为题目给出的样例数太少,为了思考这个问题,首先我是自己用excel做了几个简单的样例,然后自己试着能不能填平,填着填着就发现有几种最简单最容易的情形。

假设我们会垫高到的最终高度是top_h,我们的当前高度是h。

情形1:

         当top_h - h是偶数时,直接竖着垫高即可。

情形2:

         当h1和h2相邻,而且h1=h2时,可以横着放,把两块同时垫高。

    情形3:

         当h1和h2相邻,而且h1和h2相差偶数个高度时,先竖着垫到一样高,再横着同时垫高。

        于是,我产生的第一个想法就是,我可以把北湖划分为若干个列组,每个列组有一个或两个列,并且每个列组都是上述三种最简单的情形之一。

不过我很快找到了反例,例如

        如果按我刚刚的想法,那就被划分成了1,2,3,45,6,7,8,这个图是无解的。然而从图中我们很容易知道实际上是可以填平的,这个算法有极大的漏洞。

        但是观察上面的图,左边和右边奇偶性是一一对应的,这才让我们想到了使用栈。


        还记得我刚刚说到的情形中有提到:当相差偶数个时,可以填平。其实这道题也就是从这个角度切入的。

        我们建立一个栈,每次读入一个元素时。如果栈内为空,或者栈顶元素和该元素奇偶性不同,则入栈;如果栈顶元素和该元素奇偶性相同,则出栈。

        

        最后只要判断,如果栈内的元素个数小于等于1,则输出“YES”,否则输出“NO”。

这个方法还有个好处是只要扫描一次。 


三、代码实现

        这个思路一旦想到,寥寥几行就完事了。

//总共有n列
for (int i=0;i<n;i++) {
	
	scanf( "%d" , &h );
	if ( ( st.size()>0 ) && ( (h+st.top())%2==0 ) ) {
		st.pop();
	}
	else {
		st.push(h);
	}
}

//然后输出
if (st.size()<=1) 
    printf("YES\n");
else 
    printf("NO\n");	

四、完整代码

代码完全不难,采用扫描一次的方式也根本不可能超时,这就是栈(队列)的优点。

#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
const int N = 1e4+10;

int height[N];
struct Stack {
	int front = 0;
	void push( int h ) {
		if (front+1<N) height[front++] = h;
	}
	
	void pop() {
		if (front>0) front--;
	}
	
	int top() {
		if (front>0) return height[front-1];
	}
	
	int size() {
		return front;
	}
	
};

int main(){
	
	int n,h;
	while ( scanf("%d",&n) != EOF ) {
		
		Stack st;
		for (int i=0;i<n;i++) {
			
			scanf("%d",&h);
			if ( ( st.size()>0 ) && ( (h+st.top())%2==0 ) ) {
				st.pop();
			}
			else {
				st.push(h);
			}
		}
		if (st.size()<=1) printf("YES\n");
		else printf("NO\n");	
		
	}
	
	 
	return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值