KMP

题目链接

剪花布条

思路

KMP算法入门题,能写出算法就基本完成

有以点需要注意,因为花布条要被剪掉,因此重复的部分不可取

如 abababac    aba

abababac

aba          相互匹配减去新的字符串就是  babac ,而不要从第二位开始查找

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1000000;
int cnt;
string s, p;
int f[N];
void getf()
{
    f[0] = -1;
    int i = 0, j = -1;

    while (i < p.size())
    {
        if (j == -1 || p[i] == p[j])
        {
            ++i;
            ++j;
            f[i] = j;
        }
        else
            j = f[j];
    }
}
void solve()
{
    int i = 0;
    int j = 0;
    while (i < s.size())
    {
        if (j == -1 || s[i] == p[j])
        {
            i++;
            j++;
        }
        else
            j = f[j];
        if (j == p.size())
        {
            cnt++;
            j = 0;
          
        }
    }
}
int main()
{
    while (1)
    {
        cnt = 0;
        cin >> s;
        if (s.size() == 1 && s[0] == '#')
            break;
        cin >> p;
        getf();
        solve();
        cout << cnt << endl;
    }
    return 0;
}

 

题目链接

B - Period

思路

 

代码

 

题目链接

C - Power Strings

题意

找出s字符串由多少个重复子串循环构成

思路

 先求出 s 字符串的 next 数组,设 len 为 s 长度 其len-next [len ] 就是到 s 结尾循环节是多少

 那么len / (len - next [len ] )就是有几个循环节 , 注意一定要len能够整除(len-next[len]),否则输出 1

代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int N = 10000000;
string s;
char p[N << 1];
int f[N], len;
void getf()
{
    f[0] = -1;
    int i = 0, j = -1;

    while (i < len)
    {
        if (j == -1 || p[i] == p[j])
        {
            i++;
            j++;
            f[i] = j;
        }
        else
            j = f[j];
    }
}
int main()
{
    while (1)
    {
        scanf("%s", p);
        len = strlen(p);
        if (p[0] == '.' && len == 1)
            break;
        getf();
        if (len % (len - f[len]) == 0)
        {
            cout << len / (len - f[len]) << endl;
        }
        else
            cout << 1 << endl;
    }
    return 0;
}

 

题目链接

D - Oulipo

题意

给定一个单词 W 和文本 T 求 W 在 T 中出现几次

思路

 求出 next 数组再遍历 T 查找就可以了,注意匹配成功时 j 的回溯

代码

#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
const int N = 1000000;
string s, p;
int f[N], cnt;
void grt_f()
{
    int i = 0, j = -1;
    f[0] = -1;
    while (i < p.size())
    {
        if (j == -1 || p[i] == p[j])
            f[++i] = ++j;
        else
            j = f[j];
    }
}
void solve()
{
    int i = 0, j = 0;
    while (i < s.size())
    {
        if (j == -1 || s[i] == p[j])
        {
            i++;
            j++;
        }
        else
            j = f[j];
        if (j == p.size())
        {
            j = f[j];
            cnt++;
        }
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int T;
    cin >> T;
    while (T--)
    {
        cnt = 0;
        cin >> p >> s;
        grt_f();
        solve();
        cout << cnt << endl;
    }

    return 0;
}

 

题目链接

E - Seek the Name, Seek the Fame

题意

给一个字符串 S 求其所以相同前后缀的长度,以升序输出

思路

计算原字符串的hash。然后枚举长度,判断 前 len 的长度的字符串hash和后 len 长度的字符串hash

代码

 

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 400010;
string s;
char p[400010];
int f[N], d[N], cnt, len;
void grt_f()
{
    int i = 0, j = -1;
    f[0] = -1;
    while (i < len)
    {
        if (j == -1 || p[i] == p[j])
            f[++i] = ++j;
        else
            j = f[j];
    }
}
void solve()
{
    int i = 0, j = 0;
    while (i < s.size())
    {
        if (j == -1 || s[i] == p[j])
        {
            i++;
            j++;
        }
        else
            j = f[j];
        if (j == len)
        {
            j = f[j];
            cnt++;
        }
    }
}

int main()
{
    while (scanf("%s", p)!=EOF)
    {
        len = strlen(p);
        cnt = 0;
        grt_f();
        int count = 0;
        int t = f[len - 1];
        while (t != -1)
        {
            if (p[t] == p[len - 1])
                d[count++] = t + 1;
            t = f[t];
        }
        for (int i = count - 1; i >= 0; i--)
            printf("%d ", d[i]);
        printf("%d\n", len);
    }

    return 0;
}

 

总结

果然,字符串ksm不好理解,题目答案很简单,但是不好理解,对 next 数组理解不够

要多看看

posted @ 2022-04-04 11:09  黎_lyh  阅读(26)  评论(0)    收藏  举报