• [每天默写一个算法]KMP


    [每天默写一个算法]KMP

    作业要求:默写String的KMP算法。

    KMP是经典的字符串匹配算法。复杂度为O(n+m)

     1     public static class StringKMP
     2     {
     3         /// <summary>
     4         /// This indicates that no pattern found from source.
     5         /// </summary>
     6         public const int KMPNoMatch = -1;
     7         /// <summary>
     8         /// Special value of next[] array, which means i should be increased by 1 and j sould be reset to 0.
     9         /// </summary>
    10         public const int FirstBlood = -1;
    11         /// <summary>
    12         /// Find first match for specified pattern in the source.
    13         /// </summary>
    14         /// <param name="source"></param>
    15         /// <param name="pattern"></param>
    16         /// <returns></returns>
    17         public static int KMP(this String source, String pattern)
    18         {
    19             if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(pattern))
    20             { return KMPNoMatch; }
    21             var i = 0; var j = 0; var result = KMPNoMatch;
    22             var nextVal = GetNextVal(pattern);
    23 
    24             while (i < source.Length && j < pattern.Length)
    25             {
    26                 if (j == FirstBlood)
    27                 {// source[i] does NOT equal with pattern[0], so i should be increased by 1 and j should be reset to 0.
    28                     i++; j = 0;
    29                 }
    30                 else if (source[i].Equals(pattern[j]))
    31                 {
    32                     i++; j++;
    33                 }
    34                 else
    35                 {// Get next j that should be compared with.
    36                     j = nextVal[j];
    37                 }
    38             }
    39 
    40             if (j >= pattern.Length)// Match succeeded.
    41             { result = i - pattern.Length; }
    42 
    43             return result;
    44         }
    45         /// <summary>
    46         /// nextVal[j]: source[i] should compare with pattern[ nextVal[j] ] in next loop
    47         /// <para>if source[i] does NOT equal with pattern[j].</para>
    48         /// <para>Specially, if source[i] does NOT equal with pattern[0], then i should be increased by 1</para>
    49         /// <para>and j should be reset to 0.</para>
    50         /// <para>So we should always set nextVal[0] = FirstBlood.</para>
    51         /// </summary>
    52         /// <param name="pattern"></param>
    53         /// <returns></returns>
    54         private static int[] GetNextVal(String pattern)
    55         {
    56             var j = 0; var k = -1;
    57             var nextVal = new int[pattern.Length];
    58 
    59             nextVal[0] = FirstBlood;
    60 
    61             while (j < pattern.Length - 1)
    62             {
    63                 if ((k == -1) || (pattern[j].Equals(pattern[k])))
    64                 {
    65                     j++; k++;
    66                     if (!(pattern[j].Equals(pattern[k])))
    67                     { nextVal[j] = k; }
    68                     else
    69                     { nextVal[j] = nextVal[k]; }
    70                 }
    71                 else
    72                 { k = nextVal[k]; }
    73             }
    74 
    75             return nextVal;
    76         }
    77     }

     

    字符串能匹配,其他类型的串(数组Array和泛型数组IList<T>)也就可以匹配。

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 using System.Text;
      5 
      6 namespace System
      7 {
      8     public static class StringKMP
      9     {
     10         /// <summary>
     11         /// This indicates that no pattern found from source.
     12         /// </summary>
     13         public const int KMPNoMatch = -1;
     14         /// <summary>
     15         /// Special value of next[] array, which means i should be increased by 1 and j sould be reset to 0.
     16         /// </summary>
     17         private const int FirstBlood = -1;
     18         /// <summary>
     19         /// Find first match for specified pattern in the source.
     20         /// </summary>
     21         /// <param name="source"></param>
     22         /// <param name="pattern"></param>
     23         /// <returns></returns>
     24         public static int KMP(this String source, String pattern)
     25         {
     26             if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(pattern))
     27             { return KMPNoMatch; }
     28             var i = 0; var j = 0; var result = KMPNoMatch;
     29             var nextVal = GetNextVal(pattern);
     30 
     31             while (i < source.Length && j < pattern.Length)
     32             {
     33                 if (j == FirstBlood)
     34                 {// source[i] does NOT equal with pattern[0], so i should be increased by 1 and j should be reset to 0.
     35                     i++; j = 0;
     36                 }
     37                 else if (source[i].Equals(pattern[j]))
     38                 {
     39                     i++; j++;
     40                 }
     41                 else
     42                 {// Get next j that should be compared with.
     43                     j = nextVal[j];
     44                 }
     45             }
     46 
     47             if (j >= pattern.Length)// Match succeeded.
     48             { result = i - pattern.Length; }
     49 
     50             return result;
     51         }
     52         /// <summary>
     53         /// nextVal[j]: source[i] should compare with pattern[ nextVal[j] ] in next loop
     54         /// <para>if source[i] does NOT equal with pattern[j].</para>
     55         /// <para>Specially, if source[i] does NOT equal with pattern[0], then i should be increased by 1</para>
     56         /// <para>and j should be reset to 0.</para>
     57         /// <para>So we should always set nextVal[0] = FirstBlood.</para>
     58         /// </summary>
     59         /// <param name="pattern"></param>
     60         /// <returns></returns>
     61         private static int[] GetNextVal(String pattern)
     62         {
     63             var j = 0; var k = -1;
     64             var nextVal = new int[pattern.Length];
     65 
     66             nextVal[0] = FirstBlood;
     67 
     68             while (j < pattern.Length - 1)
     69             {
     70                 if ((k == -1) || (pattern[j].Equals(pattern[k])))
     71                 {
     72                     j++; k++;
     73                     if (!(pattern[j].Equals(pattern[k])))
     74                     { nextVal[j] = k; }
     75                     else
     76                     { nextVal[j] = nextVal[k]; }
     77                 }
     78                 else
     79                 { k = nextVal[k]; }
     80             }
     81 
     82             return nextVal;
     83         }
     84     }
     85 
     86     public static class ArrayKMP
     87     {
     88         /// <summary>
     89         /// This indicates that no pattern found from source.
     90         /// </summary>
     91         public const int KMPNoMatch = -1;
     92         /// <summary>
     93         /// Special value of next[] array, which means i should be increased by 1 and j sould be reset to 0.
     94         /// </summary>
     95         private const int FirstBlood = -1;
     96         /// <summary>
     97         /// Find first match for specified pattern in the source.
     98         /// </summary>
     99         /// <param name="source"></param>
    100         /// <param name="pattern"></param>
    101         /// <returns></returns>
    102         public static int KMP(this Array source, Array pattern)
    103         {
    104             if (source == null || pattern == null || source.Length == 0 || pattern.Length == 0)
    105             { return KMPNoMatch; }
    106             var i = 0; var j = 0; var result = KMPNoMatch;
    107             var nextVal = GetNextVal(pattern);
    108 
    109             while (i < source.Length && j < pattern.Length)
    110             {
    111                 if (j == FirstBlood)
    112                 {// source[i] does NOT equal with pattern[0], so i should be increased by 1 and j should be reset to 0.
    113                     i++; j = 0;
    114                 }
    115                 else if (source.GetValue(i).Equals(pattern.GetValue(j)))
    116                 {
    117                     i++; j++;
    118                 }
    119                 else
    120                 {// Get next j that should be compared with.
    121                     j = nextVal[j];
    122                 }
    123             }
    124 
    125             if (j >= pattern.Length)// Match succeeded.
    126             { result = i - pattern.Length; }
    127 
    128             return result;
    129         }
    130         /// <summary>
    131         /// nextVal[j]: source[i] should compare with pattern[ nextVal[j] ] in next loop
    132         /// <para>if source[i] does NOT equal with pattern[j].</para>
    133         /// <para>Specially, if source[i] does NOT equal with pattern[0], then i should be increased by 1</para>
    134         /// <para>and j should be reset to 0.</para>
    135         /// <para>So we should always set nextVal[0] = FirstBlood.</para>
    136         /// </summary>
    137         /// <param name="pattern"></param>
    138         /// <returns></returns>
    139         private static int[] GetNextVal(Array pattern)
    140         {
    141             var j = 0; var k = -1;
    142             var nextVal = new int[pattern.Length];
    143 
    144             nextVal[0] = FirstBlood;
    145 
    146             while (j < pattern.Length - 1)
    147             {
    148                 if ((k == -1) || (pattern.GetValue(j).Equals(pattern.GetValue(k))))
    149                 {
    150                     j++; k++;
    151                     if (!(pattern.GetValue(j).Equals(pattern.GetValue(k))))
    152                     { nextVal[j] = k; }
    153                     else
    154                     { nextVal[j] = nextVal[k]; }
    155                 }
    156                 else
    157                 { k = nextVal[k]; }
    158             }
    159 
    160             return nextVal;
    161         }
    162     }
    163 
    164     public static class IListKMP
    165     {
    166         sealed class DefaultComparer<T> : IComparer<T>
    167         {
    168             private static readonly DefaultComparer<T> instance = new DefaultComparer<T>();
    169 
    170             public static DefaultComparer<T> Instance
    171             {
    172                 get { return DefaultComparer<T>.instance; }
    173             }
    174 
    175 
    176             int IComparer<T>.Compare(T x, T y)
    177             {
    178                 if (x.Equals(y)) { return 0; }
    179                 else { return 1; }
    180             }
    181         }
    182 
    183         /// <summary>
    184         /// This indicates that no pattern found from source.
    185         /// </summary>
    186         public const int KMPNoMatch = -1;
    187         /// <summary>
    188         /// Special value of next[] array, which means i should be increased by 1 and j sould be reset to 0.
    189         /// </summary>
    190         private const int FirstBlood = -1;
    191         /// <summary>
    192         /// Find first match for specified pattern in the source.
    193         /// </summary>
    194         /// <param name="source"></param>
    195         /// <param name="pattern"></param>
    196         /// <param name="comparer"></param>
    197         /// <returns></returns>
    198         public static int KMP<T>(this IList<T> source, IList<T> pattern, IComparer<T> comparer = null)
    199         {
    200             if (source == null || pattern == null || source.Count == 0 || pattern.Count == 0)
    201             { return KMPNoMatch; }
    202 
    203             if (comparer == null) { comparer = DefaultComparer<T>.Instance; }
    204 
    205             var i = 0; var j = 0; var result = KMPNoMatch;
    206             var nextVal = GetNextVal(pattern, comparer);
    207 
    208             while (i < source.Count && j < pattern.Count)
    209             {
    210                 if (j == FirstBlood)
    211                 {// source[i] does NOT equal with pattern[0], so i should be increased by 1 and j should be reset to 0.
    212                     i++; j = 0;
    213                 }
    214                 else if (comparer.Compare(source[i], pattern[j]) == 0) //(source[i].Equals(pattern[j]))
    215                 {
    216                     i++; j++;
    217                 }
    218                 else
    219                 {// Get next j that should be compared with.
    220                     j = nextVal[j];
    221                 }
    222             }
    223 
    224             if (j >= pattern.Count)// Match succeeded.
    225             { result = i - pattern.Count; }
    226 
    227             return result;
    228         }
    229 
    230         /// <summary>
    231         /// nextVal[j]: source[i] should compare with pattern[ nextVal[j] ] in next loop
    232         /// <para>if source[i] does NOT equal with pattern[j].</para>
    233         /// <para>Specially, if source[i] does NOT equal with pattern[0], then i should be increased by 1</para>
    234         /// <para>and j should be reset to 0.</para>
    235         /// <para>So we should always set nextVal[0] = FirstBlood.</para>
    236         /// </summary>
    237         /// <param name="pattern"></param>
    238         /// <returns></returns>
    239         private static int[] GetNextVal<T>(IList<T> pattern, IComparer<T> comparer)
    240         {
    241             var j = 0; var k = -1;
    242             var nextVal = new int[pattern.Count];
    243 
    244             nextVal[0] = FirstBlood;
    245 
    246             while (j < pattern.Count - 1)
    247             {
    248                 if ((k == -1) || (comparer.Compare(pattern[j], pattern[k]) == 0))
    249                 {
    250                     j++; k++;
    251                     if (!(comparer.Compare(pattern[j], pattern[k]) == 0))
    252                     { nextVal[j] = k; }
    253                     else
    254                     { nextVal[j] = nextVal[k]; }
    255                 }
    256                 else
    257                 { k = nextVal[k]; }
    258             }
    259 
    260             return nextVal;
    261         }
    262 
    263     }
    264 
    265 }


     
     

  • 相关阅读:
    常用连链接命令行存储小工具
    switch case 跳转表
    抖音越狱版本App下载
    AutoLayout + UILabel布局
    ReplayKit2 有线投屏项目-反向Socket实现
    ReplayKit2 有线投屏项目总结
    直播相关-搭建直播流服务器nodejs
    难过!失眠!
    CAShapeLayer
    WebService相关概念介绍
  • 原文地址:https://www.cnblogs.com/bitzhuwei/p/algorithm_kmp.html
Copyright © 2020-2023  润新知