parent
4d29825c5a
commit
abb9862872
@ -0,0 +1,103 @@
|
||||
package class_2023_05_5_week;
|
||||
|
||||
// 字符串哈希原理和实现
|
||||
public class Code04_StringHash {
|
||||
|
||||
// 暴力方法
|
||||
// 为了验证
|
||||
public static boolean rightCheck(String str, int l1, int l2, int len) {
|
||||
if (l1 + len > str.length() || l2 + len > str.length()) {
|
||||
return false;
|
||||
}
|
||||
if (l1 == l2) {
|
||||
return true;
|
||||
}
|
||||
return str.substring(l1, l1 + len).equals(str.substring(l2, l2 + len));
|
||||
}
|
||||
|
||||
// 哈希方法检测
|
||||
public static int MAXN = 100005;
|
||||
|
||||
public static long[] pow = new long[MAXN];
|
||||
|
||||
public static long[] hash = new long[MAXN];
|
||||
|
||||
public static int base = 499;
|
||||
|
||||
public static void build(String str, int n) {
|
||||
pow[0] = 1;
|
||||
for (int j = 1; j < n; j++) {
|
||||
pow[j] = pow[j - 1] * base;
|
||||
}
|
||||
// a -> 1
|
||||
// b -> 2
|
||||
// c -> 3
|
||||
// z -> 26
|
||||
// 前缀和的哈希值
|
||||
hash[0] = str.charAt(0) - 'a' + 1;
|
||||
for (int j = 1; j < n; j++) {
|
||||
hash[j] = hash[j - 1] * base + str.charAt(j) - 'a' + 1;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hashCheck(int n, int l1, int l2, int len) {
|
||||
int r1 = l1 + len - 1;
|
||||
int r2 = l2 + len - 1;
|
||||
if (r1 >= n || r2 >= n) {
|
||||
return false;
|
||||
}
|
||||
return hash(l1, r1) == hash(l2, r2);
|
||||
}
|
||||
|
||||
// s[l...r]
|
||||
public static long hash(int l, int r) {
|
||||
// hash[0] : s[0...0]
|
||||
// hash[5] : s[0...5]
|
||||
// hash[i] : s[0...i]
|
||||
long ans = hash[r];
|
||||
ans -= l == 0 ? 0 : (hash[l - 1] * pow[r - l + 1]);
|
||||
return ans;
|
||||
}
|
||||
|
||||
// 为了测试
|
||||
public static String randomString(int len, int v) {
|
||||
char[] str = new char[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
str[i] = (char) ('a' + (int) (Math.random() * v));
|
||||
}
|
||||
return String.valueOf(str);
|
||||
}
|
||||
|
||||
// 为了测试
|
||||
public static void main(String[] args) {
|
||||
String test = "abcabcabcabcabcabcabcabc";
|
||||
int size = test.length();
|
||||
build(test, size);
|
||||
System.out.println(hashCheck(size, 6, 15, 3));
|
||||
|
||||
System.out.println("测试开始");
|
||||
int N = 10000;
|
||||
int V = 3;
|
||||
int testTeams = 100;
|
||||
int testTimes = 5000;
|
||||
int LEN = 6;
|
||||
for (int i = 0; i < testTeams; i++) {
|
||||
int n = (int) (Math.random() * N) + 1;
|
||||
String str = randomString(n, V);
|
||||
build(str, n);
|
||||
for (int k = 0; k <= testTimes; k++) {
|
||||
int l1 = (int) (Math.random() * n);
|
||||
int l2 = (int) (Math.random() * n);
|
||||
int len = (int) (Math.random() * LEN) + 1;
|
||||
boolean ans1 = rightCheck(str, l1, l2, len);
|
||||
boolean ans2 = hashCheck(n, l1, l2, len);
|
||||
if (ans1 != ans2) {
|
||||
System.out.println("出错了!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("测试结束");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
package class_2023_05_5_week;
|
||||
|
||||
// 正方形矩阵哈希实现
|
||||
// 二维哈希只适用于正方形的情况
|
||||
// 如果想支持普通矩阵,需要更复杂度的过程,这里不做展开
|
||||
public class Code06_TwoDimensionalHash {
|
||||
|
||||
public static int MAXN = 1001;
|
||||
|
||||
public static long[] powr = new long[MAXN];
|
||||
|
||||
public static long[] powc = new long[MAXN];
|
||||
|
||||
public static long[][] sum = new long[MAXN][MAXN];
|
||||
|
||||
public static int baser = 491;
|
||||
|
||||
public static int basec = 499;
|
||||
|
||||
public static void buildHash(int[][] arr) {
|
||||
int n = arr.length - 1;
|
||||
int m = arr[0].length - 1;
|
||||
powr[0] = 1;
|
||||
powc[0] = 1;
|
||||
for (int i = 1; i <= n; i++) {
|
||||
powr[i] = (powr[i - 1] * baser);
|
||||
}
|
||||
for (int i = 1; i <= m; i++) {
|
||||
powc[i] = (powc[i - 1] * basec);
|
||||
}
|
||||
for (int i = 1; i <= n; i++) {
|
||||
for (int j = 1; j <= m; j++) {
|
||||
// 左 * basec + arr[i][j]
|
||||
sum[i][j] = sum[i][j - 1] * basec + arr[i][j];
|
||||
}
|
||||
}
|
||||
for (int i = 1; i <= n; i++) {
|
||||
for (int j = 1; j <= m; j++) {
|
||||
// 上 * baser
|
||||
sum[i][j] += sum[i - 1][j] * baser;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int[][] randomArray(int n, int m) {
|
||||
int[][] arr = new int[n + 1][m + 1];
|
||||
for (int i = 0; i < n; i++) {
|
||||
for (int j = 0; j < m; j++) {
|
||||
arr[i][j] = Math.random() < 0.5 ? 5 : 6;
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
int n = 100;
|
||||
int m = 100;
|
||||
int[][] arr = randomArray(n, m);
|
||||
buildHash(arr);
|
||||
int testTimes = 50000;
|
||||
int len = 5;
|
||||
System.out.println("测试开始");
|
||||
for (int i = 0; i < testTimes; i++) {
|
||||
int a = (int) (Math.random() * 90) + 1;
|
||||
int b = (int) (Math.random() * 90) + 1;
|
||||
int c = (int) (Math.random() * 90) + 1;
|
||||
int d = (int) (Math.random() * 90) + 1;
|
||||
int sizer = (int) (Math.random() * len) + 1;
|
||||
int sizec = sizer; // 如果矩阵是正方形,完全可以使用
|
||||
// sizec = (int) (Math.random() * len) + 1; // 如果矩阵不是正方形,不能用!会报错!
|
||||
boolean ans1 = rightCheck(arr, a, b, c, d, sizer, sizec);
|
||||
boolean ans2 = hashCheck(a, b, c, d, sizer, sizec);
|
||||
if (ans1 != ans2) {
|
||||
System.out.println("出错了!");
|
||||
}
|
||||
}
|
||||
System.out.println("测试结束");
|
||||
}
|
||||
|
||||
// 当前矩阵,必须是正方形!
|
||||
// 左上点(a,b)
|
||||
// 右下点(c,d)
|
||||
public static long hash(int a, int b, int c, int d) {
|
||||
return sum[c][d]
|
||||
- sum[a - 1][d] * powr[c - a + 1]
|
||||
- sum[c][b - 1] * powc[d - b + 1]
|
||||
+ sum[a - 1][b - 1] * powr[d - b + 1] * powc[c - a + 1];
|
||||
}
|
||||
|
||||
public static boolean hashCheck(int a, int b, int c, int d, int lenr, int lenc) {
|
||||
return hash(a, b, a + lenr - 1, b + lenc - 1) == hash(c, d, c + lenr - 1, d + lenc - 1);
|
||||
}
|
||||
|
||||
public static boolean rightCheck(int[][] arr, int a, int b, int c, int d, int lenr, int lenc) {
|
||||
for (int i = a, j = c; i < a + lenr; i++, j++) {
|
||||
for (int p = b, q = d; p < b + lenc; p++, q++) {
|
||||
if (arr[i][p] != arr[j][q]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in new issue