字符串之字符串匹配

题目描述:处理字符串操作相关问题时,常见的做法是从字符串尾部开始编辑,从后往前逆向操作。

                这么做的原因是因为字符串的尾部往往有足够空间,可以直接修改而不用担心覆盖字符串前面的数据。

题解:对于字符串查找问题,可使用双重 for 循环解决,效率更高的则为 KMP 算法。双重 for 循环的使用较有讲究,因为这里需要考虑目标字符串比源字符串短的可能。对目标字符串的循环肯定是必要的,所以可以优化的地方就在于如何访问源字符串了。简单直观的解法是利用源字符串的长度作为 for 循环的截止索引,这种方法需要处理源字符串中剩余长度不足以匹配目标字符串的情况,而更为高效的方案则为仅遍历源字符串中有可能和目标字符串匹配的部分索引。

【朴素字符串匹配算法】:对主串的每一个字符作为子串开头,与要匹配的字符串进行匹配。对主串做大循环,每个字符开头做T长度的小循环,知道匹配成功或便利完成。

源码:

 1 public class Solution {
 2     public int strStr(String source, String target) {
 3         if (source == null && target == null) return 0;
 4         if (source == null) return -1;
 5         if (target == null) return 0;
 6 
 7         for (int i = 0; i < source.length() - target.length() + 1; i++) {
 8             int j = 0;
 9             for (; j < target.length(); j++) {
10                 if (source.charAt(i+j) != target.charAt(j)) break;
11             }
12             if (j == target.length()) 
13             return i;
14         }
15 
16         return -1;
17 } 18

 

双重for循环,时间复杂度最坏情况下为O((n-m)*m).(n为主串长度,m为子串长度)

【KMP模式匹配算法】:i表示主串当前位置下标,j表示子串当前位置下标;进行匹配时,i值不回溯,即不可以变小,j值变化的关键在于T串的结构中是否有重复,取值的多少取决于当前字符之前的串的前后缀的相似度。

核心:求next数组,该数组中存储的是T串各个位置的j值的变化。next长度=T串长度

KMP模式匹配源码:

 

 1 /*返回next数组*/
 2 public static int[] get_Next(String target){
 3         int[] next = new int[target.length() ];// 声明一个长度为子串长度的数组
 4         char[] tar = target.toCharArray();// 将字符串转化为一个字符串数组
 5         int len = target.length(); //子串长度
 6         int i = 1;
 7         int j = 0;
 8         next[0] = -1; 
 9         while( i < len ){
10             if (j == 0 || tar[i-1] == tar[j-1]){//target[i]表示后缀的单个字符;target[j]表示前缀的单个字符
11                 
12                 ++j;                
13                 next[i]=j-1;
14                 i++;
15                 
16             }else{
17                 j = next[j];//若字符不相同,则j值回溯
18             }
19             
20         }
21         return next;
22     }
 1 /*KMP匹配,《大话数据结构》方法*/
 2 public static void StringMatchbyKMP2(String source, String target, int[] next){
 3         char[] ch1 = source.toCharArray();
 4         char[] ch2 = target.toCharArray();
 5         int i = 0,j = 0;  //i控制ch1,j控制ch2;
 6         for(;i<ch1.length; ) {
 7             if(ch1[i]==ch2[j]) {//匹配就自动递增,往后匹配。
 8                 if(j==ch2.length-1) {
 9                     System.out.println(i-ch2.length+1);
10                     break;
11                 }
12                 j++;
13                 i++;
14             }
15             else if(j==0) {
16                  i++;
17             }
18             else {
19                 j = next[j]; //j退回合适的位置,i值不变
20             }
21         }
22 }

时间复杂度最坏情况下为O(n+m).{get_next方法:O(m);KMP匹配:for循环时间复杂度为O(n)}

  

 

posted @ 2016-02-28 14:51  MeTeor_Lzz  阅读(176)  评论(0)    收藏  举报