字符串匹配算法

字符串匹配算法

一串文本字符串String,一个模式字符串pattern,字符串匹配算法的工作就是检测String中是否含有对应模式字符串。然后返回模式字符串pattern在文本字符串String所在的位置,如果不存在返回-1。或者返回一个布尔值代表这个String是否含有对应模式字符串。

暴力求解

暴力求解即从第0个字符开始互相匹配,直到存在不同的字符

在这里插入图片描述

前移一个字符继续进行匹配
在这里插入图片描述

直到存在完全一致的字符串,返回字符串所在序号或者true

在这里插入图片描述

或者直到文本字符串末尾也不存在所求字符串返回false或者-1

在这里插入图片描述

暴力求解代码

public class ExhaustiveAlgorithm {
	public int isMatch(String s, String p) {
		char[] chars = s.toCharArray();
		char[] charp = p.toCharArray();
		int lengths = chars.length;
		int lengthp = charp.length;
		for(int i = 0; i < lengths - lengthp + 1; i++){
			boolean flag = true;
			for(int j = 0; j < lengthp; j++){
				if(chars[i+j] == charp[j])
					continue;
				else{
					flag = false;
					break;
				}
			}
			if(flag){
				return i;
			}
		}
		return -1;
	}
}

设文本字符串的长度是m,模式字符串长度是n,暴力求解的时间复杂度粗略估计是O(mn)的样子,效率相当低。主要是逐个后移太消耗时间。

KMP算法

KMP算法创造了一种最长前后缀数的概念。
在这里插入图片描述

即最长的相等前后缀长度

KMP算法原理如下:
当匹配到不同字符时,如图:
在这里插入图片描述

并不是如同暴力求解,仅向前挪动一格。而是已匹配过的字符串中的最长前后缀数
在这里插入图片描述
来跳动较多格,使后缀和前缀对齐,避免重复计算相同的字符串
在这里插入图片描述

因此只需要次数为文本字符串长度的比较,即时间复杂度为O(n)

KMP算法代码

public class KMPAlgorithm {
	public int isMatch(String s, String p){
		char[] schars = s.toCharArray();
		char[] pchars = p.toCharArray();
		int slength = s.length();
		int plength = p.length();
		int[] fixCount = new int[plength];
		fixCount[0] = -1;
		if(plength == 2)
			fixCount[1] = 0;
		for (int i = 2; i < plength; i++){
			fixCount[i] = computeFixCount(pchars, plength, i);
		}
		int position = 0;
		for(int i = 0; i < slength; i++){
			if(position==-1){
				position = 0;
				continue;
			}
			if(schars[i] == pchars[position]){
				if(position == plength-1)
					return i-position;
				else{
					position++;
					continue;
				}
			}else{
				i--;
				position = fixCount[position];
			}
		}
		return -1;
	}
	
	public static int computeFixCount(char[] pchars, int plength, int fixLength){
		for(int i = fixLength ; i > 0; i--){
			boolean flag = true;
			for(int j = 0; j < i; j++){
				if(pchars[j] == pchars[plength-fixLength+j])
					continue;
				else{
					flag = false;
					break;
				}
			}
			if(flag){
				return i;
			}
		}
		return 0;
	}
	public static void main(String[] args){
		KMPAlgorithm kmpAlgorithm = new KMPAlgorithm();
		String sString = "paTTmSHoYEIsEmpaHyASXTlPaVnkGpJLDPGfcbGHASPiQfjniuKWqtIbUARDLtW";
		String pString = "nkGpJLDPGfcbGHASPiQfjniu";
		int index = 26;
		//boolean bool = scanner.nextBoolean();
		System.out.println(kmpAlgorithm.isMatch(sString, pString) + " " +  index);
	}
	

}

java中的indexOf方法

java中的默认实现是java.lang.String.indexOf(String),看看这个方法是怎么做的:

        //source是匹配的字符串
        //sourceOffset是偏移量
        //sourceCount是需要计算的总数
        //target是模式字符串
        //targetOffset是模式字符串的便宜了
        //targetCount是模式字符串的总数
        //fromIndex是从哪个序号开始搜索
        static int indexOf(char[] source, int sourceOffset, int sourceCount,
            char[] target, int targetOffset, int targetCount,
            int fromIndex) {
        //如果启动序号比文本字符串总数还大
        if (fromIndex >= sourceCount) {
            //如果模式字符串长度为0,就返回起始匹配的字符序号,因为为0就任意满足嘛
            //同时为了确保数组不越界,最大只能返回sourceCount。如果模式长度不为0,那就返回-1
            return (targetCount == 0 ? sourceCount : -1);
        }
        //确保启动的序号非负
        if (fromIndex < 0) {
            fromIndex = 0;
        }
        //如果模式字符串长度是0,就返回起始匹配的字符序号
        if (targetCount == 0) {
            return fromIndex;
        }
        //第一个模式字符
        char first = target[targetOffset];
        //文本字符串的最大序号
        int max = sourceOffset + (sourceCount - targetCount);
        
        //起始字符是文本字符的偏移量加上启动序号,i要小于最大的文本字符串序号
        for (int i = sourceOffset + fromIndex; i <= max; i++) {
            /* Look for first character. */
            //找到和第一个模式字符串相等的文本字符串中的字符
            if (source[i] != first) {
                while (++i <= max && source[i] != first);
            }
            
            /* Found first character, now look at the rest of v2 */
            //进行后续的比较
            if (i <= max) {
                int j = i + 1;
                int end = j + targetCount - 1;
                for (int k = targetOffset + 1; j < end && source[j]
                        == target[k]; j++, k++);
                if (j == end) {
                    /* Found whole string. */
                    return i - sourceOffset;
                }
            }
        }
        //没有找到返回-1
        return -1;
    }

看得出java中的indexOf基本上等同于暴力搜索

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值