1. 程式人生 > >棧+括號配對 51Nod1478 括號序列的最長合法子段

棧+括號配對 51Nod1478 括號序列的最長合法子段

題意:給一字串只有括號,問最長合法子串的長度是多少,並輸出這樣的長度的子串有多少個。

思路:啊。。我發現這種括號配對的題我總是處理不好。

一開始想到了一種比較腦殘的方法,首先(代表+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;
}
啊,,下次再不會做括號匹配的題就藥丸了