1143. 最長公共子序列
題目連結:https://leetcode.cn/problems/longest-common-subsequence/
文章講解:https://programmercarl.com/1143.最長公共子序列.html
題目難度:中等
影片講解:https://www.bilibili.com/video/BV1ye4y1L7CQ
題目狀態:有點思路,但細節有點混亂
思路:
維護一個二維動規陣列dp[i][j],用來記錄長度為i-1的字串text1與長度為j-1的字串text2的最長公共子序列,它的更新條件如下:
- 若
text1[i - 1] == text2[j - 1]
,則dp[i][j] = dp[i - 1][j - 1] + 1
; - 若
text1[i - 1] != text2[j - 1]
,則dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
。
其中為什麼是i-1和j-1,這個問題和上一題是一樣的。
程式碼:
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
int len1 = text1.size();
int len2 = text2.size();
vector<vector<int>> dp(len1 + 1, vector<int>(len2 + 1, 0));
for(int i = 1; i <= len1; ++i) {
for(int j = 1; j <= len2; ++j) {
if(text1[i - 1] == text2[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1;
else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
}
return dp[len1][len2];
}
};
1035. 不相交的線
題目連結:https://leetcode.cn/problems/uncrossed-lines/
文章講解:https://programmercarl.com/1035.不相交的線.html
題目難度:中等
影片講解:https://www.bilibili.com/video/BV1h84y1x7MP
題目狀態:看題解
思路:
其本質就是尋找最長公共子序列,也就是上一題。
程式碼:
class Solution {
public:
int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) {
int len1 = nums1.size();
int len2 = nums2.size();
vector<vector<int>> dp(len1 + 1, vector<int>(len2 + 1, 0));
for(int i = 1; i <= len1; ++i) {
for(int j = 1; j <= len2; ++j) {
if(nums1[i - 1] == nums2[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1;
else dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]);
}
}
return dp[len1][len2];
}
};
53. 最大子陣列和
題目連結:https://leetcode.cn/problems/maximum-subarray/
文章講解:https://programmercarl.com/0053.最大子序和(動態規劃).html
題目難度:中等
影片講解:https://www.bilibili.com/video/BV19V4y1F7b5
題目狀態:之前使用其他方法AC過
思路一:貪心演算法
遍歷整體陣列,記錄當前總和count
,若count
出現了負數,說明前面這些陣列都可以刪掉,從下一個元素開始重新遍歷,最終返回最大的count
值。
程式碼一:
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int count = 0;
int res = INT_MIN;
for(int i = 0; i < nums.size(); ++i) {
count += nums[i];
if(count > res) res = count;
if(count <= 0) count = 0;
}
return res;
}
};
思路二:動態規劃
維護一個一維動規陣列dp[i]
表示以i
元素結尾的最大值(注意是以i
元素結尾的,而並不是整體的最大值,整體最大值還需要再去遍歷)。
程式碼二:
class Solution {
public:
int maxSubArray(vector<int>& nums) {
if(nums.size() == 0) return 0;
vector<int> dp(nums.size());
dp[0] = nums[0];
int maxSum = dp[0];
for(int i = 1; i < nums.size(); ++i) {
dp[i] = max(nums[i], dp[i - 1] + nums[i]);
maxSum = max(maxSum, dp[i]);
}
return maxSum;
}
};
392. 判斷子序列
題目連結:https://leetcode.cn/problems/is-subsequence/
文章講解:https://programmercarl.com/0392.判斷子序列.html
題目難度:簡單
影片講解:https://www.bilibili.com/video/BV1tv4y1B7ym/
題目狀態:使用其他方式透過,沒有使用動規
思路一:
使用兩個指標i
和j
分別遍歷題目中的序列s
和t
,若遇到s[i] == t[j]
,則i++
,最後判斷i
的位置,如果i
最後的位置是序列s
的末尾,表示s
遍歷完了,也就是說在t
中找到了所有的s
。
程式碼一:
class Solution {
public:
bool isSubsequence(string s, string t) {
if(s.empty()) return true;
if(t.empty()) return false;
int i = 0, j = 0;
while(i < s.size() && j < t.size()) {
if(s[i] == t[j]) i++;
j++;
}
return i == s.size();
}
};
思路二:動態規劃
維持一個二維動規陣列dp[i][j]
表示在序列s
遍歷到i - 1
,序列t
遍歷到j - 1
時,這兩者的相同子序列的長度。
- 當
s[i - 1] == t[j - 1]
時,動規陣列將在前面的基礎上加1 - 當兩者不相等的時候,動規陣列維持原狀
程式碼二:
class Solution {
public:
bool isSubsequence(string s, string t) {
int sLen = s.size();
int tLen = t.size();
vector<vector<int>> dp(sLen + 1, vector<int>(tLen + 1, 0));
for(int i = 1; i <= sLen; ++i) {
for(int j = 1; j <= tLen; ++j) {
if(s[i - 1] == t[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1;
else dp[i][j] = dp[i][j - 1];
}
}
if(dp[sLen][tLen] == sLen) return true;
else return false;
}
};