zoukankan      html  css  js  c++  java
  • 数据结构与算法-串

    串及其匹配

    串或字符串属于线性结构,结构简单,规模庞大,元素重复率高

    • 相关术语:
    • 接口:

    • 测评标准
      有效涵盖成功匹配情况的一种简便策略是,随机选取文本串T,并从T中随机取出长度为m的子串作为模式串P。

    蛮力算法

    原理


    实现

    package com.atguigu.string;
    /**
     * @anthor shkstart
     * @create 2020-08-16 8:57
     */
    public class brute extends Str{
    	public static int match1(char[] P, char[] T){
    		int n = P.length;
    		int m = T.length;
    		int i = 0;
    		int j = 0;
    		while (j < m && i < n){
    			if (T[i] == P[j]){
    				i++;
    				j++;
    			} else {
    				i -= j - 1;
    				j = 0;
    			}
    		}
    		return i - j;
    	}
    	public static int match2(char[] P, char[] T){
    		int n = P.length;
    		int m = T.length;
    		int i = 0;
    		int j = 0;
    		for (;i < n - m;i++){
    			for (;j < m;j++){
    				if (T[i+j] != P[j]) break;
    			}
    			if ( j >= m) break;
    		}
    		return i;
    	}
    }
    

    效率

    KMP算法

    分析上面的方法:

    • 发现问题在于这里存在大量的局部匹配:每一轮的m次比对中,仅最后一次可能失配。而一旦发现失配,文本串、模式串的字符指针都要回退,并从头开始下一轮尝试。没有很好的利用已经掌握的信息。

    • 利用以往的成功比对所提供的信息(记忆),不仅可避免文本串字符指针的回退,而且可使模式串尽可能大跨度地右移

    next表


    • 满足条件:P[0, t) = T[i - t, i) = P[j - t, j)
    • 原理
    • 实现
    public int[] buildNext1(char[] P){
    	int m = P.length;
    	int j = 0;
    	int[] N = new int[m];
    	int t = N[0] = -1;
    	while (j < m-1){
    		if (0 > t || P[j] == P[t]){
    			j++;
    			t++;
    			N[j] = t;
    		} else {
    			t = N[t];
    		}
    	}
    	return N;
    }
    public int[] buildNext2(char[] P){
    	int m = P.length;
    	int j = 0;
    	int[] N = new int[m];
    	int t = N[0] = -1;
    	while (j < m-1){
    		if (0 > t || P[j] == P[t]){
    			j++;
    			t++;
    			N[j] = (P[j] != P[t] ? t:N[t]);
    		} else {
    			t = N[t];
    		}
    	}
    	return N;
    }
    

    实现

    package com.atguigu.string;
    /**
     * @anthor shkstart
     * @create 2020-08-16 8:57
     */
    public class Kmp extends Str{
    	public int match(char[] P, char[] T){
    		int[] next = buildNext1(P);
    		int n = P.length;
    		int m = T.length;
    		int i = 0;
    		int j = 0;
    		while (j < m && i < n){
    			if (T[i] == P[j]){
    				i++;
    				j++;
    			} else {
    				j = next[j];
    			}
    		}
    		return i - j;
    	}
    	public int[] buildNext1(char[] P){
    		int m = P.length;
    		int j = 0;
    		int[] N = new int[m];
    		int t = N[0] = -1;
    		while (j < m-1){
    			if (0 > t || P[j] == P[t]){
    				j++;
    				t++;
    				N[j] = t;
    			} else {
    				t = N[t];
    			}
    		}
    		return N;
    	}
    	public int[] buildNext2(char[] P){
    		int m = P.length;
    		int j = 0;
    		int[] N = new int[m];
    		int t = N[0] = -1;
    		while (j < m-1){
    			if (0 > t || P[j] == P[t]){
    				j++;
    				t++;
    				N[j] = (P[j] != P[t] ? t:N[t]);
    			} else {
    				t = N[t];
    			}
    		}
    		return N;
    	}
    }
    

    实例


    BM算法

    原理

    KMP算法的思路可概括为:当前比对一旦失配,即利用此前的比对(无论成功或失败)所提 供的信息,尽可能长距离地移动模式串。事先根据模式串预测出所可能出现的失配情况,并将这些信息 “浓缩”为一张next表。而BM算法一旦局部失配,这里不再是机械地令i += 1并在下一字符处重新对齐,而是采用了两种启发式策略确定最大的安全移动距离



    坏字符策略

    • 快速排序不能对齐的位置

      移动情况:从右至左,一旦不匹配.从右开始找与x匹配的数,然后移动;或者太靠右,只移动一位
    • 构建bc表
    public int[] buildBc(char[] P){
    	int[] bc = new int[256];
    	for (int j = 0;j < 256;j++) bc[j] = -1;
    	for (int m = P.length,j = 0;j < m;j++){
    		bc[P[j]] = j;
    	}
    	return bc;
    }
    

    好后缀策略

    • 成功的对比
      坏字符策略仅利用了此前(最后一次)失败比对所提供的“教训”。而实际上在此之前,还做过一系列成功的比对,而这些“经验”却被忽略了
    • 分析

      对齐的情况:
      已经发现w与U一直都对齐,直到x与y不同
      需要从在p中从右向左找到一个子串能够满足v(k)=u且k处与J处不相等
      如果不存在,则从p的所有前缀中找与某一后缀最匹配长度的
    • gs、ss表的构建

      gs表每个位置对应,应该移动多少位;其中的gs[10] = 6可理解为:一旦在P[10] = 'P'处发生失配,则应将模式串P右移6个字符,即用P[10 - 6] = P[4] = '□'对准文本串T的失配字符,然后启动下一轮比对
      ss表对于任一整数j Î [0, m),在P[0, j]的所后缀中,考查那些与P的某一后缀匹配者。若将其中的最长者记作MS[j],则ss[j]就是该串的长度|MS[j]|。


    public int[] buildGS(char[] P){
    	int[] ss = buildSS(P);
    	int m = P.length;
    	int[] gs = new int[m];
    	for (int j = 0; j < m;j++) gs[j] = m;
    	for (int i = 0,j = m-1;j > 0;j--){
    		if (j + 1 == ss[j]){
    			while (i < m - j - 1){
    				gs[i++] = m - j -1;
    			}
    		}
    	}
    	for (int j = 0;j < m-1;j++){
    		gs[m - ss[j] - 1] = m-j - 1;
    	}
    	return gs;
    }
    public int[] buildSS(char[] P){
    	int m = P.length;
    	int[] ss = new int[m];
    	ss[m-1] = m;
    	for (int lo = m-1,hi = m - 1,j = lo - 1;j >= 0;j--){
    		if ((lo < j) && (ss[m - hi + j -1] <= j - lo)){
    			ss[j] = ss[m - hi +j -1];
    		} else {
    			hi = j;
    			lo = Math.min(lo,hi);
    			while ((0 <= lo) && (P[lo] == P[m - hi + lo -1])){
    				lo--;
    			}
    			ss[j] = hi -lo;
    		}
    	}
    	return ss;
    }
    

    java实现

    package com.atguigu.string;
    /**
     * @anthor shkstart
     * @create 2020-08-16 8:57
     */
    public class Bm extends Str{
    	public int match(char[] P, char[] T){
    		int[] bc = buildBc(P);
    		int[] gs = buildGS(P);
    		int i = 0;
    		while (T.length >= i + P.length){
    			int j = P.length - 1;
    			while (P[j] == T[i+j]){
    				if (0 > --j) break;
    			}
    			if (0 > j){
    				break;
    			} else {
    				i += Math.max(gs[j],j - bc[T[i+j]]);
    			}
    		}
    		return i;
    	}
    	public int[] buildBc(char[] P){
    		int[] bc = new int[256];
    		for (int j = 0;j < 256;j++) bc[j] = -1;
    		for (int m = P.length,j = 0;j < m;j++){
    			bc[P[j]] = j;
    		}
    		return bc;
    	}
    	public int[] buildGS(char[] P){
    		int[] ss = buildSS(P);
    		int m = P.length;
    		int[] gs = new int[m];
    		for (int j = 0; j < m;j++) gs[j] = m;
    		for (int i = 0,j = m-1;j > 0;j--){
    			if (j + 1 == ss[j]){
    				while (i < m - j - 1){
    					gs[i++] = m - j -1;
    				}
    			}
    		}
    		for (int j = 0;j < m-1;j++){
    			gs[m - ss[j] - 1] = m-j - 1;
    		}
    		return gs;
    	}
    	public int[] buildSS(char[] P){
    		int m = P.length;
    		int[] ss = new int[m];
    		ss[m-1] = m;
    		for (int lo = m-1,hi = m - 1,j = lo - 1;j >= 0;j--){
    			if ((lo < j) && (ss[m - hi + j -1] <= j - lo)){
    				ss[j] = ss[m - hi +j -1];
    			} else {
    				hi = j;
    				lo = Math.min(lo,hi);
    				while ((0 <= lo) && (P[lo] == P[m - hi + lo -1])){
    					lo--;
    				}
    				ss[j] = hi -lo;
    			}
    		}
    		return ss;
    	}
    }
    

    效率


    单次比对成功的概率,是决定串匹配算法时间效率的一项关键因素。对于同一算法,计算时间与Pr具有单调正相关关系

    Karp-Rabin算法

    凡事皆树:将任一有限长度的整数向量视作自然数,进而在字符串与自然数之间建立联系

    原理

    判断模式串P是否与文本串T匹配”的问题,可以转化为“判断T中是否 某个子串与模式串P拥相同的指纹

    • 散列压缩
    • 散列冲突
    • 指纹快速更新

    实现

    package com.atguigu.string;
    /**
     * @anthor shkstart
     * @create 2020-08-16 8:57
     */
    public class Fingerprint extends Str{
        public int match(char[] P, char[] T){
    	int m = P.length;
    	int n = T.length;
    	int Dm = peapreDm(m),hashP = 0,hashT = 0;
    	for (int i = 0;i < m;i++){
    		hashP = (hashP * R + DIGIT(P,i)) % M;
    		hashT = (hashT * R + DIGIT(T,i)) % M;
    	}
    	for (int k = 0; ;){
    		if (hashT == hashP){
    			if (check1by1(P,T,k)) return k;
    		}
    		if (++k > n -m) return k; else updateHash(hashT,T,m,k,Dm);
    	}
    }
    public static int M = 97;
    public static int R = 10;
    public int DIGIT(char[] S,int i){
    	return S[i] - '0';
    }
    public Boolean check1by1(char[] P,char[] T,int i){
    	for (int m = P.length,j = 0;j < m;j++,i++){
    		if (P[j] != T[i]) return false;
    	}
    	return true;
    }
    public int peapreDm(int m){
    	int Dm = 1;
    	for (int i = 1;i < m;i++){
    		Dm = (R * Dm) % M;
    	}
    	return Dm;
    }
    public void updateHash(int hashT,char[] T,int m,int k,int Dm){
    	hashT = (hashT - DIGIT(T,k - 1) * Dm) % M;
    	hashT = (hashT * R + DIGIT(T,k + m - 1)) % M;
    	if (0 > hashT) hashT += M;
    }
    }
    
  • 相关阅读:
    jmeter-可视化的非GUI模式
    深度剖析阶梯负载与最终请求数
    安全测试基础2-sqlmap演练
    百度压测,分析性能拐点
    性能测试-服务端瓶颈分析思路
    性能测试中的常见异常分析(转载整理)
    jmeter_遍历转换浮点时间戳
    性能测试-实例讲解VU、RPS、RT公式换算
    利用Docker安装Web前端性能测试工具Sitespeed.io
    基于 Jmeter 的 web 端接口自动化测试平台(转载)
  • 原文地址:https://www.cnblogs.com/suit000001/p/13526067.html
Copyright © 2011-2022 走看看