CSES - String Matching
Author: Dustin Miao
Solution - Knuth-Morris-Prat Algorithm
Define an array on some string such that stores the length of the longest nontrivial prefix of the entire string that is equivalent to a suffix ending at position . Formally,
If we are searching for string inside of string , create a new string , where is any arbitrary character that does not occur in either string. Then, create an array using the KMP algorithm. The answer is simply the number of indicies inside of that is equal to (the length of ).
C++
Time Complexity:
#include <bits/stdc++.h>using namespace std;namespace str {/** Computes the Pi array of s. */vector<int> pi(const string &s) {int n = (int)s.size();vector<int> pi_s(n);for (int i = 1, j = 0; i < n; i++) {while (j > 0 && s[j] != s[i]) { j = pi_s[j - 1]; }
Python
from typing import Listdef pi(s: str) -> List[int]:"""Computes the Pi array of s."""n = len(s)pi_s = [0] * nj = 0for i in range(1, n):while j > 0 and s[j] != s[i]:
Solution - Z-Algorithm
Like the previous solution, we now define an array such that is the length of the longest prefix beginning at index that is equivalent to a prefix of the entire string. Formally,
As before, for pattern string and text string , create a new string , and create the array using the z-algorithm. The answer is the number of indices inside of that is equal to .
C++
Time Complexity:
#include <bits/stdc++.h>using namespace std;namespace str {// Computes the Z-array of svector<int> z(const string &s) {int n = (int)s.size();vector<int> z_S(n);for (int i = 1, l = 0, r = 0; i < n; i++) {if (i <= r) { z_S[i] = min(z_S[i - l], r - i + 1); }
Solution - Rabin-Karp Algorithm
Precompute the rolling hash of both and . Each substring of length can be compared for equality in time. Since there is a relatively small number of comparisons, using a single set of hash values is fine (although it doesn't hurt to add more!). Using hash base and modulo suffices (see the string hashing module for more details on this choice).
C++
Time Complexity:
#include <bits/stdc++.h>using namespace std;namespace str {// Computes the rolling hash of s with power P and modulo Mvector<long long> rhash(const string &s, const long long P, const long long M) {int n = (int)s.size();vector<long long> rhash_S(n);for (int i = 0; i < n; i++) {if (i != 0) { rhash_S[i] = rhash_S[i - 1] * P % M; }
Join the USACO Forum!
Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!