zoukankan      html  css  js  c++  java
  • [小明学算法]6.字符串匹配算法---KMP

    1.简介
       字符串匹配就是看看那字符串b是不是字符串a的子串.常用的Knuth-Morris-Pratt 算法,又称KMP算法.
     
    2.主要思想
      当patter在某一位置与string匹配失败时,我们除了知道从string的这个位置进行匹配失败这个结果外,是否可以从前面的匹配中获得更多的信息呢。即当前匹配点匹配失败之后,向右滑动的距离是可以提前计算出来的.
     
    3.举例
      abcabcabcdef   --------- string
      abcabcdef         --------- pattern
      KMP就是利用已经匹配了的字符串这个信息,来进行尽可能的向右滑动,避免无谓的比较。匹配字符就是两个字符串的公共部分那么究竟当不匹配的时候,可以向右滑动多远呢?
      以上面的pattern "abcabcdef"为例:
        当第一个字符不匹配的时候,没有额外信息,那么就向右滑动1个字符。
        当第二个字符不匹配的时候,说明之前匹配的字符为a,但是我们是第二个字符不匹配,还是只能向右滑动1个字符。
        当第三个字符不匹配的时候,说明之前匹配的字符为ab,那么可以向右滑动2位;
        当第四个字符不匹配的时候,说明之前匹配的字符为abc,那么可以向右滑动3位;
        当第五个字符不匹配的时候,说明之前匹配的字符为abca,那么也只能向右滑动3位;
        。。。。。。
     
    4.关键问题 
      那么KMP算法的关键问题就是计算pattern某位置匹配失败的时候,可以向右滑动的位数。
      下面白话一下如何计算这个滑动位数,0匹配和1匹配时,向右滑动都为1.当匹配数n(n>=2)的时候,在之前匹配的字符串t1中,新增加的字符串t2,且不是t1的23:20:05前端完全重合的字串,则滑动数值加一,否则结束.
     
    5.代码
    static void Main(string[] args)
            {
    
    
                char[] pattern = { 'a', 'b', 'c', 'a', 'b', 'c', 'd', 'e', 'f' };
                int[] table = new int[pattern.Length];
                cal_next_table(pattern, table);
    
                Console.Read();
            }
    
            static void cal_next_table(char[] pattern,int[] table)
            {
                //设Table[0]为哨兵
                table[0] = 1;
                Print(pattern);
                Print(table);
                for (var i = 1; i < pattern.Length; i++)
                {            
                    table[i] = table[i - 1];
                    //直接与pattern比较了,以免出现t2长度大于t1的情况
                    //var t1 = GetSubArr(pattern, 0, i);
    
                    //检测t2(注意起点)是否和t1头部重合,重合则break
                    for(var j=table[i];j<i;j++)
                    {
                        var t2 = GetSubArr(t1, j, i );
                        Print(t1);
                        if (!strcncmp(pattern, t2))
                        {
                            table[i]++;
                        }
                        else
                            break;
                    }
                    Print(t1);
    
                    Print(pattern);
                    Print(table);
                }
               
            }
    
            static char[] GetSubArr(char[] pattern,int start,int end)
            {
                char[] t = new char[end - start];
                for(int i=0;i<t.Length;i++)
                {
                    t[i] = pattern[i + start];
                }
    
                return t;
            }
    
            static void Print(Array arr)
            {
                foreach(var a in arr)
                {
                    Console.Write(a + " ");
                }
                Console.WriteLine();
            }
    
            static bool strcncmp(char[] arr1,char[] arr2)
            {
                for(var i=0;i<arr2.Length;i++)
                {
                    if (arr1[i] != arr2[i])
                        return false;
                }
    
                return true;
            }    
    View Code

    6.结果

    a b c a b c d e f
    1 0 0 0 0 0 0 0 0
    a
    a b c a b c d e f
    1 1 0 0 0 0 0 0 0
    b
    a b
    a b c a b c d e f
    1 1 2 0 0 0 0 0 0
    c
    a b c
    a b c a b c d e f
    1 1 2 3 0 0 0 0 0
    a
    a b c a
    a b c a b c d e f
    1 1 2 3 3 0 0 0 0
    a b
    a b c a b
    a b c a b c d e f
    1 1 2 3 3 3 0 0 0
    a b c
    a b c a b c
    a b c a b c d e f
    1 1 2 3 3 3 3 0 0
    a b c d
    b c d
    c d
    d
    a b c a b c d
    a b c a b c d e f
    1 1 2 3 3 3 3 7 0
    e
    a b c a b c d e
    a b c a b c d e f
    1 1 2 3 3 3 3 7 8
    View Code
    1. abcabcdef
    2. 112333378
  • 相关阅读:
    vue打包报错
    css实现平行四边形
    js计算两个天数的差值
    创建vue项目的第一步——之安装vue 命令更新了
    Vue-router详解路由
    Vue-axios 在vue cli中封装
    jQuery-自己封装的弹框
    vue-上传文件
    vue-axios当只调用vue.js又需要axios请求多时
    Vant-UI移动端时间选择框
  • 原文地址:https://www.cnblogs.com/WongSiuming/p/5119943.html
Copyright © 2011-2022 走看看