字符串匹配算法 之BF、KMP

示例:

 1. 已知字符串str1="acabaabaabcacaabc",求str2="abaabcac"是否在字符串str1中?算法

 2. DNA病毒檢測。已知患者DNA序列求病毒DNA序列是否在患者DNA中出現過?病毒DNA爲環狀結構(即首尾相連)。數組

此文以問題1爲例進行解答。優化

1、BF算法

即暴力檢測法,從字符串第一個字符開始和匹配字符串進行比較若是不一樣,則從字符串第二個位置開始比較直到結束。spa

BF算法思想很簡單,直接列出代碼實現:code

 static void Main(string[] args)
        {
            string str = "acabaabaabcacaabc";//"aaabaaaaaab";
            string mo = "abaabc";//"aaaab";int flag;//表示查詢結果
            flag = BF(str, mo, 0);
            if (flag != -1) Console.WriteLine("匹配成功!" + "  下標爲: " + flag);
            else Console.WriteLine("匹配失敗!");
        }
 private static int BF(string str, string mo, int v)
        {
            int i = v ,j = 0;
            while (i < str.Length && j < mo.Length)
            {
                if (str[i] == mo[j])
                {
                    i++;
                    j++;
                }
                else
                {
                    i = i - j + 1;
                    j = 0;
                }
            }
            if (j >= mo.Length) return i - mo.Length;
            else return -1;
        }
2、KMP算法

如圖:blog

 

 

在檢測中發現i和j標記的元素不一樣,此時若是是BF算法直接i-j+1,j=0.可是KMP算法思想是讓i下標不變,j下標變化,便可以理解爲數組str2右移儘量少的單位。開發

問題來了,如何知道要移動多少呢?字符串

 

 

 如圖,咱們能夠知道在數組str2中j下標以前的全部元素都匹配,那麼咱們只要保證,移動k使得在str1中和str2中j=k元素以前的元素依舊匹配便可。因此有了string

前綴和後綴的概念,前綴:元素的真子集 ,後綴:元素的反向真子集。即如aba三個元素,最長前綴爲ab,最長後綴爲ba。可是隻有前綴a和後綴a相同因此str2的第四個元素的it

next值爲1;也就是當匹配到str[3]不一樣於str1時,此時j下標變爲1即str2向右移動到j==下標1。

爲此咱們只須要根據str2獲得next數組就行。即獲得str2的最大匹配先後綴個數。默認a[0]=0;即變化值爲next值-1.由於next值是在字符串下標從1開始,咱們開發一般下標從0開始

 

 

 代碼以下:

 static void Main(string[] args)
        {
            string str = "acabaabaabcacaabc";//"aaabaaaaaab";
            string mo = "abaabc";//"aaaab";
            int[] next=new int[mo.Length];
            int flag;//表示查詢結果
            setNext(mo, next);
            foreach (var item in next)
            {
                Console.Write(item + " ");
            }
            Console.WriteLine();
            flag = KMP(str, mo, 0, next);
            if (flag != -1) Console.WriteLine("匹配成功!" + "  下標爲: " + flag);
            else Console.WriteLine("匹配失敗!");
        }
  private static void setNext(string mo, int[] next)
        {
            int i = 0, j = -1;
            next[0] = -1;
            while (i < mo.Length - 1)
            {
                if (j == -1 || mo[i] == mo[j])
                {
                    i++; j++;
                    next[i] = j;
                }
                else j = next[j];
            }
        }
   private static int KMP(string str, string mo, int v,int[] next)
        {
            int i = v, j = 0;
            while (i < str.Length && j < mo.Length)
            {
                if (j==-1 || str[i] == mo[j])
                {
                    i++;
                    j++;
                }
                else
                {
                    j = next[j];
                }
            }
            if (j >= mo.Length) return i - mo.Length;
            else return -1;
        }
 
//進一步對next數組優化
private static void setNextVal(string mo, int[] next) { int i = 0, j = -1; next[0] = -1; while (i < mo.Length-1) { if (j == -1 || mo[i] == mo[j]) { i++; j++; if (mo[i] != mo[j]) next[i] = j; else next[i] = next[j]; } else j = next[j]; } }
相關文章
相關標籤/搜索