32.Longest Valid Parentheses---dp

題目連接:https://leetcode.com/problems/longest-valid-parentheses/description/
ide

題目大意:找出最長的括號匹配的子串長度。例子:"(()("長度是2;"()()(())"長度是8spa

解法一:利用三層for循環,逐一的找每個子串,並判斷每個子串是不是括號匹配的。很遺憾,超時了。代碼以下:code

 1     public int longestValidParentheses(String s) {
 2         int res = 0;
 3         for(int i = 0; i < s.length(); i++) {//逐一查看每個子串
 4             for(int j = i + 2; j <= s.length(); j += 2) {
 5                 int cnt = parentheses(s.substring(i, j));
 6                 if(res < cnt) {
 7                     res = cnt;
 8                 }
 9             }
10         }
11         return res;
12     }
13     //判斷是不是括號匹配的
14     public static int parentheses(String s) {
15         Stack<Character> st = new Stack<Character>();
16         int cnt = 0;
17         for(int i = 0; i < s.length(); i++) {
18             char c = s.charAt(i);
19             if(c == ')') {
20                 if(!st.isEmpty() && st.peek() == '(') {
21                     cnt++;
22                     st.pop();
23                 }
24                 else {
25                     return 0;
26                 }
27             }
28             else {
29                 st.push(c);
30             }
31         }
32         if(!st.isEmpty()) {
33             return 0;
34         }
35         return cnt * 2;
36     }
View Code

 解法二(借鑑):用棧存儲左括號下標,而不是'('左括號。若是是'(',則將下標壓棧。若是是')',則查看棧的狀況,若是棧空,則記錄下一個子串開始的位置下標(即i+1);若是非空,則查看棧中元素狀況,若是隻有一個'(',則彈出計數子串長度,若是有多個'(',則計數到目前爲止的匹配的子串長度狀況。或者同時壓棧存儲左括號和右括號下標,當遇到')',則查看棧頂元素,若是是'(',則計數,不然壓棧。這兩種方法都是o(n)的時間複雜度。代碼以下(耗時26ms):blog

第一種壓棧左括號下標的方法:ip

 1 public int longestValidParentheses(String s) {
 2         Stack<Integer> st = new Stack<Integer>();//存'('下標
 3         int res = 0, lastIndex = 0, length = s.length();
 4         for(int i = 0; i < length; i++) {
 5             char c = s.charAt(i);
 6             if(c == '(') {//若是是'(',將下標壓棧
 7                 st.push(i);
 8             }
 9             else {//若是是')',分狀況討論
10                 if(st.isEmpty()) {//若是爲空,則出現')'沒有'('匹配的狀況,則當前子串結束,下一個子串的開始位置便是當前子串結束的下一個位置
11                     lastIndex = i + 1;
12                 }
13                 else {//若是非空,可能出現兩種狀況:'()'或'(())'
14                     st.pop();
15                     if(st.isEmpty()) {//若是爲空,則說明棧中沒有'('須要匹配
16                         res = Math.max(res, i - lastIndex + 1);
17                     }
18                     else {//若是非空,則當前棧中還有'('存在
19                         res = Math.max(res, i - st.peek());
20                     }
21                 }
22             }
23         }
24         return res;
25     }
View Code

第二種壓棧左括號和右括號下標的方法(基本與上面第一種同樣):leetcode

 1     public int longestValidParentheses(String s) {
 2         Stack<Integer> st = new Stack<Integer>();
 3         int res = 0, length = s.length();
 4         for(int i = 0; i < length; i++) {
 5             if(s.charAt(i) == '(') {//左括號壓棧下標
 6                 st.push(i);
 7             }
 8             else {//遇到右括號
 9                 if(st.isEmpty()) {//若是棧空,則壓棧右括號下標
10                     st.push(i);
11                 }
12                 else {
13                     if(s.charAt(st.peek())== '(') {//若是棧頂元素是左括號,則匹配,退棧計數子串長度
14                         st.pop();
15                         res = Math.max(res, (i - (st.isEmpty() ? -1 : st.peek())));
16                     }
17                     else {//若是棧頂元素是右括號,則壓棧右括號下標
18                         st.push(i);
19                     }
20                 }
21             }
22         }
23         return res;
24     }
View Code

解法三:利用dp。首先dp[i] 表示從s[i]往前推最長能匹配的子串,換句話說,就是到s[i]爲止的最長匹配子串後綴。那麼當對於下面幾種狀況進行分析:get

1. s[i] ==’(’     s[i]爲左括號,dp[i]=0這個很好理解。
2. s[i] ==’)’  這就要分狀況了
  a) 若是s[i-1]是’(’說明已經完成了一次匹配,子串長度爲2,可是還要加上dp[i-2]的大小,也就是當前匹配的這對括號前面的最長匹配長度,它們是相連的。
  b) 若是s[i-1]是’)’這樣不能匹配,則須要考慮s[i-1-dp[i-1]]的狀況了,若是s[i-1-dp[i-1]]是一個左括號,則與當前右括號匹配,那麼此時咱們令dp[i]=dp[i-1]+2,這個2就是剛剛匹配的左右括號。最後還要把dp[i-2-dp[i-1]](即與當前括號')'匹配的'('前面一個位置的dp長度,它們是相連的)值加起來,把相連的最大長度求出來。代碼以下(耗時20ms):string

 1     public int longestValidParentheses(String s) {
 2         int length = s.length();
 3         int[] dp = new int[length];
 4         int res = 0;
 5         for(int i = 0; i < length; i++) {
 6             dp[i] = 0;
 7             if(s.charAt(i) == ')' && (i - 1) >= 0) {
 8                 if((i - 1) >= 0 && s.charAt(i - 1) == '(') {//若是前一個位置與當前括號')'匹配
 9                     dp[i] = 2;//暫且只計算匹配的'('')'
10                     if(i - 2 >= 0) {//加上與')'匹配的'('前一個位置的dp匹配長度
11                         dp[i] += dp[i - 2];
12                     }
13                 }
14                 else {//若是前一個位置與當前括號'('不匹配
15                     if((i - 1 - dp[i - 1]) >= 0 && s.charAt(i - 1 - dp[i - 1]) == '(') {//查看【前一個位置下標-匹配數】以後的字符與當前括號')'是否匹配
16                         dp[i] = dp[i - 1] + 2;//若是匹配,則在前一個位置匹配數的狀況下+2,即加上剛與當前')'匹配的左右括號數量
17                         if(i - 2 - dp[i - 1] >= 0) {//加上與')'匹配的'('前一個位置的dp匹配長度
18                             dp[i] += dp[i - 2 - dp[i - 1]];
19                         }
20                     }
21                 }
22             }
23             res = Math.max(res, dp[i]);
24         }
25         return res;
26     }
View Code
相關文章
相關標籤/搜索