模式匹配 KMP

上代码:

next道理懂了,运行过程还是没琢磨明白。

第二个next是优化的算法,还没看懂。

 

package com.test;

public class Test {

	/**
	 * kmp算法,主串指针不回溯的一种算法。时间复杂度可以达到O(n+m)nm是串长度
	 * 关键是要解决:当匹配到模式串的某个字符,发生不匹配之后;主串指针如何向右移动。(next就是解决这个问题)
	 * next返回的是:
	 * 1数组的意义:
	 * 	每个元素代表模式串一个字符,表示当这个字符失配,而前面的字符都匹配时,“主串当前指针要和模式串中的第几个字符继续比较”。
	 * 2这个结果数组的计算方式是:
	 * 	找到模式串当前这个字符紧挨着它前面的连续几个字符和模式串开头连续几个字符是否相等,
	 * 	(1)没有匹配记录0,
	 * 	(2)有匹配记录开头连续几个字符的个数(或者这个连续串的下个下标)。
	 * 	(3)-1代表母串指针需要移动
	 * @author yfchenlei
	 * @date 2012-9-20
	 * @param str 主串
	 * @param sub 子串
	 * @param pos 主串开始位置
	 * @return 
	 */
	public static int kmpIndexOf(String str, String sub, int pos){
		int i = pos;
		int j = 0;
		int[] next = next2(sub);
		while(i < str.length() && j < sub.length()){
			if(j == -1 || str.charAt(i) == sub.charAt(j)){
				i++;
				j++;
			}else{
				j = next[j];
			}
		}
		if(j == sub.length()){
			return i - sub.length();
		}
		
		return -1;
	}
	/**
	 * next算法
	 * @param sub 模式串
	 * @return
	 */
	public static int[] next1(String sub){
		int len= sub.length();
		int[] next = new int[len];
		int i = 0;
		int j = 0;
		while(i < len){
			 next[i] = j -1;
			 if(j == 0 || sub.charAt(i) != sub.charAt(j - 1))
				 j = 0;
			 i++;
			 j++;
		}
		return next;
	}
	/**
	 * 优化next算法
	 * @param sub 模式串
	 * @return
	 */
	public static int[] next2(String sub){
		int[] next = new int[sub.length()];  
		next[0] = -1;  
		int i = 0;  
		int j = -1;  
		while (i < sub.length() - 1) {  
			if (j == -1 || sub.charAt(i) == sub.charAt(j)) {  
				i++;  
				j++;  
				if (sub.charAt(i) != sub.charAt(j)) {  
					next[i] = j;  
				} else {  
					next[i] = next[j];  
				}  
			} else {  
				j = next[j];  
			}  
		}  
		return next; 
	}
	
	public static void main(String[] args) {

	}
}

 。

### KMP算法无回溯模式匹配的实现与原理 #### 1. KMP算法的核心思想 KMP(Knuth-Morris-Pratt)算法是一种高效的字符串匹配算法,其核心在于通过预先计算的部分匹配表(通常称为`next`数组),避免了传统朴素模式匹配中指针的频繁回溯。这种特性使得KMP能够在最坏情况下达到时间复杂度 \(O(m+n)\),其中\(m\)为目标串长度,\(n\)为模式串长度[^1]。 #### 2. 部分匹配表(Next数组) 部分匹配表记录的是模式串前缀和后缀的最大重合长度。具体而言,对于模式串中的每一个位置,`next[i]`表示从该位置向前看,最长相等前后缀的长度。这一信息用于指导当发生不匹配时如何移动模式串的位置而无需回退目标串指针。 构建 `next` 数组的过程如下: ```python def compute_next(pattern): next_array = [0] * len(pattern) j = 0 # 前缀末尾索引 for i in range(1, len(pattern)): while j > 0 and pattern[j] != pattern[i]: j = next_array[j - 1] if pattern[j] == pattern[i]: j += 1 next_array[i] = j return next_array ``` 此函数利用双指针方法逐步填充 `next` 数组,确保即使遇到不匹配的情况也能快速找到合适的跳转点。 #### 3. 利用 Next 数组进行匹配 一旦有了完整的 `next` 数阵列,就可以高效地执行实际的字符串匹配操作: 以下是基于 `next` 的 KMP 查找过程代码示例: ```python def kmp_search(text, pattern): next_array = compute_next(pattern) matches = [] j = 0 # 模式串当前比较位置 for i in range(len(text)): while j > 0 and text[i] != pattern[j]: j = next_array[j - 1] if text[i] == pattern[j]: j += 1 if j == len(pattern): # 找到完全匹配 matches.append(i - j + 1) j = next_array[j - 1] # 继续寻找下一个可能的匹配 return matches ``` 在此过程中,每当字符对比失败时,并不会简单地退回至之前的状态重新开始;而是依据已经建立好的 `next` 数据调整继续尝试的位置,从而实现了所谓的“无回溯”。 #### 时间复杂度分析 尽管表面上看起来存在两个嵌套循环,但由于每次内部循环都会减少至少一步进展量(`j=next[j−1]`) ,因此整个流程仍保持线性级别效率即 \(O(m+n)\)[^2]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值