单模式串字符串匹配
给定单个字符串S(长度m),查找目标模式串pattern(长度n)。 这个问题常见的会是采用朴素匹配,
朴素匹配实际为暴力匹配(BrueForce)本文讲述的是KMP算法, 维基百科 维基百科里面讲述的较详细, 就如下几个重点本文讲述下。
KMP相对朴素匹配
本质上是在朴素匹配上做了一个剪枝, 朴素匹配在S串上依次对pattern串进行比较,复杂度O(m*n), 而KMP逻辑会进行跳过,复杂度O(m+n)。
KMP关键点
- 理解字符串的真前缀(proper preffix)、真后缀(proper suffix)。不包含本身的前缀或者后缀,如snake的真前缀s,sn,sna,snak。
- 真前缀和真后缀的相同意味着什么,这个理解清楚了就是KMP对比跳过的剪枝逻辑。理解见代码
- next()函数表及实现
- 根据next()函数遍历目标串S
代码演示:
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
| import java.util.ArrayList; import java.util.Arrays; import java.util.List;
public class C10StrPattern {
private static int[] genNextArray(String pattern) {
if (pattern == null || pattern.length() == 0) { return new int[]{}; } int[] result = new int[pattern.length()]; result[0] = 0; for (int i = 1; i < pattern.length(); i++) { if (pattern.charAt(i) == pattern.charAt(result[i - 1])) { result[i] = result[i - 1] + 1; } else { result[i] = 0; }
} return result; }
public static List<String> findPosition(String str, String pattern) { List<String> result = new ArrayList<>(); if (str == null || pattern == null || str.length() == 0 || pattern.length() == 0) { return result; } int[] next = genNextArray(pattern); int i = 0, start = 0; while (i < str.length()) { for (int j = 0; j < pattern.length(); j++) { if (i + j > str.length() - 1) { return result; } if (str.charAt(i + j) == pattern.charAt(j)) { if (j == 0) { start = i; } if (j == pattern.length() - 1) { result.add(String.format("%s-%s", start, i + j)); i++; break; } } else { i = i + next[j] + 1; break; } }
}
return result; }
public static void main(String[] args) { System.out.println(Arrays.toString(findPosition("abababca", "aba").toArray())); } }
|
代码文件:C10StrPattern.java
总结
- “KMP关键点” 前两点是理解关键,后两点是实现
- AC自动状态机本质来说是KMP的一个多模式演变, 多模串仅一个分支的话就是KMP
机器在于运动,大脑也需要不断思考运作才能避免秀逗
版权声明:本文为博主原创文章,未经允许不得转载。