Binary String Matching---KMP算法,再次复习

如题地址:http://acm.nyist.net/JudgeOnline/problem.php?pid=5

Binary String Matching

时间限制:3000 ms  |  内存限制:65535 KB
难度:3
描述
Given two strings A and B, whose alphabet consist only ‘0’ and ‘1’. Your task is only to tell how many times does A appear as a substring of B? For example, the text string B is ‘1001110110’ while the pattern string A is ‘11’, you should output 3, because the pattern A appeared at the posit
输入
The first line consist only one integer N, indicates N cases follows. In each case, there are two lines, the first line gives the string A, length (A) <= 10, and the second line gives the string B, length (B) <= 1000. And it is guaranteed that B is always longer than A.
输出
For each case, output a single line consist a single integer, tells how many times do B appears as a substring of A.
样例输入
3
11
1001110110
101
110010010010001
1010
110100010101011 
样例输出
3
0
3 

虽然这道题是英文,但是稍微懂点英语的,都没有问题而且实例很明显,何况是我一个没有过四级的人,都看懂了。


思路:

这道题,第一时间想到的是暴力解决,得到两个字符串,for循环,截取比较,得出结果----结果不出意料也超时了。这就是所谓的BF算法

然后很自然想到用KMP算法,接着复习KMP算法,也是个学习的过程。这次和以往的不同,这次通过理解后,按自己的思路编写出来,虽然路途很艰辛,但是痛苦经历,印象更深。

KMP的算法关键还是在得到next数组上。依靠前后缀的相同个数,来判定next里的值,字面上理解是相同个数+1.详情看《大话数据结构》

关键代码:

书上是0号位保存长度,1号为真实值,有出入,相应实现值也有出入,感觉对算法不清晰,一有出入就会实现不了,很锻炼人的


public int[] get_next(String a){
                    int [] next=new int[a.length()];
                    int i=0;
                    int j=-1; //ij初始化要特别注意是一前一后。
                    next[i]= -1;        //初始
                    while(i<a.length()-1){         //这里要长度-1,是因为前一个比较,得到后一个的,i始终代表后一个
                               if(j==-1||a.charAt(j)==a.charAt(i)){     //相同继续比较+1,不同就回溯,指导第一个的时候,即:重新比较
                              j++;
                               i++;
//                            if(a.charAt(i)!=a.charAt(j))    //这里是升级版:让回溯得更彻底,处理aaaaab的等情况
                                       next[i]=j;
//                            else
//                                       next[i]=next[j];
                               }
                               else{
                                         j=next[j];                     //进行回溯
                               }
                    }
                    return next;
          }


加上实现函数:---思路很想get_next()函数,但是稍微有点不同,但是这个不同也是挺致命的,会实现不了,题目就是因为这样出现wrong answer.

public voidcompareStrKMP(String a,String b){

                    //得到next数组

                    int[] next=get_next(a);

                    int i=0;

                    intj=0;//这里i和j是相同的子串和大串比较,而不是自身,所以相同

                    while(i<b.length()){//对应比较,得出响应的结果,而get_next[]是得到后一个结果,所以是length而不是length-1

                              

                               if(j==-1 ||a.charAt(j)==b.charAt(i)){//j==-1是根据next[]数组里的第一位对应的,重新开始往下一个

                                         i++;

                                         j++;

                               }

                               else

                                         j=next[j];

                               if(j==a.length()){

                                         break;    //说明已经找到完全相同的子串了

                               }

                    }

                   

          }

 



这道题:写出了KMP算法后,发上去测试,结果是wrong answer很郁闷(不知道哪里考虑错了)。一直改都报错,最后睡了一觉,自己安慰自己说:虽然是错的,但是也学习了KMP算法,整理了思路才知道是:compareStrKMP()中 i<b.length-1这里错了,改为 i<b.length---然后就对了。看了书才发现,也是如此,太粗心了。


最后附上源码:

import java.util.Scanner;
/*
 * Binary String Matching
 */
public class Main {
	public static void main(String[] args) {
		Scanner cin=new Scanner(System.in);
		Main main=new Main();
		while(cin.hasNext()){
			int n=cin.nextInt();
			for(int i=0;i<n;i++){
				String a=cin.next();
				String b=cin.next();
				main.compareStrKMP(a, b);
			}
		}
	}
	//bf算法,直接暴力比较,破解  ----超时。。
	public void compareStrBF(String a,String b){
		int count=0;	//记录多少个子串相同
		int leng=a.length();
		for(int i=0;i<b.length()-leng;i++){		//这里注意要b.length()-leng。当后面都不够子串长,就不需要比较了
			String strTemp=b.substring(i,i+leng);
			//System.out.println("strTemp="+strTemp);
			if(strTemp.equals(a)){
				count++;
			}
		}
		System.out.println(count);
	}
	//kmp算法 书上是0号为装长度,改变后,对应数据要-1;  结果:91	 308	
	public void compareStrKMP(String a,String b){
		//得到next数组
		int[] next=get_next(a);
		int i=0;
		int j=0;
		int count=0;
		while(i<b.length()){	//对应比较,得出响应的结果,会比get_next()多一个范围,wrong answer就错在这里
			
			if(j==-1||a.charAt(j)==b.charAt(i)){
				i++;
				j++;
			}
			else
				j=next[j];
			if(j==a.length()){
				count++;
				i=i-(next[j-1]+1);		//i也要进行回溯,由题得子串包含相同的,回溯到相应第一次出现上。
				j=0;					//回到最初的状态
			}
		}
		System.out.println(count);
		
	}
	public int[] get_next(String a){
		int [] next=new int[a.length()];
		int i=0;
		int j=-1;
		next[i]=-1;	//初始化,对应书初始化为0,很重要
		while(i<a.length()-1){	//String.charAt()是从0~~length()-1的,并且这里是前一个比较,得出后一个的结果
			if(j==-1||a.charAt(j)==a.charAt(i)){	//从字面上理解是i-1到0中,从前或者从后比较最大有多少个相同,结果+1
				j++;								//而实际是用相对应的字符是否相同,相同则next=j(是先i++,j++后),不同回溯,因为再此处的基础上叠加--之前会相同的。
				i++;
//				if(a.charAt(i)!=a.charAt(j))	//判子串重复,不应该有这个--根据题意:next数值小了,上面i的回溯小了,会遗漏结果
					next[i]=j;
//				else
//					next[i]=next[j];
			}
			else{
				j=next[j];		//进行回溯
			}
		}
		return next;
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值