微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

基于堆栈的平衡括号问题

如何解决基于堆栈的平衡括号问题

问题来了: 如果可以通过在括号序列中插入字符 + 和 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 = (?)? 的测试用例在您的情况下将失败。但它是一个有效的字符串,因为它可以采用 (()) 的形式。

那么现在,您如何解决这样的问题?

让我们弄清楚所有可能的输入字符串是什么样的。

测试用例:

  1. 如果问号为奇数,则为无效字符串。
  2. 如果左括号出现在右括号之前,并且它们之间有奇数个问号:

(???)??(???) => 两者都是有效的字符串,因为它们可以采用 ((())) 的形式。

  1. 如果左括号出现在右括号之前,并且它们之间有偶数个问号:

(????)??(??)?? => 这些类型的字符串总是有效的。

  1. 如果左括号是右括号:

?)(? => 这个字符串也是有效的,因为它可以取自 ()()

  1. 我们唯一需要担心的是 ) 是第一个位置还是 ( 位于最后一个位置:

)??( => 总是无效的字符串。

)?(? => 总是无效的字符串。

?)?( => 总是无效的字符串。

因此,问题简化为 3 个主要条件:

  1. 字符串的长度应该是偶数:要做到这一点,字符串中 ? 字符的数量应该是偶数。

  2. 字符串不应以 ) 开头。

  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;
}

结论:

enter image description here

,

如果您想检查一串括号以查看它是否有效,您可以在遍历字符串时保留一个开放括号计数器。您可以从 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;
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。