这个学期开始学数据结构,第一节课老师又提出了这个经典的问题。

问题描述

给出一个只包含’(‘和’)‘的字符串,判断该字符串中的括号是否匹配。并将匹配的括号用’_‘代替,不匹配的括号用’$‘标出。 例如:

输入:
(())()))
输出:
(())()))
______$$

简单解法

括号匹配问题是刚开始学习C语言的时候就接触的问题,当时老师引入这个问题的原因可能是为了介绍栈的概念,但是当时班上大多数人都采取了直接用数组模拟的方法。把整个字符串录入,之后遍历整个字符串,遇到右括号就向前寻找是否存在对应的左括号,进行判断。C++代码如下:

#include<iostream>
#include<string>
using namespace std;
int main(){
    string str, tmp;    
    //tmp用于保留原来的字符串,为了方便直接用string输入
    cin >> str;
    tmp = str;
    for(int i = 0; i < str.length(); i++){
        if(str[i] == ')'){
            for(int j = i - 1; j >= 0; j--){
                if(str[j] == '('){
                    str[i] = str[j] = '_';
                    break;
                }
            }
        }
    }
    for(int i = 0; i < str.length(); i++){
        if(str[i] != '_')
            str[i] = '$';   //找出不匹配的括号
    }
    cout << tmp << endl << str;
    return 0;
}

使用栈来解决

首先忽略掉不匹配括号的标记问题,聚焦于判断整个字符串是否存在不匹配的括号。要看字符串是否匹配,只要看左括号是否有对应的右括号,或者右括号是否有对应的左括号,问题解决方法是相同的。

读入一个左括号我们就可以把它压入栈中,遇到右括号就弹出栈中的左括号。如果所有的右括号都读取完,栈中还有左括号,或者读入一个右括号栈中已经没有了括号,就意味着该字符串中的括号不匹配。C++代码:

#include<iostream>
#include<stack>
#include<string>
using namespace std;
int main(){
    stack<char> s;
    string tmp;
    cin >> tmp;
    for(int i = 0; i < tmp.length(); i++){
        if(tmp[i] == '(')
            s.push(tmp[i]);
        else
        {
            if(s.empty())
                cout << "FALSE";
            else
            {
                s.pop();
            }
            
        }
        
    }
    if(!s.empty())
        cout << "FALSE";
    else
    {
        cout << "TRUE";
    }
    return 0;
}

上面这段代码完全可以不用栈,设置一个变量来记录当前拥有的左括号的数量就可以大大简化代码。

如果我们想要知道是哪几个字符不匹配,我的想法是直接将字符的索引压入栈中,因为只有一种括号,把字符压入栈中实际上是不必要之举。将上面的代码输出错误的地方改成记录错误的下标,就可以将出错字符的下标记录下来,当所有的右括号都判断完之后,栈中剩余的所有左括号下标也同样要记录下来。