poj1226(哈希)

点击打开题目链接


大意:多组数据,每组n个字符串,寻找最长的X,使得对n个字符串中的任意一个,X或者X反转过来的字符串
是其子串。(输出X的长度即可)


思路:这道好像KMP或者后缀数组都能做,但我还是习惯用哈希。此题可以先二分这个长度(显然如果某个长度满足
那么小于这个长度的串也是能找到的),不妨记这个长度为len。然后呢,以第一个字符串为标准,正一遍反一遍扫过去得到该字符串中,以i为下标开始的长度为len的子串的哈希值(不妨记为h1[i]),以及其翻转过来串对应的哈希值(不妨记为h2[i])。同时,后面几个字符串中长度为len的子串的哈希值也可处理出来,放到容器里。接下来,就是

看是否存在这样的i,使得剩余n-1个字符串对应的n-1个容器里要么含有h1[i],要么含有h2[i]。如果是则len可以,所求长度肯定大于等于len;否则,所求长度小于len。


代码如下:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.HashSet;
import java.util.StringTokenizer;

class Reader {
	static BufferedReader reader;
	static StringTokenizer tokenizer;

	static void init(InputStream input) {
		reader = new BufferedReader(new InputStreamReader(input));
		tokenizer = new StringTokenizer("");
	}

	static String next() throws IOException {
		while (!tokenizer.hasMoreTokens()) {
			tokenizer = new StringTokenizer(reader.readLine());
		}
		return tokenizer.nextToken();
	}

	static int nextInt() throws IOException {
		return Integer.parseInt(next());
	}
}

public class Main {

	/**
	 * @param args
	 */
	static int t, n, cnt, len1;
	static char ch[][];
	static int hash1[], hashin[];
	static HashSet<Integer> hashSet[];
	static String str;
	static long mul = 100000007;
	static long monum = Integer.MAX_VALUE;
	static long mulnum;

	private static boolean isOk(int num) {
		hashSet = new HashSet[n + 1];
		for (int i = 1; i <= n; i++)
			hashSet[i] = new HashSet<Integer>();
		mulnum = 1;
		for (int i = 1; i <= num; i++)
			mulnum = (mulnum * mul) % monum;
		long v;
		for (int i = 2; i <= n; i++) {
			if (ch[i].length < num)
				return false;
			v = 0;
			for (int j = 0; j < num; j++)
				v = (v * mul + (long) ch[i][j]) % monum;
			hashSet[i].add((int) v);
			for (int j = num; j < ch[i].length; j++) {
				v = (v * mul + (long) ch[i][j]) % monum;
				v = ((v - mulnum * (long) ch[i][j - num]) % monum + monum)
						% monum;
				hashSet[i].add((int) v);
			}
		}
		hash1 = new int[len1 + 1];
		hashin = new int[len1 + 1];
		v = 0;
		for (int i = 0; i < num; i++) {
			v = (v * mul + (long) ch[1][i]) % monum;
		}
		hash1[1] = (int) v;
		for (int i = num; i < len1; i++) {
			v = (v * mul + (long) ch[1][i]) % monum;
			v = ((v - mulnum * (long) ch[1][i - num]) % monum + monum) % monum;
			hash1[i - num + 2] = (int) v;
		}
		v = 0;
		for (int i = len1 - 1; i >= len1 - num; i--) {
			v = (v * mul + (long) ch[1][i]) % monum;
		}
		hashin[len1 - num + 1] = (int) v;
		for (int i = len1 - num - 1; i >= 0; i--) {
			v = (v * mul + (long) ch[1][i]) % monum;
			v = ((v - mulnum * (long) ch[1][i + num]) % monum + monum) % monum;
			hashin[i + 1] = (int) v;
		}
		boolean flag;
		for (int i = 1; i <= len1; i++) {
			flag = true;
			for (int j = 2; j <= n; j++)
				if ((!hashSet[j].contains(hash1[i]))
						&& (!hashSet[j].contains(hashin[i]))) {
					flag = false;
					break;
				}
			if (flag)
				return true;
		}
		return false;
	}

	private static void deal() {
		len1 = ch[1].length;
		int l = 0;
		int r = ch[1].length;
		if (n == 1) {
			System.out.println(r);
			return;
		}
		int mid;
		while (r - l > 1) {
			mid = (l + r) / 2;
			if (isOk(mid))
				l = mid;
			else
				r = mid;
		}
		if (isOk(r))
			System.out.println(r);
		else
			System.out.println((r - 1));
	}

	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		Reader.init(System.in);
		t = Reader.nextInt();
		ch = new char[101][];
		for (int casenum = 1; casenum <= t; casenum++) {
			n = Reader.nextInt();
			for (int i = 1; i <= n; i++) {
				str = Reader.next();
				ch[i] = str.toCharArray();
			}
			deal();
		}
	}

}


猜你喜欢

转载自blog.csdn.net/lixiaomu2/article/details/72632534