文章目錄
-
- 1. 題目來源
- 2. 題目解析
1. 題目來源
連結:1035. 不相交的線
相關:
- 不太相關:[線性dp] aw1012. 友好城市(最長上升子序列模型+思維)
- 強相關:[線性dp] aw897. 最長公共子序列(重要模闆題+最長公共子序列模型)
- 弱相關:[線性dp] aw895最長上升子序列(知識了解+重要模闆題+最長上升子序列模型+LCS轉化LIS)
力贊題解,知識總結,對比 LCS 與 LIS 特性,深挖 LCS 狀态分類,三葉姐yyds:
- 【宮水三葉の相信科學系列】求「最值問題」隻需要確定「不漏」即可
2. 題目解析
很有意思的一道題,不虧是小馬AI,題單裡的,哈哈。
一開始以為是做過的一道 思維+LIS,[線性dp] aw1012. 友好城市(最長上升子序列模型+思維)。看了看發現不是,然後就直接
dp
吧。然後發現和
lcs
思考過程一模一樣…
做完之後看了三葉姐的題解,深受啟發。 【宮水三葉の相信科學系列】求「最值問題」隻需要確定「不漏」即可
- 時間複雜度: O ( n m ) O(nm) O(nm)。
- 空間複雜度: O ( n m ) O(nm) O(nm)
代碼:
寫法一:四種情況的分類劃分,狀态之間有重疊,但不影響最值。經典的 LCS 狀态劃分。
圖檔取自 傳送門:【宮水三葉の相信科學系列】求「最值問題」隻需要確定「不漏」即可。 強烈建議看看分析。再去看看 [線性dp] aw897. 最長公共子序列(重要模闆題+最長公共子序列模型)。
class Solution {
public:
int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) {
int n = nums1.size(), m = nums2.size();
vector<vector<int>> f(n + 1, vector<int>(m + 1));
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ ) {
f[i][j] = max(f[i - 1][j], f[i][j - 1]);
if (nums1[i - 1] == nums2[j - 1]) f[i][j] = max(f[i][j], f[i - 1][j - 1] + 1);
}
return f[n][m];
}
};
寫法二:LCS 的優化,僅判斷
a[i]==b[j]
,隻分兩種情況,狀态轉移加
if-else
,代碼結構與樸素版的一樣。更加簡潔。
其實經過仔細比對,會發現,當
a[i]==b[j]
時,狀态一定由
f[i-1][j-1]+1
進行轉移,就不需要通過
f[i][j] = max(f[i - 1][j], f[i][j - 1]);
這個轉移了。但樸素的寫法,會将這個放到前面,使其先判斷不等,再判斷相等。
重點了解:
- 其中,
隻需要a[i]==b[j]
參與狀态轉移,而不需要其它的來進行大小比較。例如和四種狀态劃分一樣,當f[i][j]=f[i-1][j-1]+1
時,a[i]==b[j]
這三個值來比大小。以其中一個為例,f[i][j]=max(f[i-1][j],f[i][j-1],f[i-1][j-1]+1)
相較于f[i][j-1]
是多了一個f[i-1][j-1]+1
元素的,那麼如果這個a[i]
元素比對了a[i]
串中的某一個,也不過是b
的貢獻量,頂多與+1
持平。如果不比對,甚至還不如f[i-1][j-1]+1
,那麼取f[i-1][j-1]+1
自然取不到它。 是以直接通過max
進行狀态轉移。f[i][j]=f[i-1][j-1]+1
- 是以,在
狀态轉移時進行一個小優化。兩種方法的代碼實作将完全一緻。a[i]==b[j]
class Solution {
public:
int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) {
int n = nums1.size(), m = nums2.size();
vector<vector<int>> f(n + 1, vector<int>(m + 1));
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ ) {
if (nums1[i - 1] == nums2[j - 1]) f[i][j] = f[i - 1][j - 1] + 1; // 直接轉移
else f[i][j] = max(f[i - 1][j], f[i][j - 1]);
}
return f[n][m];
}
};