• KMP算法学习


    (1) 参考网址:

    KMP算法:   http://www.cnblogs.com/dolphin0520/archive/2011/08/24/2151846.html  

            --- 用递推思想和直接法两种方式求解next数组

    KMP学习心得:   http://www.java3z.com/cwbwebhome/article/article19/res023.html?id=3737

           --- 当一个字符串以0为起始下标时,next[i]可以描述为"不为自身的最大首尾重复子串长度"。

    KMP字符串模式匹配中模式函数:  http://www.java3z.com/cwbwebhome/article/article19/re022.html?id=3731

           --- 详细讲解了next数组的求解方法【next数组求解的改进版本】

    (2) 经典总结:

    一、怎么求串的模式值next[n]
    定义:
    (1)next[0]= –1  意义:任何串的第一个字符的模式值规定为-1。
    (2)next[j]= –1   意义:模式串T中下标为j的字符,如果与首字符相同,且j的前面的1~k个字符与开头的1~k个字符不等或者相等但
                  T[k]==T[j]
    (1≤k<j)。 如:T=”abCabCad” 则 next[6]=-1,因T[3]=T[6]  bCa

    (3)next[j]=k      意义:模式串T中下标为j的字符,如果j的前面k个字符与开头的k个字符相等,且T[j] != T[k] (1≤k<j)。
                   即T[0]T[1]T[2]...T[k-1]== T[j-k]T[j-k+1]T[j-k+2]…T[j-1] 且T[j] != T[k].(1≤k<j);
    (4)next[j]=0        意义:除(1)(2)(3)的其他情况

    二、next 函数值究竟是什么含义

    设在字符串S中查找模式串T,若S[m]!=T[n],那么,取T[n]的模式函数值next[n],
    1. next[n]= -1 表示S[m]和T[0]间接比较过了,不相等,下一次比较 S[m+1] 和T[0]
    2. next[n]=0 表示比较过程中产生了不相等,下一次比较 S[m] 和T[0]。
    3. next[n]= k >0 但k<n, 表示,S[m]的前k个字符与T中的开始k个字符已经间接比较相等了,下一次比较S[m]和T[k]相等吗?
    4. 其他值,不可能。

    (3) 代码实现 【参考书籍:《数据结构与算法 Java语言描述》 邓俊辉 著】

    原书代码:【略有改动】

    package dsa;
    /*
     * 串模式匹配:KMP算法
     */
    public class PM_KMP {
    
    	public static void main(String[] args) {
    		System.out.println(PM("ababacab", "aca"));
    	}
    
    	public static int PM(String T, String P) {// KMP算法
    		int[] next = BuildNextImproved(P);// 构造next[]表
    		int i = 0;// 主串指针
    		int j = 0;// 模式串指针
    		while (j < P.length() && i < T.length()) {// 自左向右逐个比较字符
    			ShowProgress(T, P, i - j, j);
    			ShowNextTable(next, i - j, P.length());
    			System.out.println();
    			if (0 > j || T.charAt(i) == P.charAt(j)) {// 若匹配,或P已移出最左侧(提问:这两个条件能否交换次序?)
    				i++;
    				j++;// 则转到下一对字符
    			} else
    				// 否则
    				j = next[j];// 模式串右移(注意:主串不用回退)
    		}// while
    		return (i - j);
    	}
    
    	protected static int[] BuildNext(String P) {// 建立模式串P的next[]表
    		int[] next = new int[P.length()];// next[]表
    		int j = 0;// “主”串指针
    		int t = next[0] = -1;// “模式”串指针
    		while (j < P.length() - 1)
    			if (0 > t || P.charAt(j) == P.charAt(t)) {// 匹配
    				j++;
    				t++;
    				next[j] = t;// 此句可以改进...
    			} else
    				// 失配
    				t = next[t];
    		for (j = 0; j < P.length(); j++)
    			System.out.print("\t" + P.charAt(j));
    		System.out.print("\n");
    		ShowNextTable(next, 0, P.length());
    		return (next);
    	}
    
    	protected static int[] BuildNextImproved(String P) {// 建立模式串P的next[]表(改进版本)
    		int[] next = new int[P.length()];
    		;// next[]表
    		int j = 0;// “主”串指针
    		int t = next[0] = -1;// “模式”串指针
    		while (j < P.length() - 1)
    			if (0 > t || P.charAt(j) == P.charAt(t)) {// 匹配
    				j++;
    				t++;
    				next[j] = (P.charAt(j) != P.charAt(t)) ? t : next[t];// 注意此句与未改进之前的区别
    			} else
    				// 失配
    				t = next[t];
    		for (j = 0; j < P.length(); j++)
    			System.out.print("\t" + P.charAt(j));
    		System.out.print("\n");
    		ShowNextTable(next, 0, P.length());
    		return (next);
    	}
    
    	protected static void ShowNextTable(int[] N, int offset, int length) {// 显示next[]表,供演示分析
    		int i;
    		for (i = 0; i < offset; i++)
    			System.out.print("\t");
    		for (i = 0; i < length; i++)
    			System.out.print("\t" + N[i]);
    		System.out.print("\n\n");
    	}
    
    	protected static void ShowProgress(// 动态显示匹配进展
    			String T,// 主串
    			String P,// 模式串
    			int i,// 模式串相对于主串的起始位置
    			int j)// 模式串的当前字符
    	{
    		int t;
    		System.out.println("-------------------------------------------");
    		for (t = 0; t < T.length(); t++)
    			System.out.print("\t" + T.charAt(t));
    		System.out.print("\n");
    		if (0 <= i + j) {
    			for (t = 0; t < i + j; t++)
    				System.out.print("\t");
    			System.out.print("\t|");
    		}
    		System.out.println();
    		for (t = 0; t < i; t++)
    			System.out.print("\t");
    		for (t = 0; t < P.length(); t++)
    			System.out.print("\t" + P.charAt(t));
    		System.out.print("\n");
    		System.out.println();
    	}
    }

    精简代码:

    package dsa.me;
    
    public class Kmp {
    
    	public static void main(String[] args) {
    		System.out.println(kmp("ababa", "bab"));
    		System.out.println(kmp("ababa", "bba"));
    	}
    
    	// KMP算法
    	public static int kmp(String T, String P) {
    		int next[] = buildeNextImproved(P);
    		int i = 0;
    		int j = 0;
    		while (i < T.length() && j < P.length()) {// 一定要限制它们在范围内,不然会报错
    			if (j < 0 || T.charAt(i) == P.charAt(j)) {// 匹配,i和j都向右移动,j<0(j=-1)
    				i++;
    				j++;
    			} else {// 不匹配,只要移动j,i不要回溯
    				j = next[j];
    			}
    		}
    		if (j >= P.length())
    			return (i - j);
    		else
    			return -1;
    	}
    
    	// 求next数组
    	public static int[] buildeNext(String P) {
    		int[] next = new int[P.length()];
    		int j = 0;
    		int t = -1;// 初始值是-1
    		next[0] = -1;
    		while (j < P.length() - 1) {
    			if (t == -1 || P.charAt(t) == P.charAt(j)) {// 匹配---如果在j这里不存在首尾相同的字符串,那么next[j]就会等于0
    				t++;
    				j++;
    				next[j] = t;// 由这里看出while条件中j不能等于P.length()-1
    			} else {// 不匹配
    				t = next[t];
    			}
    		}
    		return next;
    	}
    
    	// 求next数组的改进版本
    	public static int[] buildeNextImproved(String P) {
    		int[] next = new int[P.length()];
    		int j = 0;
    		int t = -1;// 初始值是-1
    		next[0] = -1;
    		while (j < P.length() - 1) {
    			if (t == -1 || P.charAt(t) == P.charAt(j)) {// 匹配---如果在j这里不存在首尾相同的字符串,那么next[j]就会等于0
    				t++;
    				j++;
    				next[j] = (P.charAt(j) != P.charAt(t)) ? t : next[t];// 改进的地方
    			} else {// 不匹配
    				t = next[t];
    			}
    		}
    		return next;
    	}
    
    }

    附上参考书籍的对应章节pdf下载地址:http://115.com/file/dpkg6art#数据结构与算法(Java_描述).pdf

  • 相关阅读:
    如何设置某些动作在凌晨12点时自动更新
    箭头式导航
    解决遮罩层下面的内容仍可滑动问题
    时间戳转换时间
    折扣显示
    纯css自定义checkbox和radio的样式
    布局补充
    文字水平垂直居中
    Spring_自动组件扫描和 基于注解配置bean
    Spring_JDBC连接
  • 原文地址:https://www.cnblogs.com/yinger/p/2592072.html
Copyright © 2020-2023  润新知