今天做了一道二维字符串hash题,第一次做二维hash,水一篇题解
题目的做法就是对正方形先进行列哈希
然后再二分正方形的边长,直到二分出正方形的最大边长
在检查函数中,每次需要处理出hs2[i,j]表示以j结尾的长度为x的列hash值,即将正方形的竖边hash
然后再使用hs3[]存储每一行的hash值,再压缩成每一个正方形右下端点对应正方形的hash值,即square_hs[]。最后依次比对square_hs[]中的所有值。可以先排序,这样只要找到一组即返回true;
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef long long LL;
#define N 1005
const int base=31;
const int base2=127;
LL n,m;
LL p[N],p2[N],a[N][N],cnt,l,r,mid,hs[N][N],hs2[N][N],hs3[N],square_hs[N*N];
bool check(LL x){
//get row_string out of string of length x
for(int i=1;i<=n;i++)
for(int j=x;j<=m;j++)
hs2[i][j]=hs[i][j]-hs[i][j-x]*p[x];
cnt=0;
//get col_string out of string of length x
for(int j=x;j<=m;j++){
//col hash
for(int i=1;i<=n;i++) hs3[i]=hs3[i-1]*base2+hs2[i][j];
for(int i=x;i<=n;i++) square_hs[++cnt]=hs3[i]-hs3[i-x]*p2[x];
}
sort(square_hs+1,square_hs+1+cnt);
for(int i=2;i<=cnt;i++)
if(square_hs[i]==square_hs[i-1]) return true;
return false;
}
//binary the maxium ans
LL binary(){
LL l=0,r=min(n,m);
while(l<r){
LL mid=l+r+1 >> 1;
if(check(mid)) l=mid;
else r=mid-1;
}
return l;
}
signed main(){
scanf("%lld%lld",&n,&m);
char c[N][N];
//input and hash char
for(int i=1;i<=n;i++){
scanf("%s",c[i]+1);
for(int j=1;j<=m;j++)
a[i][j]=c[i][j]-'a';
}
//matrix hash in row
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
hs[i][j]=hs[i][j-1]*base+a[i][j];
//pre solve for check
p[0]=p2[0]=1;
for(int i=1;i<=max(n,m);i++) p[i]=p[i-1]*base;
for(int i=1;i<=max(n,m);i++) p2[i]=p2[i-1]*base2;
printf("%lld",binary());
return 0;
}