某日,小明特别无聊,就想找点东西玩,于是他发现括号()特别好玩,而且新学会了一项技能,
将一对小括号(),插入到一个括号序列中,其中插入的规则是,左括号'('的位置要小于右括号')'的位置,不要求插入的左右括号相邻,
例如以下,为了方便区分,我们拿ab代表原括号序列
将()插入到()中可形成()ab (a)b (ab) a()b a(b) ab()等等序列,其中a代表原括号序列的左括号,b代表原括号序列的右括号。
小明认为一个括号序列是一个优美的序列当且仅当这个括号序列可以被如下方法构造出来:
一开始有一个空串,然后执行0次或者若干次操作,每次操作将()插入到当前的括号序列中。
根据上面的定义:() , (()) , (()())都是优美的括号序列,(() , )( , ()))都不是优美的括号序列
输入格式:
多组输入
每行输入给定一个仅由'(',')'组成的括号序列,长度小于等于1000
题目保证没有空串
输出格式:
对于每个输入输出一行,若当前的括号序列是优美的,则输出"YES"(不含引号)
否则输出"NO"(不含引号)
输入样例:
()
(())
(()())
()()
(()
)(
()))
输出样例:
YES
YES
YES
YES
NO
NO
NO
思路:
我们首先要知道什么叫做优美的括号序列
- 左括号数量=右括号数量
- 当输入一个括号,如果是右括号,一定有左括号与之匹配
所以我们每次迭代的时候:
- 如果是左括号,就将左括号依次压入栈中;
- 如果是右括号,就看看栈顶还有没有左括号
- 如果没有左括号了,就说明这个右括号不能匹配上了
- 如果还有左括号,就给他用掉,将一个左括号出栈。
- 最后,看看栈中还有没有左括号没有被领走的,如果有的话就不是优美的括号序列了。
参考代码:
#include<bits/stdc++.h>
using namespace std;
int main() {
string line;
while(cin>>line) {
stack<char> st;
bool perfect = true;
for(auto ch:line) {
if(ch == '(') {
st.push(ch);
} else if(ch == ')') {
if(st.empty()) {
perfect = false;
break;
} else {
st.pop();
}
}
}
if(perfect) perfect=st.empty();
cout<<(perfect?"YES":"NO")<<endl;
}
return 0;
}
精益求精:
- 注意我们在迭代的过程中,栈内元素的取值是不是不需要考虑的?我们只在乎到底还有多少个左括号没有被匹配上,那么我们只需要定义一个变量cnt来记录当前还未匹配掉的左括号数量。因此,如果遇到左括号,就将cnt自增;如果遇到右括号,就看还有没有左括号可以和他匹配,如果cnt此时是小于等于0的,就说明这个右括号被孤立了。
- 如果字符串长度是奇数,那么一定有一个括号不是成双成对的,所以直接特判即可。
参考代码:
#include<bits/stdc++.h>
using namespace std;
int main() {
string line;
while(cin>>line) {
if(line.size()%2) {
cout<<"NO"<<endl;
continue;
}
int cnt = 0;
bool perfect= true;
for(char ch:line) {
if(ch == '(') cnt++;
else if(cnt <= 0) {
perfect = false;
break;
} else {
cnt--;
}
}
if(perfect && cnt != 0) {
perfect = false;
}
cout<<(perfect?"YES":"NO")<<endl;
}
return 0;
}
举一反三:
此题是很经典的栈入门题,可以试着做一下力扣这道题https://leetcode-cn.com/problems/valid-parentheses/
另外力扣有很多针对性的分栏,比如数据结构有堆、栈、树、图等,算法有贪心、回溯、二分、动归等,可以针对性地训练一下较为薄弱的地方。