我尝试使用搜索算法 KMP 来计算模式发生次数和所需的比较(在下面的代码中称为匹配)。
我尝试过以下操作:
public class KMP {
private String pat;
private int[][] dfa;
private static int match;
private static int count;
public KMP(String pat) {
// Build DFA from pattern.
this.pat = pat;
int M = pat.length();
int R = 256;
dfa = new int[R][M];
dfa[pat.charAt(0)][0] = 1;
for (int X = 0, j = 1; j < M; j++) {
// Compute dfa[][j].
for (int c = 0; c < R; c++) {
dfa[c][j] = dfa[c][X]; // Copy mismatch cases.
dfa[pat.charAt(j)][j] = j + 1; // Set match case.
X = dfa[pat.charAt(j)][X]; // Update restart state.
}
}
}
public int search(String txt) {
// Simulate operation of DFA on txt.
int i, j, N = txt.length(), M = pat.length();
for (i = 0, j = 0; i < N && j < M; i++) {
j = dfa[txt.charAt(i)][j];
}
if (j == M) {
return i - M; // found (hit end of pattern)
} else {
return N; // not found (hit end of text)
}
}
public static void main(String[] args) {
String pat = "babba";
String txt = "aaaaaaaaaaaabbaaababbaaaaababbaaaa";
int lastIndex = 0;
KMP kmp = new KMP(pat);
int offset = kmp.search(txt);
System.out.println("text: " + txt);
System.out.print("pattern: ");
while (lastIndex != txt.length()) {
for (int i = 0; i < offset; i++) {
lastIndex++;
match++;
}
count++;
}
System.out.println(pat);
System.out.println("count: " + count);
System.out.println("match: " + match);
}
}
我的代码在编译时效果很好,但是当我将String txt
属性更改为aaaaaaaaaaaabbaaababbaaaaababbaaaababba
之类的内容时,它会给我一个意外的负数计数值(同样,它需要大约30实际运行代码的秒数。)
我试图找到一个更好的计算事件的解决方案,我也想知道我的代码有什么问题,因为它只适用于某些情况。
答案 0 :(得分:1)
原因是你的循环条件。
while (lastIndex != txt.length())
您的问题字符串长度为38,偏移量为17
每个for循环lastIndex
增加17
在第三个for循环之后,它具有值51
这符合条件,循环继续
它只在可能导致负计数值的几个int溢出之后结束。
你也无法计算那样的事件。
kmp.search()
仅返回模式第一次出现的起始位置
例如
String txt = "aaaaaaaaaaaaaaaaababbaaaaaaaaaaaaa";
您的代码返回count = 2
。
解决方案是在每次搜索后拆分字符串,然后在模式后搜索子字符串。
KMP kmp = new KMP(pat);
int offset = kmp.search(txt);
while (offset != txt.length()) {
count++;
txt = txt.substring(offset+pat.length());
offset = kmp.search(txt);
}
System.out.println("count: " + count);
编辑:上面的代码仅适用于非重叠模式。
txt = txt.substring(offset+at.length());
需要更改为
txt = txt.substring(offset+1);
如果有重叠。