給兩個數列 A B 分別寫成上下平行,如果 A[i] == B[j] ,那可以用一直線相連,要找出最大沒有交叉的連線數。
做完上一個 contest ,再看這個問題,很自然就會以相似的解法去進行。
這裡有一個特色「兩數列,各取一個兩兩配對,配對後不能重複再用到。」這樣想到可能會有一個表格狀的DP,再應題目做處理。
這題也是這樣。
DP[i][j] 定為該位置上的最大的沒交叉的相連數。
如果位置 A[i] == B[j] ,那 DP[i][j] = 1 再加右下方 DP[i+1][j+1] ,即加上後方的最大沒交叉相連數。
然後 DP[i][j] = 從自身、右、下三者取最大值,這樣 DP[i][j] 會是最大的沒交叉的相連數。
最後回傳 DP[0][0] 即可。
class Solution: def maxUncrossedLines(self, A: List[int], B: List[int]) -> int: from functools import lru_cache ia, ib = 0, 0 na, nb = len(A), len(B) @lru_cache(None) def dfs(ia, ib): if ia > na - 1 or ib > nb - 1: return 0 ans = 1 if A[ia] == B[ib] else 0 ans = max(ans + dfs(ia+1, ib+1), dfs(ia+1, ib), dfs(ia, ib+1)) return ans return dfs(0, 0)C#
public class Solution { public int MaxUncrossedLines(int[] A, int[] B) { int[,] dp = new int[A.Length, B.Length]; dp[A.Length-1, B.Length-1] = A[A.Length - 1] == B[B.Length - 1] ? 1 : 0; int lastNum = B[B.Length - 1]; for(int i = A.Length - 2; i >= 0; i--) { if(A[i] == lastNum) dp[i, B.Length-1] = 1; else dp[i, B.Length-1] = dp[i+1, B.Length-1]; } lastNum = A[A.Length - 1]; for(int j = B.Length - 2; j >= 0; j--) { if(B[j] == lastNum) dp[A.Length-1, j] = 1; else dp[A.Length-1, j] = dp[A.Length-1, j+1]; } for(int i = A.Length - 2; i >= 0; i--) { for(int j = B.Length - 2; j >= 0; j--) { dp[i, j] = dp[i+1, j+1] + (A[i] == B[j] ? 1 : 0); dp[i, j] = Math.Max(dp[i, j], dp[i+1, j]); dp[i, j] = Math.Max(dp[i, j], dp[i, j+1]); } } return dp[0, 0]; } }