问题描述
问题来了: 如果可以通过在括号序列中插入字符 + 和 1 来获得正确的算术表达式,则该括号序列称为正则。例如,序列 (())(),() 和 (()(())) 是正则的,而 )(,(() 和 (()))( 不是。让我们称正则括号序列“RBS ”。
给定一个由 n 个字符 (,) 和/或 ? 组成的序列 s。在这个序列中只有一个字符(并且正好有一个字符)。
你必须替换每个字符?使用 ) 或 ( (不同的字符 ? 可以用不同的方括号替换)。您不能对字符重新排序、删除它们、插入其他字符,并且每个 ? 必须被替换。
确定在这些替换后是否有可能获得平衡序列。
例如:
5
()
(?)
(??)
??()
)?(?
输出:
YES
NO
YES
YES
NO
这是我的代码:
#include <bits/stdc++.h>
using namespace std;
bool checkValidString(string s) {
stack<char>st;
for(int i=0;i<s.length();i++)
{
if(!st.empty() && (((st.top() == '(') && s[i] == '?') || ((st.top() == '?') && s[i] == ')') || st.top() == '(' && s[i] == ')'))
{
st.pop();
}
else
{
st.push(s[i]);
}
}
if(st.empty())
{
return true;
}
int si = st.size();
bool odd = false;
if(si%2!=0)
{
odd = true;
}
while(!st.empty())
{
char c = st.top();
if(c!='?')
{
return false;
}
st.pop();
}
if(odd)
{
return false;
}
return true;
}
int main() {
// your code goes here
int n;
cin>>n;
while(n--)
{
string s;
cin>>s;
bool ans = checkValidString(s);
if(ans == 1)
{
cout<<"YES"<<endl;
}
else
{
cout<<"NO"<<endl;
}
}
return 0;
}
但是它给出了错误的答案,你能帮助我哪里出错吗?谢谢。
解决方法
检查有效括号的逻辑不会解决这种问题。
示例: input string = (?)?
的测试用例在您的情况下将失败。但它是一个有效的字符串,因为它可以采用 (())
的形式。
那么现在,您如何解决这样的问题?
让我们弄清楚所有可能的输入字符串是什么样的。
测试用例:
- 如果问号为奇数,则为无效字符串。
- 如果左括号出现在右括号之前,并且它们之间有奇数个问号:
(???)?
或 ?(???)
=> 两者都是有效的字符串,因为它们可以采用 ((()))
的形式。
- 如果左括号出现在右括号之前,并且它们之间有偶数个问号:
(????)
或 ??(??)??
=> 这些类型的字符串总是有效的。
- 如果左括号是右括号:
?)(?
=> 这个字符串也是有效的,因为它可以取自 ()()
。
- 我们唯一需要担心的是
)
是第一个位置还是(
位于最后一个位置:
)??(
=> 总是无效的字符串。
)?(?
=> 总是无效的字符串。
?)?(
=> 总是无效的字符串。
因此,问题简化为 3 个主要条件:
-
字符串的长度应该是偶数:要做到这一点,字符串中
?
字符的数量应该是偶数。 -
字符串不应以
)
开头。 -
字符串不应以
(
结尾。
查看以下在 Codeforces 上具有已接受状态的代码:
#include <iostream>
#include <string>
int main(){
int t;
scanf("%d",&t);
while(t--){
std::string s;
std::cin>>s;
int len = s.length();
int countQuestion = 0;
for(int i=0;i<len;i++){
if(s[i]=='?'){
countQuestion++;
}
}
//Check 1: If question count is even?
if(countQuestion & 1){
printf("NO\n");
}else{
if(s[0] == ')' || s[len-1] == '('){
printf("NO\n");
}else{
printf("YES\n");
}
}
}
return 0;
}
结论:
,如果您想检查一串括号以查看它是否有效,您可以在遍历字符串时保留一个开放括号计数器。您可以从 0 开始,每 (
增加一次,每 )
减少一次。您需要检查以确保它永远不会变为负数并且以 0 结尾。
如果一些括号被问号代替,你可以想象做同样的事情,但在每个位置你都可以计算计数器的所有可能的非负值。如果该组值变为空,则不可能出现有效的括号字符串。如果该集合不包含 0,则不可能出现有效的括号字符串。
事实证明(您可以通过归纳证明),可能值的集合总是包含两个数字 x 和 y 之间的每个 2nd 数字。
在 ?,[x,y] -> [x-1,y+1] 之后,不包括数字
之后 (,y] -> [x+1,y+1]
之后),y-1],不包括数字
因此您可以通过遍历字符串来测试任何括号和问号序列,从 [0,0] 开始并根据上述每个字符的规则修改范围。确保它永远不会变空并在末尾包含 0。
bool checkValidString(string s) {
int l=0,h=0;
for(int i=0;i<s.length();i++) {
switch(s[i]) {
case '(':
++l;++h;
break;
case ')':
if (h<=0) {
return false;
}
--h;
l += (l>0 ? -1:1);
break;
default:
++h;
l += (l>0 ? -1:1);
break;
}
}
return l==0;
}