字符串子串求解(KMP算法)

引言

子串求解是面试中经常问到的算法问题,其方法有暴力匹配法、KMP方法

暴力匹配法

将设有一文本串S,其长度为sLen,已匹配字符串M,其长度为mLen。现需要求解M是否为S的子串,并返回M在S中第一次出现的首字符H位置。

利用暴力匹配法,很容易想到两层循环解决问题:
第一层循环:对S进行遍历,以H出现之前的所有字符为首字符对M进行匹配
第二层循环:一个字符为起点,对M进行匹配,成功结束所有循环,失败则退出并进入外层循环

public int getFirstLocation(String character ,String match){
        char[] characters = character.toCharArray();
        char[] matchs = match.toCharArray();
        for(int i=0;i<characters.length;i++)
            for(int j=i,k=0;k<matchs.length && j<characters.length;k++,j++) {
                if (characters[j] != matchs[k])
                    break;
                if(k==matchs.length-1)
                    return i;
            }
        return -1;
    }

KMP算法

KMP算法相较于暴力匹配法的优点在于,减少了不必要的回溯过程
其实现过程引入了next数组的概念,该数组记录了M匹配失败过程中的回退准则。
暴力匹配过程中匹配失败,程序会对下一个S字符进行匹配操作并将M匹配位置重新置于队头。但是KMP的方式有所不同,其通过next数组的指引,对M字符串的回退仅回退到必要的位置,其算法实现过程大致如下:

求解next数组

public int[] getNextArray(char[] matchs){
        int[] nextArray = new int[matchs.length];
        nextArray[0]=0;
        for(int i=1;i<nextArray.length;i++){
        		/**情形1*/
            if(matchs[i]==matchs[nextArray[i-1]])
                nextArray[i] = nextArray[i-1]+1;
            else
            	/**情形2*/
                getNext(matchs,nextArray,i,nextArray[i-1]);
        }
        for(int i=nextArray.length-1;i>0;i--)
            nextArray[i]=nextArray[i-1];
        nextArray[0]=-1;
        return nextArray;
    }

public int getNext(char[] matchs,int[] nextArray,int nLocation,int bLocation){
		/**利用字符串两端next段的相对对称性,左端的字符串必定与右端字符串相等*/
		/**左端首匹配必定存在对应的右端尾匹配*/
        if(matchs[nLocation]==matchs[nextArray[bLocation]])
            return nextArray[bLocation]+1;
        else {
            if(nextArray[bLocation]!=0)
                return getNext(matchs,nextArray,nLocation,nextArray[bLocation]);
            else
                return 0;
        }
    }

kmp匹配

 public int kmp(String character,String match){
        char[] matchs = match.toCharArray();
        char[] characters = character.toCharArray();
        int[] nextArray = getNextArray(matchs);
        int j=0,i=0;
        while (i<characters.length && j<matchs.length){
             /**
              * j指向位置-1时,此时未出现已配对字符
              * 配对字符位置至于队首
              * 被配对字符后移一位
              */
            if( j==-1 || characters[i]==matchs[j] ){
                i++;
                j++;
            }else {
                /**配对符位置回退*/
                j=nextArray[j];
            }
        }
        if(j==matchs.length)
            return i-j;
        else
            return -1;
    }
发布了28 篇原创文章 · 获赞 3 · 访问量 1602

猜你喜欢

转载自blog.csdn.net/qq_43044875/article/details/104143836