718.最长重复子数组
暴力题解
- 时间复杂度O(n^3),超时
代码
public int findLength(int[] A, int[] B) {
int max=0;
int l1=A.length,l2=B.length;
for(int i=0;i<l1;i++){
int tmp=0;
for(int j=0;j<l2;j++){
if(A[i]==B[j]){
tmp=find(i,j,A,B);
}
max=Math.max(max,tmp);
}
}
return max;
}
public int find(int i,int j,int[] A,int[] B){
int tmp=0;
while(i<A.length&&j<B.length&&A[i]==B[j]){
tmp++;
i++;
j++;
}
return tmp;
}
动态规划
- 递推公式:
if(A[i]==B[j]){
dp[i][j]=dp[i-1][j-1]+1;
}else{
dp[i][j]=0;
}
- 可以先对第一行第一列的数据进行预处理,再进行匹配
代码
public int findLength(int[] A,int[] B){
int max=0;
int[][] dp=new int[A.length][B.length];
//初始化dp[0][i] 第一行
for(int i=0;i<B.length;i++){
if(A[0]==B[i]){
dp[0][i]=1;
}
}
//初始化dp[i][0] 第一列
for(int i=0;i<A.length;i++){
if(A[i]==B[0]){
dp[i][0]=1;
}
}
for(int i=1;i<A.length;i++){
for(int j=1;j<B.length;j++){
if(A[i]==B[j]){
dp[i][j]=dp[i-1][j-1]+1;
max=Math.max(max,dp[i][j]);
}
}
}
return max;
}
- 若不进行预处理,
dp
的长宽都加1,且dp
的第一行第一列视为0(无数据对应)
代码如下:
public int findLength(int[] A,int[] B){
int max=0;
int[][] dp=new int[A.length+1][B.length+1];
for(int i=1;i<=A.length;i++){
for(int j=1;j<=B.length;j++){
if(A[i-1]==B[j-1]){
dp[i][j]=dp[i-1][j-1]+1;
}else{
dp[i][j]=0;
}
max=Math.max(max, dp[i][j]);
}
}
return max;
}
滑动窗口
- A固定,B移动;B固定,A移动
代码
//50ms
public class Solution4 {
public int findLength(int[] A,int[] B){
int n=A.length,m=B.length;
int max=0;
//固定B 移动A
for(int i=0;i<n;i++){
int len=Math.min(m, n-i);
int maxLen=maxLength(A,B,i,0,len);
max=Math.max(max, maxLen);
}
//固定A 移动B
for(int i=0;i<m;i++){
int len=Math.min(n,m-i);
int maxLen=maxLength(A, B, 0, i, len);
max=Math.max(max, maxLen);
}
return max;
}
//公共区域 最大匹配长度
private int maxLength(int[] A, int[] B, int addA, int addB, int len) {
int ans=0,k=0;
for(int i=0;i<len;i++){
if(A[addA+i]==B[addB+i]){
k++;
}else{
k=0;
}
ans=Math.max(ans, k);
}
return ans;
}
}
参考链接