KMP快速字符串匹配

KMP匹配算法

1.简介

简单匹配算法虽然易于实现,但是时间复杂度比较高。Knuth、Morris和Pratt发明了快速字符串匹配算法,算法以这三个人的名字命名,即KMP算法。

KMP算法的想法是,设法利用这个已知信息,不要把"搜索位置"移回已经比较过的位置,继续把它向后移,这样就提高了效率。

2.match表

[1].举例:

字符串: bread

前缀:b,br,bre,brea

后缀:read,ead,ad,d

在这里插入图片描述

生成方式:

match[0] = -1;

从i = 1遍历数组到i = pattern.length - 1

每次遍历记录j = match[i-1]

让j = match[j],此处使用while循环,循环条件是j >= 0 && 字符 i != j+1

如果字符i == j+1,match[i] = ++j;

如果i != j ,match[i] = -1

匹配方式:

主串指针i,子串指针j

while(指针i和指针j没有越界)

如果指针i和指针j对应字符相等,i++,j++;

不相等时,如果指针j不在0的位置,j = match[j - 1] + 1

否则指针i后移

循环结束后,如果指针j == 子串长度,表示找到了子串

返回i - 子串长度,否则返回-1

public class KMP {
	/**
	 * match数组
	 */
	private  int [] match;
	
	/**
	 * 主串
	 */
	private  String mainStr;

	/**
	 * 子串
	 */
	private  String subStr;
	
	
	/**
	 * 构造器
	 * @param mainStr 主串
	 * @param subStr 子串
	 */
	public KMP(String mainStr,String subStr) {
		try {
			this.subStr = subStr;
			this.mainStr = mainStr;
			match = new int[subStr.length()];
			initMatch();//初始化match表
		}
		catch (Exception e) {
			// TODO: handle exception
			System.out.println("字符串非法!!!");
			System.exit(0);//终止运行
		}
	}
	
	/**
	 * 初始化match表中的值
	 */
	public void initMatch() {
		int len = subStr.length();
		
		match[0] = -1;
		for(int i = 1; i < len; i++) {
			//获得当前位置的前一个字符的部分匹配值
			int j = match[i - 1];
			
			while(j >= 0 && subStr.charAt(i) != subStr.charAt(j+1)) {
				j = match[j];
			}
			if(subStr.charAt(i) == subStr.charAt(j+1)) {
				match[i] = j + 1;
			}
			else {
				match[i] = -1;
			}
		}
	}
	
	/**
	 * 匹配字符串,找到子串,返回子串出现的位置
	 * 否则返回-1
	 * @return 
	 */
	public int getMatchResult() {
		try {
			int mainLength = mainStr.length();
			int subLength = subStr.length();
			//如果主串长度小于子串长度,不可能匹配到
			if(mainLength < subLength) {
				return -1;
			}
			
			int i = 0;//主串指针
			int j = 0;//子串指针
			while(i < mainLength && j < subLength) {
				if(mainStr.charAt(i) == subStr.charAt(j)) {
					i++;
					j++;
				}
				else if(j != 0) {
					j = match[j - 1] + 1;
				}
				else {
					i++;
				}
			}
			return (j == subLength) ? i - subLength : -1;
			
		}
		//如果捕捉到异常,参与比较的两个字符串不合法
		catch (Exception e) {
			System.out.println("参与比较的字符串非法!!!");
		}
		return -1;
	}
	
	/**
	 * 在主串中找到子串出现的所有位置,找到返回位置数组
	 * 否则返回null
	 * @return
	 */
	public int [] getMatchValueArray() {
		try {
			int mainLength = mainStr.length();
			int subLength = subStr.length();
			//如果主串长度小于子串长度,不可能匹配到
			if(mainLength < subLength) {
				return null;
			}
			
			int i = 0;//主串指针
			int j = 0;//子串指针
			while(i < mainLength && j < subLength) {
				if(mainStr.charAt(i) == subStr.charAt(j)) {
					i++;
					j++;
				}
				else if(j != 0) {
					j = match[j - 1] + 1;
				}
				else {
					i++;
				}
			}
		}
		//如果捕捉到异常,参与比较的两个字符串不合法
		catch (Exception e) {
			System.out.println("参与比较的字符串非法!!!");
		}
		return null;
	}
	
	public  int[] getMatch() {
		return match;
	}

	public  void setMatch(int[] match) {
		this.match = match;
	}

	public  String getMainStr() {
		return mainStr;
	}

	public void setMainStr(String mainStr) {
		this.mainStr = mainStr;
	}

	public String getSubStr() {
		return subStr;
	}

	public void setSubStr(String subStr) {
		this.subStr = subStr;
	}
}
	public void setMainStr(String mainStr) {
		this.mainStr = mainStr;
	}

	public String getSubStr() {
		return subStr;
	}

	public void setSubStr(String subStr) {
		this.subStr = subStr;
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Phil Jackson

你的鼓励就是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值