zoukankan      html  css  js  c++  java
  • KMP算法

    第一次用繁體字寫裝一下逼...

    KMP算法是一種改進的字符串匹配算法。KMP算法的關鍵是利用匹配失敗後的信息,儘量減少模式串與主串的匹配次數以達到快速匹配的目的。

    具體的實現就是實現一個next函數,函數本身包含了模式串的局部匹配的信息。當然我還不是很懂的...

    第一步是得到next數組,next[i]代表的是當前位置i字符跳的步長,就是跳回去下一步應該進行的匹配的位置;

    第二步根據next數組找到匹配的位置,一般找到第一個就好了,當然也可以找出一共有多少個匹配的,貌似功能挺多的...

    來几題:

    poj 3461.Oulipo

    通過KMP算法找出模式串在主串中出現的個數:

     1 // poj 3461.Oulipo
     2 // KMP算法 统计子串匹配次数 
     3 
     4 #include <iostream>
     5 #include <cstdio>
     6 #include <cstring>
     7 #include <algorithm>
     8 
     9 using namespace std;
    10 
    11 int n;    //目标串长度 
    12 int m;    //源串长度 
    13 char t[10005];    //目标串 
    14 char s[1000005];    //源串 
    15 int next[10005];    //next数组 
    16 
    17 void get_next()
    18 {
    19     int i = 0, j = -1;
    20     next[0] = -1;
    21     while(i < n)
    22     {
    23         if(j == -1 || t[i] == t[j])        //对目标串处理得到next数组 
    24         {
    25             i++, j++;
    26             next[i] = j;
    27         }
    28         else
    29             j = next[j];
    30     }
    31 }
    32 
    33 int KMP()
    34 {
    35     int count = 0;
    36     get_next();
    37     int i=0, j=0;
    38     while(i != m)
    39     {
    40         if(j == -1 || s[i] == t[j])
    41             i++, j++;
    42         else
    43             j = next[j];
    44         if(j == n)
    45         {
    46             count++;        //每次找到匹配的子串,count++; 
    47             j = next[j];
    48         }
    49     }
    50     if(count == 0)
    51         return 0;    //匹配失败 
    52     return count;
    53 }
    54 
    55 int main()
    56 {
    57     int k;
    58     scanf("%d", &k);
    59     while(k--)
    60     {
    61         memset(next, 0, sizeof(next));
    62         scanf("%s", t);
    63         scanf("%s", s);
    64         n = strlen(t);
    65         m = strlen(s);
    66         int ans = KMP();
    67         printf("%d
    ", ans);
    68     }
    69     return 0;
    70 } 

    接下來這題可以更好的加深對next數組的理解:

    poj 2406.Power Strings 

    很奇怪要用G++編譯才能過...

    // poj 2406.Power Strings
    // KMP算法 找出組成主串的重複子串
    // e.g. abababa -> ab 
    // references:
    // http://blog.sina.com.cn/s/blog_6635898a0100l3sd.html
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 1000005;
    
    char s[N];
    int next[N];
    int len;
    
    int get_next()
    {
        int i = 0, j = -1;
        next[0] = -1;
        while(i < len)
        {
            if(j == -1 || s[i] == s[j])
            {
                i++, j++;
                next[i] = j;
            }
            else
                j = next[j];
        }
    }
    
    int main()
    {
        while(scanf("%s", s) != EOF)
        {
            if(s[0] == '.')
                break;
            len = strlen(s);
            get_next();
            int ans = 1;
            if(len % (len - next[len]) == 0)
                ans = len / (len - next[len]);
            printf("%d
    ", ans);
        }
        return 0;
    }

    poj 1961.Period 

    跟上一題一樣的,只是輸出不同;這題輸出第幾個位置出現來多少次子串,舉個栗子:

    aabaabaabaab... 

    輸出

    3 1 表示到第三個位置出現一個aab,就是這麼簡單!!!

     1 // poj 1961.Period
     2 // KMP算法 poj 2406的加強版而已  
     3 // references:
     4 // http://blog.csdn.net/niushuai666/article/details/6967716
     5 #include <iostream>
     6 #include <cstdio>
     7 #include <cstring>
     8 #include <algorithm>
     9 
    10 using namespace std;
    11 
    12 const int N = 1000005;
    13 
    14 char s[N];
    15 int next[N];
    16 int len;
    17 
    18 int get_next()
    19 {
    20     memset(next, 0, sizeof(next));
    21     int i = 0, j = -1;
    22     next[0] = -1;
    23     while(i < len)
    24     {
    25         if(j == -1 || s[i] == s[j])
    26         {
    27             i++, j++;
    28             next[i] = j;
    29         }
    30         else
    31             j = next[j];
    32     }
    33 }
    34 
    35 int main()
    36 {
    37     int k=1;
    38     while(scanf("%d", &len) != EOF, len)
    39     {
    40         scanf("%s", s);
    41         get_next();
    42         int ans = 1;
    43         int count = 0;
    44         printf("Test case #%d
    ", k++);
    45         for(int i=1; i<=len; i++)
    46         {
    47             if(i % (i - next[i]) == 0)
    48             {
    49                 ans = i / (i - next[i]);
    50                 if(ans != 1)
    51                     printf("%d %d
    ", i, ans);
    52                 
    53             }        
    54         } 
    55         printf("
    ");
    56     }
    57     return 0;
    58 }

    一次過三題,你值得擁有!!!

  • 相关阅读:
    UILocalNotification实现本地的闹钟提醒的方法
    自定义UITableViewCell:Cell高度、分割线、间距等
    第三方苹果开发库之ASIHTTPRequest(翻译版)
    字符串NSString和数组NSArray操作
    MFMailComposeViewController发送邮件的实例
    IOS开发之手势—UIGestureRecognizer 共存
    ios 画图总结 [转]
    iOS-响应上下左右滑动手势
    MFMessageComposeViewController程序内发送短信息的实例
    FIELDSYMBOLS 学习—转载
  • 原文地址:https://www.cnblogs.com/dominjune/p/4715497.html
Copyright © 2011-2022 走看看