目錄
- 2024-03-15 leetcode寫題記錄
- 32. 最長有效括號
- 題目連結
- 題意
- 解法
- 42. 接雨水
- 題目連結
- 題意
- 解法
- 動態規劃
- 雙指標
- 32. 最長有效括號
2024-03-15 leetcode寫題記錄
32. 最長有效括號
題目連結
32. 最長有效括號
題意
給你一個只包含$ '\((\)' 和 '\()\)' 的字串,找出最長有效(格式正確且連續)括號子串的長度。
解法
動態規劃
用\(dp[i]\)代表從第\(i\)個字串開始,最多往前多少個字元是合法的。那麼當我們遍歷\(s\)時,第\(i\)個字元只需要跟第\(i-dp[i-1]-1\)(這裡為了方便,記為\(l\))處的字元比較。
當\(l<=0\)時,代表沒有字元能夠跟第\(i\)個字元配對了,顯然\(dp[i]=0\);當第\(i\)個字元為'\((\)'時,由於第\(i\)個字元無法配對(右邊沒有字元了),所以\(dp[i]=0\);當第\(l\)個字元為'\()\)'時,由於從第\(l+1\)到第\(i-1\)的字元都已經合法了,而第\(i\)個字元無法與第\(l\)個字元配對,所以也有\(dp[i]=0\)。
只有當第\(l\)個字元為'\((\)'且第\(i\)個字元為'\()\)'時,才能完成狀態轉移,方程為\(dp[i]=dp[i-1]+2+dp[l-1]\)。
從所有\(dp[i]\)裡找到最大的那個,就是答案。
class Solution {
public:
int longestValidParentheses(string s) {
int n = s.size(), ans = 0;
vector<int> dp(n + 1, 0);
for (int i = 1; i <= n; ++i) {
int l = i - dp[i - 1] - 1;
if (l <= 0 || s[i - 1] == '(' || s[l - 1] == ')')
continue;
dp[i] = dp[i - 1] + 2 + dp[l - 1];
ans = max(ans, dp[i]);
}
return ans;
}
};
42. 接雨水
題目連結
42. 接雨水
題意
給定 n 個非負整數表示每個寬度為 1 的柱子的高度圖,計算按此排列的柱子,下雨之後能接多少雨水。
解法
動態規劃
時間複雜度\(O(n)\),空間複雜度\(O(n)\)。
class Solution {
public:
int trap(vector<int>& height) {
int n = height.size();
vector<int> l(n + 2, 0), r(n + 2, 0);
for (int i = 1; i <= n; ++i)
l[i] = max(l[i - 1], height[i - 1]);
for (int i = n; i >= 1; --i)
r[i] = max(r[i + 1], height[i - 1]);
int ans = 0;
for (int i = 1; i <= n; ++i) {
int lr = min(l[i - 1], r[i + 1]);
if (lr <= height[i - 1])
continue;
ans += lr - height[i - 1];
}
return ans;
}
};
雙指標
用\(l\)和\(r\)遍歷,若\(l\)左邊的最大值已經小於\(r\)右邊的最大值,那麼\(l\)左邊的最大值一定小於\(l+1\)右邊的最大值,所以就可以把第\(l+1\)個元素的貢獻加上,然後\(l\)右移\(1\)位,反之同理。
時間複雜度\(O(n)\),空間複雜度\(O(1)\)。
class Solution {
public:
int trap(vector<int>& height) {
int n = height.size(), l = 0, r = n - 1, ans = 0, ml = 0, mr = 0;
while(l < r) {
ml = max(ml, height[l]);
mr = max(mr, height[r]);
if (ml < mr) {
if (ml > height[l + 1])
ans += ml - height[l + 1];
l++;
} else {
if (mr > height[r - 1])
ans += mr - height[r - 1];
r--;
}
}
return ans;
}
};