Loading

P1944 最长括号匹配(DP/贪心/括号匹配)

题目描述

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

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

感觉和dp没有什么关系。设id[i]表示以s[i]结尾的括号串的最长长度,当id[i - 1]存在的时候需要判断s[i - id[i - 1] - 1]是否能够和s[i]匹配,若能则令id[i] = id[i - 1] + 2;此时如果id[i - id[i]]存在的话说明可以两个括号串拼起来,则id[i] += id[i - id[i]];同时更新mxlen。当id[i - 1]不存在的时候先判断s[i - 1]能否和s[i]匹配,若能则令id[i] = 2。此时需要继续判断id[i - 2]是否存在,如果存在说明仍然可以两个括号串拼成一个大的扩号串,则令id[i] += id[i - 2];mxlen = max(mxlen, id[i]);

注意对于()()()这样的是没有问题的因为id[3]在更新完后已经等于4了,此时就能顺利的更新id[5]了。

#include <iostream>
using namespace std;
string s;
int mxlen, id[1000005];
int main(){
	cin >> s;
	for(int i = 0; i < s.size(); i++) {
		if(i == 0) continue;
		else if(i == 1) {
			if(s[0] == '(' && s[1] == ')' || s[0] == '[' && s[1] == ']') id[1] = 2;
			mxlen = max(mxlen, id[1]);
		} else {
			if(id[i - 1]) {
				if(s[i - id[i - 1] - 1] == '(' && s[i] == ')' || s[i - id[i - 1] - 1] == '[' && s[i] == ']') {
					id[i] = id[i - 1] + 2;
					mxlen = max(mxlen, id[i]);
				}
				if(id[i] && id[i - id[i]]) {
					id[i] += id[i - id[i]];
					mxlen = max(mxlen, id[i]);
				}
			} else {
				if(s[i - 1] == '(' && s[i] == ')' || s[i - 1] == '[' && s[i] == ']') id[i] = 2;
				mxlen = max(mxlen, id[i]);
				if(id[i] == 2 && id[i - 2]) {
					id[i] += id[i - 2];
					mxlen = max(mxlen, id[i]);
				}
			}
		}
	}
	for(int i = 0; i < s.size(); i++) {
		if(id[i] == mxlen) {
			for(int j = i - mxlen + 1; j <= i; j++) cout << s[j];
			break;
		}
	}
	return 0;
} 
//()()([]()]][()(())])
posted @ 2021-04-24 10:24  脂环  阅读(162)  评论(0编辑  收藏  举报