这道题时最长公共子序列的一个变种,对这道题目印象非常的深,原因是以前面试的时候被这道题目卡住了,老规矩我们先尝试暴力破解方法。

class Solution {
public:
    int findLength(vector<int>& A, vector<int>& B) {
        int maxlen = 0;
        for(int i = 0;i < A.size();i++)
        {
            for(int j = 0;j < B.size();j++)
            {
                if(A[i] == B[j])
                {
                    int k = 1;
                    while((i + k < A.size())&&(j + k < B.size()) 
                        &&(A[i + k] == B[j + k])){
                        k += 1;
                    }
                    maxlen = max(maxlen,k);
                }
            }
        }

        return maxlen;
    }
};

运行结果:

Time Limit Exceeded
Details 
Last executed input
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0View All

一般运行超时表示我们思路是对的,但是性能不行,可以点开detail看到我们已经pass了一半用例,下面我们尝试优化算法。
需要一提的是上面的暴力破解如果忽略对参数合法性的判断,会导致运行时错误(vector访问越界)。
使用动态规划算法解决该问题,难点在于状态转移方程:
dp[i][j] = dp[i-1][j-1]+1 if A[i]==B[j] else 0
dp[i][j] 表示以A[i]结尾 B[j]结尾的数组最长的公共序列长度,如果A[i]和B[j]不相等,那么公共长度为0.(满足以A[i] B[i结尾,最后A[i]] B[j]不相等),如果A[i]和B[j]相等转移到dp[i-1][j-1],这一点相对来说比较好理解。

class Solution {
public:
    int findLength(vector<int>& A, vector<int>& B) {
        int m = A.size(),n = B.size();
        int dp[m + 1][n + 1];
        memset(dp,0,sizeof(int)*(m+1)*(n+1));
        int maxlen = 0;
        for(int i = 0; i < m;i++) {
            for(int j = 0;j < n;j++) {
                if(A[i] == B[j])
                    dp[i][j] = (i == 0 || j == 0) ? 1 : dp[i - 1][j - 1] + 1;
                else
                    dp[i][j] = 0;
                
                maxlen = max(maxlen,dp[i][j]);
            }
        }
        return maxlen;
    }
};

运行结果:

Runtime: 160 ms, faster than 91.29% of C++ online submissions for Maximum Length of Repeated Subarray.
Memory Usage: 16 MB, less than 71.61% of C++ online submissions for Maximum Length of Repeated Subarray.