image.png

暴力匹配

  1. public class ViolenceMatch {
  2. public static void main(String[] args) {
  3. String str1="黑马程序员硅谷尚硅谷你好";
  4. String str2="尚硅谷";
  5. int index=violenceMatch(str1,str2);
  6. System.out.println("index="+index);
  7. }
  8. public static int violenceMatch(String str1,String str2)
  9. {
  10. char[]a= str1.toCharArray();
  11. char[]b=str2.toCharArray();
  12. int i=0;int j=0;
  13. while(i<a.length&&j<b.length)
  14. {
  15. if(a[i]==b[j])
  16. {
  17. ++i;++j;
  18. }
  19. else {
  20. i=i-j+1;j=0;
  21. }
  22. }
  23. if(j==b.length)
  24. {
  25. return i-j+1;
  26. }
  27. else {
  28. return -1;
  29. }
  30. }
  31. }

最坏时间复杂度O(nm),n是主串的长度,m是模式串的长度

KMP算法

移动位数=已匹配的字符数-对应的部分匹配值
时间复杂度O(n+m)
对算法的改进
将PM表的next数组右移一位,就可以直接查看部分匹配值。第一个元素用-1填充。Move=(j-1)-next[j]
子串比较指针右移:j=j-Move=j-((j-1)-next[j])=next[j]+1
这PM表的next数组整体加一。
next[j]数组的含义:在子串的第j个字符与主串发生失配时,则跳到子串的next[j]位置重新与主串当前位置进行比较。

next数组值推导
如果前后缀一个字符相等,k值是2,两个字符k值是3,n个相等k值是n+1
image.png
image.png

这段代码是为了计算出子串的next数组

  1. public static int[] kmpNext(String patternString)
  2. {
  3. //创建一个next数组保存部分匹配值
  4. int[]next=new int[patternString.length()];
  5. //如果字符串的长度为1,则部分匹配值就是0
  6. next[0]=0;
  7. for(int i=1,j=0;i<patternString.length();i++)
  8. {
  9. //当patternString.charAt(i)!=patternString.charAt(j),我们需要从next[j-1]获取新的j
  10. //直到我们发现有patternString.charAt(i)==patternString.charAt(j)成立才退出。这是KMP算法的核心
  11. while(j>0&&patternString.charAt(i)!=patternString.charAt(j))
  12. {
  13. j=next[j-1];
  14. }
  15. //当patternString.charAt(i)==patternString.charAt(j)成立时,部分匹配值+1
  16. if(patternString.charAt(i)==patternString.charAt(j))
  17. {
  18. j++;
  19. }
  20. next[i]=j;
  21. }
  22. return next;
  23. }