上交考研机试 最长公共子串 字符串哈希
🍑 最长公共子串
输入
ab123abccff
abcfacb123
输出
3
🍑 P = 133 降低哈希冲突的几率
🍑 System.arraycopy(数组1,数组1起始下标,目的数组,目的起始下标,拷贝长度);
🍤 数据拷贝方向:数组1 --> 目的数组
import java.util.HashSet;
import java.util.Scanner;
public class Main
{
static int N = 20010, P = 131, n, m;
static char[] c = new char[N];
static long[] h = new long[N];
static long[] p = new long[N];
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
char[] a = sc.next().toCharArray();
char[] b = sc.next().toCharArray();
n = a.length;
m = b.length;
// 数组的复制
System.arraycopy(a, 0, c, 0, n);
System.arraycopy(b, 0, c, n + 1, m);
// 字符串哈希预处理 + 题目限制不能有数字处理
p[0] = 1;
for (int i = 1; i <= n + m; i++)
{
p[i] = p[i - 1] * P;
if (Character.isDigit(c[i]))//处理数字
{
if (i <= n)
c[i] = '$';//第一个串和第二串的数字都置换成不一样的特殊字符即可
else
{
c[i] = '*';
}
}
h[i] = h[i - 1] * P + c[i];
}
// 二分求解答案
int l =0;
int r = Math.min(n, m);
while(l < r)
{
int mid = l + r + 1 >> 1;
if(check(mid))
l = mid;
else {
r = mid - 1;
}
}
System.out.println(l);
}
// 检查此长度的子串是否是公共子串
private static boolean check(int len)
{
HashSet<Long> set = new HashSet<>();
// 遍历第一个原串
for(int i = 1; i + len -1 <= n; i++)
set.add(get(i,i+len-1));
// 遍历第二个原串
for(int i = n+1; i + len - 1 <= n+m; i++)
if(set.contains(get(i, i+len-1)))//重复,是公共子串
return true;
return false;
}
// 字串哈希
private static Long get(int l, int r)
{
return h[r] - h[l-1]*p[r-l+1];
}
}