C++實(shí)現(xiàn)LeetCode(32.最長(zhǎng)有效括號(hào))
[LeetCode] 32. Longest Valid Parentheses 最長(zhǎng)有效括號(hào)
Given a string containing just the characters '(' and ')', find the length of the longest valid (well-formed) parentheses substring.
Example 1:
Input: "(()"
Output: 2
Explanation: The longest valid parentheses substring is "()"
Example 2:
Input: ")()())"
Output: 4
Explanation: The longest valid parentheses substring is "()()"
這道求最長(zhǎng)有效括號(hào)比之前那道 Valid Parentheses 難度要大一些,這里還是借助棧來(lái)求解,需要定義個(gè) start 變量來(lái)記錄合法括號(hào)串的起始位置,遍歷字符串,如果遇到左括號(hào),則將當(dāng)前下標(biāo)壓入棧,如果遇到右括號(hào),如果當(dāng)前棧為空,則將下一個(gè)坐標(biāo)位置記錄到 start,如果棧不為空,則將棧頂元素取出,此時(shí)若棧為空,則更新結(jié)果和 i - start + 1 中的較大值,否則更新結(jié)果和 i - st.top() 中的較大值,參見(jiàn)代碼如下:
解法一:
class Solution {
public:
int longestValidParentheses(string s) {
int res = 0, start = 0, n = s.size();
stack<int> st;
for (int i = 0; i < n; ++i) {
if (s[i] == '(') st.push(i);
else if (s[i] == ')') {
if (st.empty()) start = i + 1;
else {
st.pop();
res = st.empty() ? max(res, i - start + 1) : max(res, i - st.top());
}
}
}
return res;
}
};
還有一種利用動(dòng)態(tài)規(guī)劃 Dynamic Programming 的解法。這里使用一個(gè)一維 dp 數(shù)組,其中 dp[i] 表示以 s[i-1] 結(jié)尾的最長(zhǎng)有效括號(hào)長(zhǎng)度(注意這里沒(méi)有對(duì)應(yīng) s[i],是為了避免取 dp[i-1] 時(shí)越界從而讓 dp 數(shù)組的長(zhǎng)度加了1),s[i-1] 此時(shí)必須是有效括號(hào)的一部分,那么只要 dp[i] 為正數(shù)的話,說(shuō)明 s[i-1] 一定是右括號(hào),因?yàn)橛行Юㄌ?hào)必須是閉合的。當(dāng)括號(hào)有重合時(shí),比如 "(())",會(huì)出現(xiàn)多個(gè)右括號(hào)相連,此時(shí)更新最外邊的右括號(hào)的 dp[i] 時(shí)是需要前一個(gè)右括號(hào)的值 dp[i-1],因?yàn)榧偃?dp[i-1] 為正數(shù),說(shuō)明此位置往前 dp[i-1] 個(gè)字符組成的子串都是合法的子串,需要再看前面一個(gè)位置,假如是左括號(hào),說(shuō)明在 dp[i-1] 的基礎(chǔ)上又增加了一個(gè)合法的括號(hào),所以長(zhǎng)度加上2。但此時(shí)還可能出現(xiàn)的情況是,前面的左括號(hào)前面還有合法括號(hào),比如 "()(())",此時(shí)更新最后面的右括號(hào)的時(shí)候,知道第二個(gè)右括號(hào)的 dp 值是2,那么最后一個(gè)右括號(hào)的 dp 值不僅是第二個(gè)括號(hào)的 dp 值再加2,還可以連到第一個(gè)右括號(hào)的 dp 值,整個(gè)最長(zhǎng)的有效括號(hào)長(zhǎng)度是6。所以在更新當(dāng)前右括號(hào)的 dp 值時(shí),首先要計(jì)算出第一個(gè)右括號(hào)的位置,通過(guò) i-3-dp[i-1] 來(lái)獲得,由于這里定義的 dp[i] 對(duì)應(yīng)的是字符 s[i-1],所以需要再加1,變成 j = i-2-dp[i-1],這樣若當(dāng)前字符 s[i-1] 是左括號(hào),或者j小于0(說(shuō)明沒(méi)有對(duì)應(yīng)的左括號(hào)),或者 s[j] 是右括號(hào),此時(shí)將 dp[i] 重置為0,否則就用 dp[i-1] + 2 + dp[j] 來(lái)更新 dp[i]。這里由于進(jìn)行了 padding,可能對(duì)應(yīng)關(guān)系會(huì)比較暈,大家可以自行帶個(gè)例子一步一步執(zhí)行,應(yīng)該是不難理解的,參見(jiàn)代碼如下:
解法二:
class Solution {
public:
int longestValidParentheses(string s) {
int res = 0, n = s.size();
vector<int> dp(n + 1);
for (int i = 1; i <= n; ++i) {
int j = i - 2 - dp[i - 1];
if (s[i - 1] == '(' || j < 0 || s[j] == ')') {
dp[i] = 0;
} else {
dp[i] = dp[i - 1] + 2 + dp[j];
res = max(res, dp[i]);
}
}
return res;
}
};
此題還有一種不用額外空間的解法,使用了兩個(gè)變量 left 和 right,分別用來(lái)記錄到當(dāng)前位置時(shí)左括號(hào)和右括號(hào)的出現(xiàn)次數(shù),當(dāng)遇到左括號(hào)時(shí),left 自增1,右括號(hào)時(shí) right 自增1。對(duì)于最長(zhǎng)有效的括號(hào)的子串,一定是左括號(hào)等于右括號(hào)的情況,此時(shí)就可以更新結(jié)果 res 了,一旦右括號(hào)數(shù)量超過(guò)左括號(hào)數(shù)量了,說(shuō)明當(dāng)前位置不能組成合法括號(hào)子串,left 和 right 重置為0。但是對(duì)于這種情況 "(()" 時(shí),在遍歷結(jié)束時(shí)左右子括號(hào)數(shù)都不相等,此時(shí)沒(méi)法更新結(jié)果 res,但其實(shí)正確答案是2,怎么處理這種情況呢?答案是再反向遍歷一遍,采取類似的機(jī)制,稍有不同的是此時(shí)若 left 大于 right 了,則重置0,這樣就可以 cover 所有的情況了,參見(jiàn)代碼如下:
解法三:
class Solution {
public:
int longestValidParentheses(string s) {
int res = 0, left = 0, right = 0, n = s.size();
for (int i = 0; i < n; ++i) {
(s[i] == '(') ? ++left : ++right;
if (left == right) res = max(res, 2 * right);
else if (right > left) left = right = 0;
}
left = right = 0;
for (int i = n - 1; i >= 0; --i) {
(s[i] == '(') ? ++left : ++right;
if (left == right) res = max(res, 2 * left);
else if (left > right) left = right = 0;
}
return res;
}
};
到此這篇關(guān)于C++實(shí)現(xiàn)LeetCode(32.最長(zhǎng)有效括號(hào))的文章就介紹到這了,更多相關(guān)C++實(shí)現(xiàn)最長(zhǎng)有效括號(hào)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C++實(shí)現(xiàn)LeetCode(37.求解數(shù)獨(dú))
- C++實(shí)現(xiàn)LeetCode(36.驗(yàn)證數(shù)獨(dú))
- C++實(shí)現(xiàn)LeetCode(35.搜索插入位置)
- C++實(shí)現(xiàn)LeetCode(34.在有序數(shù)組中查找元素的第一個(gè)和最后一個(gè)位置)
- C++實(shí)現(xiàn)LeetCode(33.在旋轉(zhuǎn)有序數(shù)組中搜索)
- C++實(shí)現(xiàn)LeetCode(31.下一個(gè)排列)
- C++實(shí)現(xiàn)LeetCode(51.N皇后問(wèn)題)
相關(guān)文章
關(guān)于移位操作的一點(diǎn)重要說(shuō)明
下面小編就為大家?guī)?lái)一篇關(guān)于移位操作的一點(diǎn)重要說(shuō)明。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-12-12
C++實(shí)現(xiàn)將一個(gè)字符串中的字符替換成另一個(gè)字符串的方法
這篇文章主要介紹了C++實(shí)現(xiàn)將一個(gè)字符串中的字符替換成另一個(gè)字符串的方法,需要考慮的情況比較全面,有不錯(cuò)的借鑒價(jià)值,需要的朋友可以參考下2014-09-09
C++實(shí)現(xiàn)順序排序算法簡(jiǎn)單示例代碼
這篇文章主要介紹了C++實(shí)現(xiàn)順序排序算法簡(jiǎn)單示例代碼,對(duì)于學(xué)過(guò)C++的朋友一定不會(huì)陌生,現(xiàn)在重溫一下這個(gè)算法,需要的朋友可以參考下2014-08-08
VS2010+Opencv+MFC讀取圖像和視頻顯示在Picture控件
這篇文章主要為大家詳細(xì)介紹了VS2010+Opencv+MFC讀取圖像和視頻顯示在Picture控件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-08-08
深入解析C語(yǔ)言中的內(nèi)存分配相關(guān)問(wèn)題
這篇文章主要深入地介紹了C語(yǔ)言中的內(nèi)存分配,C語(yǔ)言編程中的內(nèi)存泄漏問(wèn)題一直以來(lái)都是C編程中的一大棘手問(wèn)題,本文從malloc和指針等方面對(duì)C內(nèi)存進(jìn)行了深層次講解,強(qiáng)烈推薦!需要的朋友可以參考下2015-08-08
C++實(shí)現(xiàn)Dijkstra(迪杰斯特拉)算法
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)Dijkstra(迪杰斯特拉)算法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05

