字符串搜索算法与匹配算法的总结

BF算法

暴力破解(就是BF算法),
算法核心思想:首先S[1]和T[1]比较,若相等,则再比较S[2]和T[2],一直到T[M]为止;若S[1]和T[1]不等,则T向 右移动一个字符的位置,再依次进行比较。如果存在k,1≤k≤N,且S[k+1…k+M]=T[1…M],则匹配成功;否则失败。该算法最坏情况下要进行 M*(N-M+1)次比较,时间复杂度为O(M*N)

比如: String a =“123456789” String b= “23”
其实就是循环 a一个一个字符匹配,开始a[0]和b[0]匹配,没有找到,直接不用找b[1],直接用a[1]和b[0]匹配发现已经 找到,然后继续用
a[2]和b[1]匹配发现已经 找到。前且是b字符串末尾。说明已经完全找到。返回结果

代码实现:

public class 暴力解法 {
	public static void main(String args[]){  
	      String str1 = "ailkmno";  
	      String str2 = "ilkm";  
	      int n = find(str1,str2);  
	      System.out.println(str2+"在"+str1+"中出现的位置是:"+n);  
	        
	  }  
	  public static int find(String str1,String str2){
		  char[] c1=str1.toCharArray();
		  char[] c2=str2.toCharArray();
		  int j=0;
		  int i=0;
		  for(;i<str1.length();){
			  if(j>=str2.length()-1){
				  break;
			  }
			  if(c1[i]==c2[j] ){
				  i=i+1;
				  j=j+1;
			  }else{
				  i=i+1;
			  }
		  }
		  System.out.println(i+"          "+j);
		  return i-str2.length()+1;
	  }
}

Sunday匹配算法

Sunday算法是Daniel M.Sunday于1990年提出的一种比BM算法搜索速度更快的算法。
Sunday算法其实思想跟BM算法很相似,只不过Sunday算法是从前往后匹配,在匹配失败时关注的是文本串中参加匹配的最末位字符的下一位字符。如果该字符没有在匹配串中出现则直接跳过,即移动步长= 匹配串长度+ 1;否则,同BM算法一样其移动步长=匹配串中最右端的该字符到末尾的距离+1。

举例:
假设我们有如下字符串: 
S = “LESSONS TEARNED IN SOFTWARE TE”;
T = “SOFTWARE”;
在这里插入图片描述
(5) k指向的模式串T字符与m指向的主串S字符“E”相等,因此再次移动模式串1位。
在这里插入图片描述
在这里插入图片描述
代码实现如下:

import java.util.Arrays;

public class Sunday算法 {

	//创建下一序号表,即记录字母对应下标
	public static int[] next(char[] T) {
		//初始化序号数组
		int []next=new int[65536];
		//填充坏字符序号
		Arrays.fill(next, -1);
		//填充好字符序号
		for(int j=0;j<T.length;j++) {
			next[T[j]]=j;
		}
		return next;
	}
	

	/**
	 * sunday查找
	 * @param S 正文字符数组
	 * @param T 模式字符数组
	 * @return 匹配位置
	 */
	public static int sunday(char[] S,char[] T) {
		//检查输入参数有效
		if (S==null||T==null||S.length==0 || T.length==0 ||T.length>S.length){
			return -1;
		}
		
		//获取下一序号数组
		int next[]=next(T);
		//遍历正文数组
		int delta =S.length-T.length;
		for (int i = 0; i <delta;) {
			//从头开始比较
			int j=0;
			for (;j<T.length&&i+j<S.length; j++) {
				if (T[j]!=S[i+j]) {
					break;
				}
			}
			//已经完全匹配
			if (j==T.length) {
				return i;
			}
			//后移长度不够
			if (i+T.length>=S.length) {
				return -1;
			}
			//后移偏移距离(根据末位下一字符在模式字符串中的位置判断偏移距离)
			i+=T.length-next[S[i+T.length]];
		}
		//返回查找失败
		return -1;
	}
	public static void main(String[] args) {
		String text="LESSONS TEARNED IN SOFTWARE TE";
		String pattern="SOFTWARE";
		System.out.println("S:\t"+text);
		System.out.println("T:\t"+pattern);
		//测试下一序号数组
		int next[]=next(pattern.toCharArray());
		
		System.out.println("下一序号数组:");
		for(int i=0;i<next.length;i++) {
			if (next[i]!=-1) {
				System.out.println("next['"+(char)i+"']:"+next[i]);
			}
		}
		//测试Sunday查找算法
		System.out.println("Sunday:\t"+sunday(text.toCharArray(),pattern.toCharArray()));
		//Java内置的匹配方法,找出第一次匹配的index索引
		System.out.println("String:\t"+text.indexOf(pattern));
	}
}

KMP算法

KMP是一个解决模式串在文本串是否出现过以及若出现找出最早出现位置的算法.
KMP要做的就是通过一个next数组保存模式串中前后最长公共子序列的长度以保证每次回溯时通过next数组找到应回溯的位置节省大量无用的回溯比较.

next数组的计算方法:
模式串
ababa
子串
a 前缀:无 后缀:无 最长公共子序列长度:0
ab 前缀:a 后缀:b 最长公共子序列长度: 0
aba 前缀:a ab 后缀:a ba 最长公共子序列长度: 1
abab 前缀:a ab aba 后缀:b ab bab 最长公共子序列长度:2
ababa 前缀:a ab aba abab 后缀:a ba aba baba 最长公共子序列长度:3

next数组 0 0 1 2 3

KMP算法时间复杂度O(m+n)

算法实现:

public class KMP算法 {

	//求出next数组
	public static int[] kmpnext(String dest) {
		int[] next=new int[dest.length()];
		next[0]=0;
		//i为子序列长度
		for (int i = 1,j=0; i < dest.length(); i++) {
			//循环内的i为后缀下标,j为前缀下标,同时j记录着当前最大公共子序列长度
			while(j>0&&dest.charAt(j)!=dest.charAt(i)) {
				j=next[j-1];
			}
			if (dest.charAt(i)==dest.charAt(j)) {
				j++;
			}
			next[i]=j;
		}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值