传送门:点击打开链接
题意:给一字符串只有括号,问最长合法子串的长度是多少,并输出这样的长度的子串有多少个。
思路:啊。。我发现这种括号配对的题我总是处理不好。
一开始想到了一种比较脑残的方法,首先(代表+1,)代表-1,我们维护前缀和s,然后我们用单调栈来维护最左端的满足[x,i]所有前缀和都>=s。
然后,我们并不能一直扩展到最左边,我们还应该记录前缀和等于s且后一个字符是(的位置。因为我们对于一个),向左匹配最多也只能匹配到这个位置。
于是,就有了下面这段傻逼代码
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <bitset>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
#define fuck(x) cout<<"["<<x<<"]";
#define FIN freopen("input.txt","r",stdin);
#define FOUT freopen("output.txt","w+",stdout);
//#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef long long LL;
const int MX = 1e6 + 5;
const int MID = MX;
char S[MX];
int pos[2 * MX];
int Stack[MX], z[MX], ssz;
int main() {
//FIN;
scanf("%s", S + 1);
int n = strlen(S + 1), now = 0;
memset(pos, -1, sizeof(pos));
Stack[++ssz] = 0; z[ssz] = 0;
int maxlen = 0, cnt = 1;
for(int i = 1; i <= n; i++) {
if(S[i] == '(') now++;
else now--;
int p = i;
while(ssz && now <= Stack[ssz]) p = z[ssz--];
Stack[++ssz] = now; z[ssz] = p;
if(S[i] == ')' && pos[now + MID] != -1) {
int len = i - max(pos[now + MID], p);
if(len > maxlen) {
maxlen = len; cnt = 1;
} else if(len == maxlen) cnt++;
} else if(S[i] == '(' && pos[now + MID - 1] == -1) {
pos[now + MID - 1] = i - 1;
}
}
printf("%d %d\n", maxlen, cnt);
return 0;
}
然后看了一下排行榜里别人的做法,实在是太简单易懂了~
我们来使用栈来匹配括号。如果为(,就压入栈。如果为),就取出栈顶,此时,从当前的位置,到栈顶表示的(的位置,这整个子串,一定是合法的。
然后如果在(的前面也有一段合法括号,那么两段就能合在一起,形成更长的。
所以代码非常简单,一个普通的栈,再加一个dp数组记录一下就ok了
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <bitset>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
#define fuck(x) cout<<"["<<x<<"]";
#define FIN freopen("input.txt","r",stdin);
#define FOUT freopen("output.txt","w+",stdout);
//#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef long long LL;
const int MX = 1e6 + 5;
char S[MX];
int Stack[MX], dp[MX], ssz;
int main() {
//FIN;
scanf("%s", S + 1);
int n = strlen(S + 1);
int maxlen = 0, cnt = 1;
for(int i = 1; i <= n; i++) {
if(S[i] == '(') Stack[++ssz] = i;
else if(ssz) {
int t = Stack[ssz--];
dp[i] = dp[t - 1] + i - t + 1;
if(dp[i] > maxlen) maxlen = dp[i], cnt = 1;
else if(dp[i] == maxlen) cnt++;
}
}
printf("%d %d\n", maxlen, cnt);
return 0;
}
啊,,下次再不会做括号匹配的题就药丸了