-
Notifications
You must be signed in to change notification settings - Fork 29
/
Copy pathMain.java
108 lines (93 loc) · 3.26 KB
/
Main.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package com.company;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Main main = new Main();
String patStr = "ababaca";
Map<Character, Map<Integer, Integer>> table = main.createStateTransitionTable(patStr);
String str = "abababacaba";
char[] chars = str.toCharArray();
int position = 0;
int state = 0;
for (char c : chars) {
state = table.get(c).get(state);
if (state == patStr.length()) {
main.say("found end in " + position);
break;
}
position++;
}
}
/**
* 创建状态转移表
*
* @param pat
* @return
*/
private Map<Character, Map<Integer, Integer>> createStateTransitionTable(String pat) {
//创建状态转移表
char[] pats = pat.toCharArray();
Set<Character> patChars = new HashSet<>();
//求出模式串不重复字符集合
for (char p : pats) {
patChars.add(p);
}
Map<Character, Map<Integer, Integer>> table = new HashMap<>();
//相当于表格每一列,模式串字符集合的每个字符构成了列
for (char item : patChars) {
Map<Integer, Integer> colums = new HashMap<>();
//表格每一列的不同行,以及对应的状态转移
for (int i = 0; i < pats.length; i++) {
//从第一行开始
int state = findState(pat, item, i);
colums.put(i, state);
}
table.put(item, colums);
}
return table;
}
/**
* 获取转移状态
*
* @param pat
* @param patChar
* @param patCharPositonIndex
* @return
*/
private int findState(String pat, char patChar, int patCharPositonIndex) {
//构造末尾为对应字符的字符串,求出最长前后缀
StringBuilder finalStrBuilder = new StringBuilder();
String subStr = pat.substring(0, patCharPositonIndex);
finalStrBuilder.append(subStr);
finalStrBuilder.append(patChar);
String finalStr = finalStrBuilder.toString();
//情况1,位置,字符相等,状态+1
if (pat.charAt(patCharPositonIndex) == patChar) {
return patCharPositonIndex + 1;
}
//求最长相同前后缀
String longestSuffix = null;
int finalStrLength = finalStr.length();
for (int subLength = 1; subLength < finalStrLength; subLength++) {
String headSubStr = finalStr.substring(0, subLength);
String endSubStr = finalStr.substring(finalStrLength - subLength, finalStrLength);
if (headSubStr.equals(endSubStr)) {
longestSuffix = headSubStr;
}
}
if (longestSuffix == null) {
//情况2,没有相同前后子缀,状态归0
return 0;
} else {
//既是最长缀长度,同时又代表了转移状态
//情况3,发现相同子缀,设置状态
return longestSuffix.length();
}
}
private void say(String msg) {
System.out.println(msg);
}
}