跳转至

洛谷-P1944 最长括号匹配(字符串动态规划)

题目描述

对一个由(,),[,]括号组成的字符串,求出其中最长的括号匹配子串。具体来说,满足如下条件的字符串成为括号匹配的字符串:

1.(),[]是括号匹配的字符串。

2.若A是括号匹配的串,则(A),[A]是括号匹配的字符串。

3.若A,B是括号匹配的字符串,则AB也是括号匹配的字符串。

例如:(),[],([]),()()都是括号匹配的字符串,而][,[(])则不是。

字符串A的子串是指由A中连续若干个字符组成的字符串。

例如,A,B,C,ABC,CAB,ABCABCd都是ABCABC的子串。空串是任何字符串的子串。

输入格式

输入一行,为一个仅由()[]组成的非空字符串。

输出格式

输出也仅有一行,为最长的括号匹配子串。若有相同长度的子串,输出位置靠前的子串。

输入输出样例

输入 #1

([(][()]]()

输出 #1

[()]

输入 #2

())[]

输出 #2

()

说明/提示

【数据范围】

对20%的数据,字符串长度<=100.

对50%的数据,字符串长度<=10000.

对100%的数据,字符串长度<=1000000.


#include <iostream>
#include <iomanip>
#include <vector>
#include <cmath>
#include <string>
#include <climits>
#include <cstdio>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <algorithm>

using namespace std;

int main()
{
    std::ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    string s; cin >> s;
    int n = s.size();
    vector<int> d(n, 0);
    int res = 0, pos = 0;
    for (int i = 1; i < n; ++i) {
        if ( i > d[i - 1] && ((s[i] == ')' && s[i - 1 - d[i - 1]] == '(') 
            || (s[i] == ']' && s[i - 1 - d[i - 1]] == '[')) ) {
            d[i] = d[i - 1] + 2 + (i >= 2 + d[i - 1 ] ? d[i - 2 - d[i - 1]] : 0);
            if (d[i] > res) {
                res = d[i];
                pos = i;
            }
        }
    }
    cout << (pos - res + 1 >= 0 ? s.substr(pos - res + 1, res) : "") << endl;

    return 0;
}

这道题是LeetCode 32的扩展,用d[i]表示以s[i]为结尾的最长有效括号长度,那么d[i - 1]表示以s[i-1]结尾的最长有效括号长度,那么如果和s[i - 2 - d[i - 1]]匹配,那么就可以更新长度,另外需要考虑涉及下标的时候,要保证下标在合理的范围内。