package demoFour;
/*
 *@author:张文波
 *@time2020年4月10日下午3:54:34
 */
 //本类是用于实现Kmp算法,和笨蛋模式串匹配算法,而kmp是模式串匹配算法中
 //的一种高效算法,如果用传统的模式串,就是笨蛋算法,是有回溯的,但是笨蛋方法简单,kmp比较难
 public class Kmp
 {
     // 先声明俩名词:模式串:就是你要拿这个串在另一个串中去找看是否能找到的串,他叫模式串,那么另一个我们称之为目标串
     // 在这我们两种方法都实现
     public static void main(String[] args)
     {
         String str1 = "abac";
         //String str2 = "b";        //System.out.println(foolMethod(str1, str2));
         
         //得到next数组后我们就可以进行模式匹配了
         String str2="ba";  
         int next[]=getNext(str2);
         for(int i:next) {
             System.out.print(i+" ");
             
         }
         int pos=Kmp(str1, str2, next);
         System.out.println("\n"+pos);
         
     }//一种传统的笨蛋模式串匹配算法
     public static int foolMethod(String str1, String str2)
     {
         // s1为目标串,str2叫模式串
         int pos = 0;
         // 思路就是两层循环,第一层就是每次开始匹配的位置,第二层就是从第一层开始
         // 位置连续读模式串长度的串,如果期间都匹配成功那么咱们就GG否则就i+1,
         // 值得注意的是substring(a,b)是不包括b的
         for (int i = 0; i < str1.length(); i++)
         {
             String temp = str1.substring(i, i + str2.length());
             if (temp.equals(str2))
             {
                 pos = i;
                 break;            }
         }
         return pos;
     }
     //Kmp算法,KMP算法是要先求next数组的,然后根据next数组在每次失去匹配时候跳跃式的匹配下一个位置
     //关于next数组怎么求如果有需要的话可以留言,
         public static int Kmp(String str,String strMoude,int next[]) {
             int pos1=0;//主串匹配位置
             int pos2=0;//模式串匹配成功个数
             int len1=str.length();//主串的长度
             int len2=strMoude.length();//模式串的长度
             while(pos1<len1) {
                 while(pos2<len2&&pos1<len1&&str.charAt(pos1)==strMoude.charAt(pos2)) {
                     pos1++;
                     pos2++;
                 }
                 //退出循环判断是否是因为pos2=len2了,因为加入等于那么就说明已经匹配完成了
                 if(pos2==len2) {
                     
                     return pos1-len2+1;//返回匹配成功的位置
                 }
                 else {
                     pos2=0;//模式串匹配成功个数归零
                     pos1=pos1-next[pos2]+1;//主串跳跃位置为当前下标减去next数组对应失配的数,+1
                 }
                 
             }
             return -1;
         }
         public static int[] getNext(String str) {
             int next[]=new int[str.length()];
             //约定俗成,next的第一个是0,第二个是1
             next[0]=0;
             next[1]=1;
             //定义一个字符串类型变量,因为在求每一位上的next数组时都是要根据当前位-1的子串的前后缀相等个数+1
             String newStr;
             for(int i=2;i<str.length();i++) {
                 newStr=str.substring(0,i);
                 int temp=i-1; //为什么要定义一个temp呢,是因为我们需要确定当前位置i的子串前后缀然后判断时候相等
                                 //
                 while(temp>0) {
                     String t1=newStr.substring(0,temp);
                     String t2=newStr.substring(i-temp,newStr.length());
                     //如果此时前后缀相等那么next值就等于前后缀相等个数
                     if(t1.equals(t2)) {
                         next[i]=temp+1;  //next等于前后缀相等个数+1
                         break;
                     }
                     temp--;  //通过temp--我们可以让前后缀同时缩小
                 }
                 //仍然需要注意的是,如果当temp=0还没找到说明前后缀相等个数为零,我们规定,如果等于0我们令next值为1
                 if(temp==0) {
                     next[i]=1;
                 }
                 
             }
             return next;
         }
 }