子字符串查找或匹配(暴力法,KMP)
字符串的一种基本操作就是子字符串的查找:给定一个长度为M的文本和一个长度为M的模式(pattern)字符串,在文本中找到一个和该模式相符的子字符串。通常情况下扩展为
- 找出文本中所有与该模式相符的子字符串
- 统计该模式在文本中出现的次数;
- 找出上下文(和该模式相符的子字符串周围的文字)的算法
解决此类问题通用的方法有
1.暴力子字符串查找法
基本思想:定义指针i跟踪文本txt,另一个指针j跟踪模式。对于每个i,代码首先将j重置为0,并不断将它增大,直至找到一个不匹配的字符break;更新到下一个i,j重置。直到完全匹配(j==N)return i;或者全部文本遍历完成(return -1;)。//主函数 public static void main(String[] args) { String txt = "ABACADABRACDEF"; String pat = "CDEF"; Solution so = new Solution(); System.out.println(so.searchByForce(txt, pat)); System.out.println(so.searchByForceCopy(txt, pat)); } /*************************************/ //暴力法1:时间复杂度-O(NM) public int searchByForce(String txt,String pat){ int M = txt.length(); int N = pat.length(); for(int i=0;i<=M-N;i++){ int j; for(j=0;j<N;j++) if(txt.charAt(i+j)!=pat.charAt(j)) break; if(j==N) return i; } return -1; }
另一种暴力法实现被称为显式回退。
定义指针i跟踪文本,指针j跟踪模式;在指针文本的i和模式的j相匹配时(j++)i指向下一个txt;直到模式所有的匹配完成,j=N,返回查找成功,返回i-N+1;或者不相匹配时,i回退到i-=j,j重置为0。//暴力法另一种实现 public int searchByForceCopy(String txt,String pat){ int i,M = txt.length(); int j,N = pat.length(); for(i=0,j=0;i<M&&j<N;i++){ if(txt.charAt(i)==pat.charAt(j)) j++; else{ i-=j; j=0; } if(j==N) return i-N+1; } return -1; }
KMP(Kunth-Morris-Pratt子字符串查找算法)
Kunth-Morris-Pratt发明的算法的基本思想是:当出现不匹配时,就能知晓一部分文本的内容(因为在二次匹配失败之前它们已经和模式相匹配)。我们可以利用这些信息避免将指针回退到所有这些已知的字符之前。