题目链接

题目描述

给定字符串 的多个查询。对每个查询字符串(长度为 ),定义其前缀函数 的最长相等真前缀与真后缀的长度(可为 )。你需要输出整串的前缀函数:

解题思路

  • 。对 ,令 ,不断回退 直到
  • 若匹配则 ,令 。该算法按字符线性推进,每个位置的指针最多回退若干次,总体
  • 多组数据独立处理,保证所有 之和约束内可在线性时间完成。

代码

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int T; if (!(cin >> T)) return 0;
    while (T--) {
        int n; string s; cin >> n >> s;
        vector<int> pi(n, 0);
        for (int i = 1; i < n; ++i) {
            int j = pi[i - 1];
            while (j > 0 && s[i] != s[j]) j = pi[j - 1];
            if (s[i] == s[j]) ++j;
            pi[i] = j;
        }
        for (int i = 0; i < n; ++i) {
            if (i) cout << ' ';
            cout << pi[i];
        }
        cout << '\n';
    }
    return 0;
}
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int T = sc.nextInt();
        while (T-- > 0) {
            int n = sc.nextInt();
            String s = sc.next();
            int[] pi = new int[n];
            for (int i = 1; i < n; i++) {
                int j = pi[i - 1];
                while (j > 0 && s.charAt(i) != s.charAt(j)) j = pi[j - 1];
                if (s.charAt(i) == s.charAt(j)) j++;
                pi[i] = j;
            }
            StringBuilder out = new StringBuilder();
            for (int i = 0; i < n; i++) {
                if (i > 0) out.append(' ');
                out.append(pi[i]);
            }
            System.out.println(out.toString());
        }
    }
}
T = int(input())
for _ in range(T):
    parts = input().split()
    if len(parts) == 1:
        n = int(parts[0])
        s = input().strip()
    else:
        n = int(parts[0])
        s = parts[1]
    pi = [0] * n
    j = 0
    for i in range(1, n):
        while j > 0 and s[i] != s[j]:
            j = pi[j - 1]
        if s[i] == s[j]:
            j += 1
        pi[i] = j
    print(' '.join(str(x) for x in pi))

算法及复杂度

  • 算法:线性前缀函数(KMP 前缀表)迭代构造。
  • 时间复杂度:单组 ,多组总计
  • 空间复杂度