132 lines
3.7 KiB
Java
132 lines
3.7 KiB
Java
|
|
|||
|
import java.util.HashMap;
|
|||
|
import java.util.LinkedList;
|
|||
|
import java.util.Map;
|
|||
|
import java.util.Objects;
|
|||
|
|
|||
|
/**
|
|||
|
* @author wayne
|
|||
|
*/
|
|||
|
public class ACAutoMata {
|
|||
|
private ACNode root;
|
|||
|
|
|||
|
public ACAutoMata() {
|
|||
|
this.root = new ACNode("/");
|
|||
|
}
|
|||
|
|
|||
|
private void insert (String pattern) {
|
|||
|
ACNode node = this.root;
|
|||
|
int len = pattern.length();
|
|||
|
for (int i = 0; i < len; i++) {
|
|||
|
String c = pattern.charAt(i) + "";
|
|||
|
if(Objects.isNull(node.children.get(c))) {
|
|||
|
node.children.put(c, new ACNode(c));
|
|||
|
}
|
|||
|
node = node.children.get(c);
|
|||
|
}
|
|||
|
|
|||
|
node.isEndingChar = true;
|
|||
|
node.length = pattern.length();
|
|||
|
}
|
|||
|
|
|||
|
private void buildFailurePointer() {
|
|||
|
ACNode root = this.root;
|
|||
|
LinkedList<ACNode> queue = new LinkedList<>();
|
|||
|
queue.add(root);
|
|||
|
|
|||
|
while (!queue.isEmpty()) {
|
|||
|
ACNode p = queue.pop();
|
|||
|
|
|||
|
for(ACNode pc: p.children.values()){
|
|||
|
if (Objects.isNull(pc)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if(p == root) {
|
|||
|
pc.fail = root;
|
|||
|
} else {
|
|||
|
ACNode q = p.fail;
|
|||
|
while (Objects.nonNull(q)) {
|
|||
|
ACNode qc = q.children.get(pc.data);
|
|||
|
if(Objects.nonNull(qc)) {
|
|||
|
pc.fail = qc;
|
|||
|
break;
|
|||
|
}
|
|||
|
q = q.fail;
|
|||
|
}
|
|||
|
if(Objects.isNull(q)) {
|
|||
|
pc.fail = root;
|
|||
|
}
|
|||
|
}
|
|||
|
queue.add(pc);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private Boolean match (String text) {
|
|||
|
ACNode root = this.root;
|
|||
|
ACNode p = root;
|
|||
|
|
|||
|
int n = text.length();
|
|||
|
for(int i = 0; i < n; i++) {
|
|||
|
String c = text.charAt(i) + "";
|
|||
|
while(Objects.isNull(p.children.get(c)) && p != root){
|
|||
|
p = p.fail;
|
|||
|
}
|
|||
|
|
|||
|
p = p.children.get(c);
|
|||
|
if(Objects.isNull(p)) {
|
|||
|
p = root;
|
|||
|
}
|
|||
|
|
|||
|
ACNode tmp = p;
|
|||
|
while ( tmp != root) {
|
|||
|
if (tmp.isEndingChar == true) {
|
|||
|
System.out.println("Start from " + (i - p.length + 1));
|
|||
|
return true;
|
|||
|
}
|
|||
|
tmp = tmp.fail;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
public static boolean match(String text, String[] patterns) {
|
|||
|
ACAutoMata automata = new ACAutoMata();
|
|||
|
for (String pattern: patterns) {
|
|||
|
automata.insert(pattern);
|
|||
|
}
|
|||
|
|
|||
|
automata.buildFailurePointer();
|
|||
|
return automata.match(text);
|
|||
|
}
|
|||
|
|
|||
|
public class ACNode {
|
|||
|
private String data;
|
|||
|
private Map<String, ACNode> children;
|
|||
|
private Boolean isEndingChar;
|
|||
|
private Integer length;
|
|||
|
private ACNode fail;
|
|||
|
|
|||
|
public ACNode(String data) {
|
|||
|
this.data = data;
|
|||
|
this.children = new HashMap<>();
|
|||
|
this.isEndingChar = false;
|
|||
|
this.length = 0;
|
|||
|
this.fail = null;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public static void main(String[] args) {
|
|||
|
String[] patterns = {"at", "art", "oars", "soar"};
|
|||
|
String text = "soarsoars";
|
|||
|
System.out.println(match(text, patterns));
|
|||
|
|
|||
|
String[] patterns2 = {"Fxtec Pro1", "谷歌Pixel"};
|
|||
|
|
|||
|
String text2 = "一家总部位于伦敦的公司Fxtex在MWC上就推出了一款名为Fxtec Pro1的手机,该机最大的亮点就是采用了侧滑式全键盘设计。DxOMark年度总榜发布 华为P20 Pro/谷歌Pixel 3争冠";
|
|||
|
System.out.println(match(text2, patterns2));
|
|||
|
}
|
|||
|
}
|