【ACWing】778. 字符串最大跨距

题目地址:

https://www.acwing.com/problem/content/780/

有三个字符串 S , S 1 , S 2 S,S_1,S_2 S,S1,S2,其中, S S S长度不超过 300 300 300 S 1 S_1 S1 S 2 S_2 S2的长度不超过 10 10 10。现在,我们想要检测 S 1 S_1 S1 S 2 S_2 S2是否同时在 S S S中出现,且 S 1 S_1 S1位于 S 2 S_2 S2的左边,并在 S S S中互不交叉(即, S 1 S_1 S1的右边界点在 S 2 S_2 S2的左边界点的左侧)。计算满足上述条件的最大跨距(即,最大间隔距离:最右边的 S 2 S_2 S2的起始点与最左边的 S 1 S_1 S1的终止点之间的字符数目)。如果没有满足条件的 S 1 S_1 S1 S 2 S_2 S2存在,则输出 − 1 −1 1。例如, S = a b c d 123 a b 888 e f g h i j 45 e f 67 k l , S 1 = a b , S 2 = e f S= abcd123ab888efghij45ef67kl, S_1= ab, S_2= ef S=abcd123ab888efghij45ef67kl,S1=ab,S2=ef,其中, S 1 S_1 S1 S S S中出现了 2 2 2次, S 2 S_2 S2也在 S S S中出现了 2 2 2次,最大跨距为: 18 18 18

输入格式:
输入共一行,包含三个字符串 S , S 1 , S 2 S,S_1,S_2 S,S1,S2,字符串之间用逗号隔开。数据保证三个字符串中不含空格和逗号。

输出格式:
输出一个整数,表示最大跨距。如果没有满足条件的 S 1 S_1 S1 S 2 S_2 S2存在,则输出 − 1 −1 1

可以用KMP。在找第二个字符串出现的最后位置的时候,可以将 S S S S 2 S_2 S2翻转然后用KMP找。代码如下:

#include <iostream>
#include <algorithm>
using namespace std;

const int N = 15;
string s, s1, s2;
int ne[N];

void build_next(string& p) {
    for (int i = 0, j = ne[0] = -1; i < p.size() - 1; ) {
        if (j == -1 || p[i] == p[j]) {
            i++;
            j++;
            ne[i] = p[i] != p[j] ? j : ne[j];
        } else j = ne[j];
    }
}

int find(string& p) {
    for (int i = 0, j = 0; i < s.size(); ) {
        if (j == -1 || s[i] == p[j]) {
            i++;
            j++;
        } else j = ne[j];

        if (j == p.size()) return i - j;
    }

    return -1;
}

int main() {
    char ch;
    while (cin >> ch, ch != ',') s += ch;
    while (cin >> ch, ch != ',') s1 += ch;
    while (cin >> ch) s2 += ch;

    build_next(s1);
    int l = find(s1);
    if (l == -1) {
        puts("-1");
        return 0;
    }
    reverse(s.begin(), s.end());
    reverse(s2.begin(), s2.end());
    build_next(s2);
    int r = find(s2);
    if (r == -1) {
        puts("-1");
        return 0;
    }

    r = s.size() - r - s2.size();
    l += s1.size() - 1;
    if (l >= r) puts("-1");
    else printf("%d\n", r - l - 1);

    return 0;
}

时间复杂度 O ( l S + l S 1 + l S 2 ) O(l_S+l_{S_1}+l_{S_2}) O(lS+lS1+lS2),空间 O ( l S ) O(l_S) O(lS)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值