30. Substring with Concatenation of All Words
題目來源:https://leetcode.com/problems/substring-with-concatenation-of-all-words/description/
思路
本道題的思路是滑動窗口,一個窗口windows在字符串S上滑動,每一個位置都檢驗窗口的內容是否滿足條件,如果滿足,則記錄這個窗口的開始位置。
而對於windows內是否滿足的判定又有技巧。因爲我們不要求次序,而只要出現過。因而可以用unordered_map記錄每個word出現的次數。這樣就不需要雙重循環來判斷,判定的複雜度降到低過O(n^2)
參考代碼
來自本題目的discussion。
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
unordered_map<string, int> counts;
for(string word: words){
counts[word]++;
}
int n = s.length(), num = words.size(), lenOfWord = words[0].length();
vector<int> indexes;
for(int i = 0; i < n - num*lenOfWord+1; i++) {
unordered_map<string, int> seen;
int j = 0;
for(; j < num; j++) {
string word = s.substr(i+j*len, len);
if(counts.find(word) != counts.end()) {
seen[word]++;
if (seen[word] > counts[word])
break;
} else {
break;
}
}
if (j == num) indexes.push_back(i);
}
return indexes;
}
};
32. Longest Valid Parentheses
題目來源:https://leetcode.com/problems/longest-valid-parentheses/description/
思路
這題非常巧妙,思路是動態規劃。
我們定義dp數組的第i個元素代表,以第s[i]終結的合法括號匹配串。顯然只有以’)’結尾的括號串纔可能合法。而以’(‘結尾的必定是不合法的,因爲括號未全部匹配,此時s[i]=0。
考慮動態規劃的update函數:
a.當遇到x()
的情況時,這裏的x是一個字符串,s[i]
和s[i-1]
匹配了,因而
dp[i] = dp[i-2]+2
。這裏,()
的長度是2,而x的長度我們不用管,無關x是否合法,我們直接加,結果都是正確的。
b.當遇到xy(...))
的時候,此處y
是一個字符,我們就要看y
和最後的)
是否匹配。如果y
爲)
,顯然是不匹配的,那麼dp[i]=0
,不用管。如果y
是(
那麼,就匹配了,則
dp[i] = dp[i-1]+dp[i-dp[i-1]-2]+2
這裏dp[i-1]
就是(...)
的長度,dp[i-dp[i-1]-2]
就是x
長度,而不管x長度多少,因爲加上去總是正確的,原因跟a類似。而2
就是最後的)
和對應的(
的長度。
由a,b兩種情況,我們就討論完了。照着就可以寫出狀態轉移方程了。
參考代碼
有參考本題的solution。
class Solution {
public:
int longestValidParentheses(string s) {
int maxans = 0;
vector<int> dp;
dp.resize(s.length());
for (int i = 1; i < s.length(); i++) {
if (s[i] == ')') {
if (s[i - 1] == '(') {
dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2;
} else if (i - dp[i - 1] > 0 && s[i - dp[i - 1] - 1] == '(') {
dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2;
}
maxans = max(maxans, dp[i]);
}
}
return maxans;
}
};