(算法题)两条不相交的线

同学面试华为手撕算法的一道题目。

直接给我的时候我是懵的,面试官也提醒了动态规划和方程,可带着这样的思路也没想起来,想着怎么这么难。后来吃完饭闲来无事网上查了一下,发现竟然是Leetcode的原题,看了一下思路,恍然大悟,原来原理和最长公共字符串的思路一样!所以特地来记录一下。

题目:

(Leetcode 1035)我们在两条独立的水平线上按给定的顺序写下 A 和 B 中的整数。

现在,我们可以绘制一些连接两个数字 A[i] 和 B[j] 的直线,只要 A[i] == B[j],且我们绘制的直线不与任何其他连线(非水平线)相交。

以这种方法绘制线条,并返回我们可以绘制的最大连线数。
(算法题)两条不相交的线_第1张图片

思路

讲这道题思路前,先讲下最长公共子序列的的思路。
最长公共子序列是说两个字符串,有多少相等的公共的子串(不需要连续)。比如:
str1:A B C B D A B
str2:B D C A B A
那么它们的最长公共子序列为:
B C A B
B D A B
B C B A
其中任意一个都是。

创建一个二维DP数组DP[i][j],表示str1第i个元素到str2第j个元素的最长公共子串长度。可以画个二维DP table便于理解。
状态转移方程:
当str[i]=str[j]时,DP等于前面的最长的加1
即:DP[i][j]=DP[i-1][j-1]+1

当str[i] !=str[j]时,DP等于临近出现的最长的
即:DP[i][j]=max( DP[i-1][j] , DP[i][j-1] )

而这些又跟本道题有什么关系呢?把这道题的思路稍微转变一下,就会发现,匹配上的不连续的公共子序列如果两两连接起来,就是不想交的线!所以本质就是最长公共子序列套了个壳。解法跟之前几乎一模一样。

这里贴一种解法的代码(C++):

class Solution {
public:
    int maxUncrossedLines(vector& A, vector& B) {
        vector> dp(A.size()+1,vector(B.size()+1,0));

        for(int i = 1;i <= A.size();i++){
            for(int j = 1;j <= B.size();j++){
                if(A[i-1] == B[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[A.size()][B.size()];
    }
};

你可能感兴趣的:(数据结构和算法)