1. 程式人生 > 實用技巧 >LeetCode刷題日記 2020/8/28

LeetCode刷題日記 2020/8/28

題目描述:

最長有效括號

給定一個只包含 '(' 和 ')' 的字串,找出最長的包含有效括號的子串的長度。

示例 1:

輸入: "(()"
輸出: 2
解釋: 最長有效括號子串為 "()"


示例 2:

輸入: ")()())"
輸出: 4
解釋: 最長有效括號子串為 "()()"

來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/longest-valid-parentheses


解題思路一: 棧

通過棧,我們可以在遍歷給定字串的過程中去判斷到目前為止掃描的子串的有效性,同時能得到最長有效括號的長度。

具體做法是我們始終保持棧底元素為當前已經遍歷過的元素中「最後一個沒有被匹配的右括號的下標」,這樣的做法主要是考慮了邊界條件的處理,棧裡其他元素維護左括號的下標:

對於遇到的每個’(’ ,我們將它的下標放入棧中
對於遇到的每個 ‘)’ ,我們先彈出棧頂元素表示匹配了當前右括號:
如果棧為空,說明當前的右括號為沒有被匹配的右括號,我們將其下標放入棧中來更新我們之前提到的「最後一個沒有被匹配的右括號的下標」
如果棧不為空,當前右括號的下標減去棧頂元素即為「以該右括號為結尾的最長有效括號的長度」
我們從前往後遍歷字串並更新答案即可。

需要注意的是,如果一開始棧為空,第一個字元為左括號的時候我們會將其放入棧中,這樣就不滿足提及的「最後一個沒有被匹配的右括號的下標」,為了保持統一,我們在一開始的時候往棧中放入一個值為 -1 的元素。


程式碼

public class
Solution { public int longestValidParentheses(String s) { int maxans = 0; Stack<Integer> stack = new Stack<>(); stack.push(-1); for (int i = 0; i < s.length(); i++) { if (s.charAt(i) == '(') { stack.push(i); } else
{ stack.pop(); if (stack.empty()) { stack.push(i); } else { maxans = Math.max(maxans, i - stack.peek()); } } } return maxans; } }



思路二: 正向逆向結合法

官方給出的這個解法太巧妙了 佩服!

在此方法中,我們利用兩個計數器left 和 right 。首先,我們從左到右遍歷字串,對於遇到的每個‘(’,我們增加left 計數器,對於遇到的每個 ‘)’ ,我們增加right 計數器。每當 left 計數器與right 計數器相等時,我們計算當前有效字串的長度,並且記錄目前為止找到的最長子字串。當right 計數器比 left 計數器大時,我們將 left 和 right 計數器同時變回 00。

這樣的做法貪心地考慮了以當前字元下標結尾的有效括號長度,每次當右括號數量多於左括號數量的時候之前的字元我們都扔掉不再考慮,重新從下一個字元開始計算,但這樣會漏掉一種情況,就是遍歷的時候左括號的數量始終大於右括號的數量,即 (() ,這種時候最長有效括號是求不出來的。

解決的方法也很簡單,我們只需要從右往左遍歷用類似的方法計算即可,只是這個時候判斷條件反了過來:

當 left 計數器比right 計數器大時,我們將left 和 right 計數器同時變回 0
當left 計數器與right 計數器相等時,我們計算當前有效字串的長度,並且記錄目前為止找到的最長子字串
這樣我們就能涵蓋所有情況從而求解出答案。


程式碼:

public class Solution {
    public int longestValidParentheses(String s) {
        int left = 0, right = 0, maxlength = 0;
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '(') {
                left++;
            } else {
                right++;
            }
            if (left == right) {
                maxlength = Math.max(maxlength, 2 * right);
            } else if (right > left) {
                left = right = 0;
            }
        }
        left = right = 0;
        for (int i = s.length() - 1; i >= 0; i--) {
            if (s.charAt(i) == '(') {
                left++;
            } else {
                right++;
            }
            if (left == right) {
                maxlength = Math.max(maxlength, 2 * left);
            } else if (left > right) {
                left = right = 0;
            }
        }
        return maxlength;
    }
}