题解 | #最长公共子数组#
最长公共子数组
http://www.nowcoder.com/practice/6032826d387c4a10ad3690cce5fdb015
题意理解
求两个数组最长的公共连续子数组的长度。
方法一
动态规划
使用一个二维数组dp,其中dp[i][j]表示A中子串以A[i]结尾且B中子串以B[j]结尾时,它们满足是公共子串的长度。显然,当两者不等时,以它们结尾的子串不可能是公共子串;当两者相等时,可以使前面的公共子串的长度加1。状态转移方程如下:
注意要设置dp的边界,数组元素相等时为1,不等时为0。我们在计算dp[i][j]的时候同时更新最后的最长长度ans。
以[22561,2256]为例,dp数组的值如下图所示:
具体代码如下:
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param A int整型vector
* @param B int整型vector
* @return int整型
*/
int longestCommonSubarry(vector<int>& A, vector<int>& B) {
// write code here
vector<vector<int>> dp(A.size(),vector<int> (B.size(),0));
int ans = 0;
//初始化
for (int i=0;i<A.size();i++)
if (A[i]==B[0]) dp[i][0] = 1;
for (int i=0;i<B.size();i++)
if (A[0]==B[i]) dp[0][i] = 1;
for (int i=1;i<A.size();i++)
{
for (int j=1;j<B.size();j++)
{
if (A[i]==B[j])
{
dp[i][j] = dp[i-1][j-1] + 1;
ans = max(ans, dp[i][j]);
}
//如果不等,dp为0
else dp[i][j] = 0;
}
}
return ans;
}
};
时间复杂度: O(N^2)。双重循环,外侧循环遍历这个A,内侧循环遍历整个B,长度均为N。
空间复杂度: O(N^2)。使用了二维数组dp,其长宽分别为A、B的长度。
方法二
枚举
我们枚举所有子数组的开头和子数组的长度。前面两重循环分别枚举A中子数组的起始位置i和B的子数组的起始位置j,第三重循环枚举连续公共子数组的长度,如果出现某两个元素不相等了就停止,说明此时已经得到以A[i]、B[j]开头的连续子数组的最大长度。如果相等,那么枚举的长度继续递增,同时更新ans。
具体代码如下:
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param A int整型vector
* @param B int整型vector
* @return int整型
*/
int longestCommonSubarry(vector<int>& A, vector<int>& B) {
// write code here
int ans = 0;
//枚举所有可能的子数组的情况
for (int i=0;i<A.size();i++)
for (int j=0;j<B.size();j++)
{
for (int k=0;k<A.size()-i&&k<B.size()-j;k++)
if (A[i+k]!=B[j+k])
{
//及时跳出循环
break;
}
else ans = max(ans, k+1);
}
return ans;
}
};
时间复杂度: O(N^3)。三重循环,每重循环的最坏情况对应的次数均为N。
空间复杂度: O(1)。没有开辟新空间。