Hace buen tiempo el jueves 25 de marzo de 2021 [No lamentes el pasado, no desperdicies el presente, no temas el futuro]
Contenido de este artículo
1. Introducción
718. La submatriz repetida más larga
2. Solución
2.1 Programación dinámica
class Solution {
public:
int findLength(vector<int>& A, vector<int>& B) {
int m = A.size(), n = B.size();
vector<vector<int>> dp(m+1,vector<int>(n+1));
int res = 0;
for(int i=0;i<m;++i){
for(int j=0;j<n;++j){
dp[i+1][j+1] = A[i]==B[j]?dp[i][j]+1:0;
res = max(res,dp[i+1][j+1]);
}
}
return res;
}
};
Versión optimizada para el espacio:
class Solution {
public:
int findLength(vector<int>& A, vector<int>& B) {
int m = A.size(), n = B.size();
// 始终使数组B的长度最小
if(m<n) return findLength(B,A);
vector<int> dp(n+1);
int res = 0;
for(int i=0;i<m;++i){
// 从后往前计算dp,避免数据被覆盖
for(int j=n-1;j>=0;--j){
if(A[i]==B[j]) dp[j+1] = dp[j] + 1;
else dp[j+1] = 0;
res = max(res,dp[j+1]);
}
}
return res;
}
};
2.2 Ventana corredera (idea ingeniosa)
Para ser honesto, lo primero que pensé para esta pregunta fue el método de la ventana deslizante. La idea sigue siendo muy simple, como se muestra en la siguiente figura (fuente: solución de ventana deslizante ), pero desafortunadamente el código no está escrito,
si lo escribe directamente de acuerdo con el proceso anterior. El código será un poco complicado, así que consideremos cambiar nuestra forma de pensar.
Hay dos tipos de alineación de matriz: el primer tipo es A sin cambios y el primer elemento de B está alineado con un elemento en A; el segundo tipo es B sin cambios y el primer elemento de A está alineado con un elemento en B. Para cada alineación, podemos calcular las submatrices repetidas con la misma posición relativa. (En resumen: alinee el primer elemento, avance por primera vez y retroceda por segunda vez )
El método de ventana corrediza también se puede podar : si la longitud común len
o menos res
, se puede devolver por adelantado.
class Solution {
public:
int findLength(vector<int>& A, vector<int>& B) {
const int lenA = A.size(), lenB = B.size();
int res = 0;
// A 不变,B 的首元素与 A 中的某个元素对齐
for(int i=0;i<lenA;++i){
int len = min(lenB, lenA-i);
if(len<=res) continue; // 剪枝
int maxLen = helper(A,B,i,0,len);
res = max(res,maxLen);
}
// B 不变,A 的首元素与 B 中的某个元素对齐
for(int i=0;i<lenB;++i){
int len = min(lenA, lenB-i);
if(len<=res) continue; // 剪枝
int maxLen = helper(A,B,0,i,len);
res = max(res,maxLen);
}
return res;
}
// 给出两数组的首元素索引和重合长度,计算重合部分的最长重复子数组
int helper(vector<int>& A, vector<int>& B, int begA, int begB, int len){
int maxLen = 0, cnt = 0;
for(int i=0;i<len;++i){
if(A[begA+i]==B[begB+i]) ++cnt;
else cnt = 0;
maxLen = max(cnt,maxLen);
}
return maxLen;
}
};
referencias
https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray/solution/zui-chang-zhong-fu-zi-shu-zu-by-leetcode-solution/
https://leetcode-cn.com/problems/maximum-length-of-repeated-subarray/solution/wu-li-jie-fa-by-stg-2/