最長合法括號子序列


最長合法括號子序列

一個合法的括號序列滿足以下條件:

  1. 序列()被認為是合法的。
  2. 如果序列XY是合法的,則XY也被認為是合法的。
  3. 如果序列X是合法的,則(X)也是合法的。

例如, () , ()() , (()) 這些都是合法的。

現在,給定一個由  (  和  )  組成的字符串。

請你求出其中的最長合法括號子序列的長度。

注意,子序列不一定連續。

輸入格式

共一行,一個由  (  和  )  組成的字符串。

輸出格式

一個整數,表示最長合法括號子序列的長度。

數據范圍

前五個測試點滿足,$1 \leq \text{輸入字符串的長度} \leq 10$。

所有測試點滿足,$1 \leq \text{輸入字符串的長度} \leq {10}^{6}$。

輸入樣例1:

(()))(

輸出樣例1:

4

輸入樣例2:

()()(()(((

輸出樣例2:

6

 

解題思路

  這是一個括號序列的問題。對於一個合法的括號序列,有兩個結論:

  1. 整個序列的左右括號數量相等。
  2. 任意一個前綴中,左括號的數量大於等於右括號的數量。

  對於這兩個條件,一般用一個計數器來實現。一開始$cnt = 0$,遇到左括號就$cnt++$,遇到右括號就$cnt--$。等價於在上面的第$1$個條件中,最后的$cnt = 0$;第$2$個條件中,整一個操作的過程$cnt$都始終滿足$cnt \geq 0$。

  一個合法括號序列最長,等價於右括號數量最多(因為左右括號數量相同),因此我們只需要找到一個合法括號序列,使得右括號的數量最多就可以了。

  貪心的思想是,對於右括號,能選則選。如果在遍歷的過程中遇到右括號,且$cnt > 0$,就選這個右括號。下面證明一下這種做法是正確的。

  首先有貪心解$\leq$最優解,因為貪心解是合法解,最優解是合法解中最大的那一個,因此貪心解$\leq$最優解。

  下面證明貪心解$\geq$最優解。反證法,假設有最優解$>$貪心解。

  因此可以證明得到貪心解$\leq$最優解,貪心解$\geq$最優解,即可以證明貪心解$=$最優解。

  AC代碼如下:

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 
 5 const int N = 1e6 + 10;
 6 
 7 char str[N];
 8 
 9 int main() {
10     scanf("%s", str);
11     
12     int l = 0, r = 0;
13     for (int i = 0; str[i]; i++) {
14         if (str[i] == '(') l++;
15         else if (l > 0) l--, r++;
16     }
17     
18     printf("%d", r << 1);
19     
20     return 0;
21 }

 

參考資料

  AcWing 4207. 最長合法括號子序列(AcWing杯 - 周賽):https://www.acwing.com/video/3660/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM