上交考研机试 最长公共子串 字符串哈希

🍑 最长公共子串
在这里插入图片描述
输入

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];
	}
}

posted @ 2023-04-21 17:41  兑生  阅读(13)  评论(0编辑  收藏  举报  来源
Live2D