Prefix Function and KMP Algorithm for Competitive Programming
Last Updated :
14 Jun, 2024
The prefix function is a string matching technique used in computer science and string algorithms. It efficiently computes an array that represents the length of the longest proper prefix which is also a suffix for each prefix of a given string. The Knuth-Morris-Pratt (KMP) algorithm utilizes the prefix function to perform pattern matching in linear time, making it an efficient algorithm for searching occurrences of a pattern within a text.
What is KMP Algorithm?
Knuth–Morris–Pratt (KMP) Algorithm is a linear time string searching algorithm that efficiently finds occurrences of a pattern within a text.
What is Prefix Function in KMP Algorithm?
The Prefix Function is an integral part of the Knuth–Morris–Pratt Algorithm.
The prefix function for a string s is an array \pi
, where \pi[i]
is the length of the longest proper prefix of the substring s[0...i]
    which is also a suffix of this substring. Proper prefix of a string is a prefix that is not equal to the string itself. It is obvious that \pi[0]=0
because a string of length 1
has no proper prefixes.
Examples:
Example 1: s="xyzxyzx"
Prefix Function for s will be
\pi
=[
0,0,0,1,2,3,4]
Example 2: s="xxyxxxy"
Prefix Function for s will be
\pi
=[
0,1,0,1,2,2,3]
Find Prefix Function (O(N3) approach):
The idea is to do the following: For all i from 0 to N-1, try all possible lengths for the prefix/suffix, with each comparison taking O(N) time.
Below is the implementation of above approach:
C++
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// Function to compute the Prefix Function using an O(N^3) approach
vector<int> prefixFunction(string s) {
int n = s.length();
vector<int> pi(n, 0);
// Iterate through each position in the string
for (int i = 0; i < n; i++) {
// Try all possible lengths for the prefix/suffix
for (int j = 0; j < i; j++) {
// Check if the substrings are equal
if (s.substr(0, j + 1) == s.substr(i - j, j + 1)) {
pi[i] = j + 1; // If equal, update the value at the current position
}
}
}
// Return the computed Prefix Function
return pi;
}
// Driver Code
int main() {
string s = "abcabcabc";
vector<int> result = prefixFunction(s);
// Print the Prefix Function values
for (int val : result) {
cout << val << " ";
}
cout << endl;
return 0;
}
Java
import java.util.ArrayList;
import java.util.List;
public class PrefixFunction {
// Function to compute the Prefix Function using an O(N^3) approach
public static List<Integer> prefixFunction(String s) {
int n = s.length();
List<Integer> pi = new ArrayList<>(n);
// Iterate through each position in the string
for (int i = 0; i < n; i++) {
pi.add(0); // Initialize the value at the current position
// Try all possible lengths for the prefix/suffix
for (int j = 0; j < i; j++) {
// Check if the substrings are equal
if (s.substring(0, j + 1).equals(s.substring(i - j, i + 1))) {
pi.set(i, j + 1); // If equal, update the value at the current position
}
}
}
// Return the computed Prefix Function
return pi;
}
// Driver Code
public static void main(String[] args) {
String s = "abcabcabc";
List<Integer> result = prefixFunction(s);
// Print the Prefix Function values
for (int val : result) {
System.out.print(val + " ");
}
System.out.println();
}
}
// This code is contributed by akshitaguprzj3
Python
# Function to compute the Prefix Function using an O(N^3) approach
def prefix_function(s):
n = len(s)
pi = [0] * n
# Iterate through each position in the string
for i in range(n):
pi[i] = 0 # Initialize the value at the current position
# Try all possible lengths for the prefix/suffix
for j in range(i):
# Check if the substrings are equal
if s[:j + 1] == s[i - j:i + 1]:
pi[i] = j + 1 # If equal, update the value at the current position
# Return the computed Prefix Function
return pi
# Driver Code
if __name__ == "__main__":
s = "abcabcabc"
result = prefix_function(s)
# Print the Prefix Function values in a single line
print(*result)
JavaScript
// Function to compute the Prefix Function using an O(N^3) approach
function prefixFunction(s) {
const n = s.length;
const pi = new Array(n).fill(0);
// Iterate through each position in the string
for (let i = 0; i < n; i++) {
pi[i] = 0; // Initialize the value at the current position
// Try all possible lengths for the prefix/suffix
for (let j = 0; j < i; j++) {
// Check if the substrings are equal
if (s.substring(0, j + 1) === s.substring(i - j, i + 1)) {
pi[i] = j + 1; // If equal, update the value at the current position
}
}
}
// Return the computed Prefix Function
return pi;
}
// Driver Code
const s = "abcabcabc";
const result = prefixFunction(s);
// Print the Prefix Function values in a single line
console.log(result.join(" "));
Find Prefix Function in O(N2) time:
It can be observed that \pi[i+1]<=\pi[i]+1
. This can be proved by contradiction. If \pi[i+1]>\pi[i]+1
, then we can take the suffix of length \pi[i+1]
that is ending at index i+1, remove the last character from it, then we get a better suffix of length \pi[i+1]-1
ending at position i, which is better than the value \pi[i]
, which leads to a contradiction. Now since the value of prefix function can increase by at most 1, this means the function can grow at most N times and it can only decrease for at most N times too. So total no. comparisons can be 2*N, which gives a complexity of O(N2).
Below is the implementation of above approach:
C++
#include <iostream>
#include <vector>
#include <string>
std::vector<int> prefix_function(const std::string& s) {
int n = s.size();
std::vector<int> pi(n, 0); // Initialize an array to store the prefix function values
// Iterate through each position in the string starting from the second character
for (int i = 1; i < n; ++i) {
int j = pi[i - 1]; // Initialize j with the previous prefix function value
// Iterate backwards through possible lengths for the prefix/suffix
while (j > 0 && s[j] != s[i]) {
j = pi[j - 1]; // Update j based on the previous prefix function value
}
// Check if the substrings are equal
if (s[j] == s[i]) {
++j; // If equal, update the value of j
}
pi[i] = j; // Update the prefix function value at the current position
}
// Return the computed Prefix Function
return pi;
}
int main() {
// Example usage:
std::string s = "xyzxyzx";
std::vector<int> result = prefix_function(s);
std::cout << "Prefix Function:";
for (int value : result) {
std::cout << " " << value;
}
std::cout << std::endl;
return 0;
}
Java
import java.util.Arrays;
public class PrefixFunction {
static int[] prefixFunction(String s) {
int n = s.length();
int[] pi = new int[n]; // Initialize an array to store the prefix function values
// Iterate through each position in the string starting from the second character
for (int i = 1; i < n; i++) {
int j = pi[i - 1]; // Initialize j with the previous prefix function value
// Iterate backwards through possible lengths for the prefix/suffix
while (j > 0 && s.charAt(j) != s.charAt(i)) {
j = pi[j - 1]; // Update j based on the previous prefix function value
}
// Check if the substrings are equal
if (s.charAt(j) == s.charAt(i)) {
j++; // If equal, update the value of j
}
pi[i] = j; // Update the prefix function value at the current position
}
// Return the computed Prefix Function
return pi;
}
public static void main(String[] args) {
String s = "xyzxyzx";
int[] result = prefixFunction(s);
System.out.println("Prefix Function: " + Arrays.toString(result));
}
}
Python
def prefix_function(s):
n = len(s)
pi = [0] * n # Initialize an array to store the prefix function values
# Iterate through each position in the string starting from the second character
for i in range(1, n):
j = pi[i - 1] # Initialize j with the previous prefix function value
# Iterate backwards through possible lengths for the prefix/suffix
while j > 0 and s[j] != s[i]:
j = pi[j - 1] # Update j based on the previous prefix function value
# Check if the substrings are equal
if s[j] == s[i]:
j += 1 # If equal, update the value of j
pi[i] = j # Update the prefix function value at the current position
# Return the computed Prefix Function
return pi
# Example usage:
s = "xyzxyzx"
result = prefix_function(s)
print("Prefix Function:", result)
JavaScript
function prefixFunction(s) {
const n = s.length;
const pi = new Array(n).fill(0); // Initialize an array to store the prefix function
//values
// Iterate through each position in the string starting from the second character
for (let i = 1; i < n; ++i) {
let j = pi[i - 1]; // Initialize j with the previous prefix function value
// Iterate backwards through possible lengths for the prefix/suffix
while (j > 0 && s[j] !== s[i]) {
j = pi[j - 1]; // Update j based on the previous prefix function value
}
// Check if the substrings are equal
if (s[j] === s[i]) {
++j; // If equal, update the value of j
}
pi[i] = j; // Update the prefix function value at the current position
}
// Return the computed Prefix Function
return pi;
}
// Example usage:
const s = "xyzxyzx";
const result = prefixFunction(s);
console.log("Prefix Function:", result.join(" "));
//This code is contributed by Utkarsh
OutputPrefix Function: 0 0 0 1 2 3 4
Find Prefix Function (Linear approach):
We can optimize the above approach to O(N). To compute \pi[i+1]
, if s[i+1]=s[\pi[i]]
, then \pi[i+1]=\pi[i]+1
, otherwise then we need to find the largest index j, such that j<\pi[i]
and s[0...j-1]=s[i-j+1....i]
. Then we can compare characters at index j and i+1, if they are equal then \pi[i+1]=j+1
, otherwise we need to find the next shortest j and repeat the procedure. If j becomes 0, then if s[i+1]=s[0]
, then \pi[i+1]
will be 1 else 0.
For efficiently computing j, suppose we are currently at index i, we need to find the largest index j that holds the following condition: s[0...j-1]=s[i-j+1....i]
, this value is nothing but \pi[i-1]
.
Below is the algorithm for the above approach:
- Create an array pi, which denotes the prefix function for string s. Initialize p[0] with 0.
- Run a loop from i=1 to n-1,
- Assign j to pi[i-1], j denotes the largest index which holds the following condition: s[0...j-1]=s[i-j+1....i]
.
- Compare s[j] and s[i], if they are equal assign p[i] will become j+1, else j will now become pi[j-1].
- Repeat the same procedure till j is greater than 0. If j becomes, s[0] and s[i] will get compared, if they are equal pi[i] will be 1 else 0.
- Return pi.
Below is the implementation of above approach:
C++
#include <iostream>
#include <string>
#include <vector>
using namespace std;
// Function to compute the optimized Prefix Function of a
// string in O(N) time
vector<int> prefix_function(string s)
{
int n = s.size();
// Create a vector to store the values of the Prefix
// Function
vector<int> pi(n);
// Iterate through the string starting from the second
// character
for (int i = 1; i < n; i++) {
// Initialize j with the value from the previous
// position
int j = pi[i - 1];
// Continue updating j until a match is found or j
// becomes 0
while (j > 0 && s[i] != s[j])
j = pi[j - 1];
// If a match is found, increment the length of the
// common prefix/suffix
if (s[i] == s[j])
j++;
// Update the Prefix Function value for the current
// position
pi[i] = j;
}
// Return the computed Prefix Function
return pi;
}
int main()
{
// Example usage
string text = "abababab";
vector<int> pf = prefix_function(text);
// Output the computed prefix function
cout << "Prefix Function values for string \"" << text
<< "\": ";
for (int i = 0; i < pf.size(); i++) {
cout << pf[i] << " ";
}
cout << endl;
return 0;
}
Java
import java.util.*;
public class PrefixFunction {
// Function to compute the optimized Prefix Function of
// a string
public static List<Integer> prefixFunction(String s)
{
int n = s.length();
// Create an ArrayList to store the values of the
// Prefix Function
List<Integer> pi
= new ArrayList<>(Collections.nCopies(n, 0));
// Iterate through the string starting from the
// second character
for (int i = 1; i < n; i++) {
// Initialize j with the value from the previous
// position
int j = pi.get(i - 1);
// Continue updating j until a match is found or
// j becomes 0
while (j > 0 && s.charAt(i) != s.charAt(j))
j = pi.get(j - 1);
// If a match is found, increment the length of
// the common prefix/suffix
if (s.charAt(i) == s.charAt(j))
j++;
// Update the Prefix Function value for the
// current position
pi.set(i, j);
}
// Return the computed Prefix Function
return pi;
}
public static void main(String[] args)
{
// Example usage
String text = "abababab";
List<Integer> pf = prefixFunction(text);
// Output the computed prefix function
System.out.print(
"Prefix Function values for string \"" + text
+ "\": ");
for (int i = 0; i < pf.size(); i++) {
System.out.print(pf.get(i) + " ");
}
System.out.println();
}
}
Python
def prefix_function(s):
n = len(s)
pi = [0] * n
for i in range(1, n):
j = pi[i - 1]
while j > 0 and s[i] != s[j]:
j = pi[j - 1]
if s[i] == s[j]:
j += 1
pi[i] = j
return pi
def main():
# Example usage
text = "abababab"
pf = prefix_function(text)
# Output the computed prefix function
print("Prefix Function values for string \"{}\": {}".format(
text, " ".join(map(str, pf))))
if __name__ == "__main__":
main()
JavaScript
function prefixFunction(s) {
const n = s.length;
// Create an array to store the values of the Prefix Function
const pi = new Array(n).fill(0);
// Iterate through the string starting from the second character
for (let i = 1; i < n; i++) {
// Initialize j with the value from the previous position
let j = pi[i - 1];
// Continue updating j until a match is found or j becomes 0
while (j > 0 && s.charAt(i) !== s.charAt(j)) {
j = pi[j - 1];
}
// If a match is found, increment the length of the common prefix/suffix
if (s.charAt(i) === s.charAt(j)) {
j++;
}
// Update the Prefix Function value for the current position
pi[i] = j;
}
// Return the computed Prefix Function
return pi;
}
function main() {
// Example usage
const text = "abababab";
const pf = prefixFunction(text);
// Output the computed prefix function
console.log(`Prefix Function values for string "${text}": ${pf.join(' ')}`);
}
main();
OutputPrefix Function values for string "abababab": 0 0 1 2 3 4 5 6
Use Cases of Prefix Function and KMP Algorithm in Competitive Programming:
1. Pattern Searching- The Knuth-Morris-Pratt algorithm:
Problem: Given a patter p and text t, the task is to find all occurrences of pattern p in text t.
The idea is to choose a character ($ or #) which is not present in any of the string p and t, which acts a separator. Compute the prefix function for the string p+#+t. Notice the value of prefix function at any index will not exceed n because of the separator. Now if \pi[i]=n
, at any position i, that means a match is found, i.e., occurrence of patter p in text t. Notice the \pi[i]=n
, won't be true for first n+1 positions in prefix function since it belongs to pattern p and separator #. Hence we take all positions where .
Below is the implementation of above approach:
C++
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class KMPAlgorithm {
public:
// Function to compute the optimized Prefix Function of a string in O(N) time
static vector<int> prefixFunction(const string& s) {
int n = s.size();
vector<int> pi(n);
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;
}
return pi;
}
// Function to find all occurrences of pattern p in text t using KMP algorithm
static vector<int> patternSearching(const string& t, const string& p) {
int n = p.size(), m = t.size();
string s = p + "#" + t;
vector<int> pi = prefixFunction(s);
vector<int> ans;
for (int i = n + 1; i < n + 1 + m; i++) {
if (pi[i] == n) {
ans.push_back(i - 2 * n);
}
}
return ans;
}
};
// Example usage
int main() {
string text = "ababcababcabc";
string pattern = "abc";
vector<int> occurrences = KMPAlgorithm::patternSearching(text, pattern);
cout << "Pattern occurrences: ";
for (int pos : occurrences) {
cout << pos << " ";
}
cout << endl;
return 0;
}
Java
import java.util.ArrayList;
import java.util.List;
public class KMPAlgorithm {
// Function to compute the optimized Prefix Function of a string in O(N) time
public static int[] prefixFunction(String s) {
int n = s.length();
// Create an array to store the values of the Prefix Function
int[] pi = new int[n];
// Iterate through the string starting from the second character
for (int i = 1; i < n; i++) {
// Initialize j with the value from the previous position
int j = pi[i - 1];
// Continue updating j until a match is found or j becomes 0
while (j > 0 && s.charAt(i) != s.charAt(j))
j = pi[j - 1];
// If a match is found, increment the length of the common prefix/suffix
if (s.charAt(i) == s.charAt(j))
j++;
// Update the Prefix Function value for the current position
pi[i] = j;
}
// Return the computed Prefix Function
return pi;
}
// Function to find all occurrences of pattern p in text t using KMP algorithm
public static List<Integer> patternSearching(String t, String p) {
int n = p.length(), m = t.length();
// Combine pattern p, separator '#', and text t
String s = p + "#" + t;
// Compute the Prefix Function for the combined string
int[] pi = prefixFunction(s);
// List to store the positions where the pattern is found in the text
List<Integer> ans = new ArrayList<>();
// Iterate through the Prefix Function results to find pattern occurrences
for (int i = n + 1; i < n + 1 + m; i++) { // Adjust index based on combined string
if (pi[i] == n) {
ans.add(i - 2 * n); // Record the starting position of the pattern occurrence
}
}
// Return the positions where the pattern is found in the text
return ans;
}
public static void main(String[] args) {
String text = "ababcababcabc";
String pattern = "abc";
// Find all occurrences of pattern in the text using KMP algorithm
List<Integer> occurrences = patternSearching(text, pattern);
// Print the positions where the pattern is found
System.out.println("Pattern occurrences: " + occurrences);
}
}
Python
def prefix_function(s):
"""
Function to compute the optimized Prefix Function of a string in O(N) time
Args:
s (str): The input string
Returns:
list: The Prefix Function values for the input string
"""
n = len(s)
pi = [0] * n # Create an array to store the values of the Prefix Function
# Iterate through the string starting from the second character
for i in range(1, n):
# Initialize j with the value from the previous position
j = pi[i - 1]
# Continue updating j until a match is found or j becomes 0
while j > 0 and s[i] != s[j]:
j = pi[j - 1]
# If a match is found, increment the length of the common prefix/suffix
if s[i] == s[j]:
j += 1
# Update the Prefix Function value for the current position
pi[i] = j
# Return the computed Prefix Function
return pi
def pattern_searching(t, p):
"""
Function to find all occurrences of pattern p in text t using KMP algorithm
Args:
t (str): The input text
p (str): The pattern to search for in the text
Returns:
list: Positions where the pattern is found in the text
"""
n, m = len(p), len(t)
# Combine pattern p, separator '#', and text t
s = p + '#' + t
# Compute the Prefix Function for the combined string
pi = prefix_function(s)
# List to store the positions where the pattern is found in the text
occurrences = []
# Iterate through the Prefix Function results to find pattern occurrences
for i in range(n + 1, n + m + 1):
if pi[i] == n:
# Record the starting position of the pattern occurrence
occurrences.append(i - 2 * n)
# Return the positions where the pattern is found in the text
return occurrences
text = "ababcababcabc"
pattern = "abc"
# Find all occurrences of pattern in the text using KMP algorithm
occurrences = pattern_searching(text, pattern)
# Print the positions where the pattern is found
print("Pattern occurrences:", occurrences)
JavaScript
class KMPAlgorithm {
// Function to compute the optimized Prefix Function of a string in O(N) time
static prefixFunction(s) {
let n = s.length;
// Create an array to store the values of the Prefix Function
let pi = new Array(n).fill(0);
// Iterate through the string starting from the second character
for (let i = 1; i < n; i++) {
// Initialize j with the value from the previous position
let j = pi[i - 1];
// Continue updating j until a match is found or j becomes 0
while (j > 0 && s[i] !== s[j]) {
j = pi[j - 1];
}
// If a match is found, increment the length of the common prefix/suffix
if (s[i] === s[j]) {
j++;
}
// Update the Prefix Function value for the current position
pi[i] = j;
}
// Return the computed Prefix Function
return pi;
}
// Function to find all occurrences of pattern p in text t using KMP algorithm
static patternSearching(t, p) {
let n = p.length, m = t.length;
// Combine pattern p, separator '#', and text t
let s = p + "#" + t;
// Compute the Prefix Function for the combined string
let pi = KMPAlgorithm.prefixFunction(s);
// Array to store the positions where the pattern is found in the text
let ans = [];
// Iterate through the Prefix Function results to find pattern occurrences
for (let i = n + 1; i < n + 1 + m; i++) {
if (pi[i] === n) {
ans.push(i - 2 * n); // Record the starting position of the pattern occurrence
}
}
// Return the positions where the pattern is found in the text
return ans;
}
}
// Example usage
let text = "ababcababcabc";
let pattern = "abc";
// Find all occurrences of pattern in the text using KMP algorithm
let occurrences = KMPAlgorithm.patternSearching(text, pattern);
// Print the positions where the pattern is found
console.log("Pattern occurrences: ", occurrences);
// This code is contributed by Rambabu
2. Count the number of occurrences of each prefix in same string:
Problem: Given a string s, find the number of occurrences of each prefix of string s in the same string i.e., string s.
The idea is to calculate the prefix function for the string s. Notice that each prefix appears at least 1 times, so we initialize the answer array with 1. Now \pi[i]
denotes the length of longest prefix that occurs in s and ends at position i. The next shortest prefix of length j that occurs in s and ends at position i can be determined by \pi[j-1]
and so on. To compute the final answer array efficiently, we count the number of number of times each value in prefix function appears. Then iterate from n-1 to 1 and for each value of increment the value at index \pi[i-1]
of final answer array by \pi[i]
.
Below is the implementation of above approach:
C++
// Function to compute the optimized Prefix Function of a
// string in O(N) time
vector<int> prefix_function(string s) {
int n = s.size();
// Create a vector to store the values of the Prefix
// Function
vector<int> pi(n);
// Iterate through the string starting from the second
// character
for (int i = 1; i < n; i++) {
// Initialize j with the value from the previous
// position
int j = pi[i - 1];
// Continue updating j until a match is found or j
// becomes 0
while (j > 0 && s[i] != s[j])
j = pi[j - 1];
// If a match is found, increment the length of the
// common prefix/suffix
if (s[i] == s[j])
j++;
// Update the Prefix Function value for the current
// position
pi[i] = j;
}
// Return the computed Prefix Function
return pi;
}
// Function to count the number of occurrences of each
// prefix in the same string
vector<int> prefix_occurrence(string s) {
int n = s.size();
// Compute the Prefix Function
vector<int> pi = prefix_function(s), count(n + 1, 0);
// Count the occurrences of each value in the Prefix Function
for (int i = 0; i < n; i++)
count[pi[i]]++;
// Iterate from n-1 to 1 and update the count array
for (int i = n - 1; i > 0; i--)
count[pi[i - 1]] += count[i];
// Increment the count array for each prefix
for (int i = 1; i <= n; i++)
count[i]++;
return count;
}
Java
import java.util.*;
public class PrefixFunction {
// Function to compute the optimized Prefix Function of
// a string in O(N) time
static int[] prefixFunction(String s)
{
int n = s.length();
// Create an array to store the values of the Prefix
// Function
int[] pi = new int[n];
// Iterate through the string starting from the
// second character
for (int i = 1; i < n; i++) {
// Initialize j with the value from the previous
// position
int j = pi[i - 1];
// Continue updating j until a match is found or
// j becomes 0
while (j > 0 && s.charAt(i) != s.charAt(j))
j = pi[j - 1];
// If a match is found, increment the length of
// the common prefix/suffix
if (s.charAt(i) == s.charAt(j))
j++;
// Update the Prefix Function value for the
// current position
pi[i] = j;
}
// Return the computed Prefix Function
return pi;
}
// Function to count the number of occurrences of each
// prefix in the same string
static int[] prefixOccurrence(String s)
{
int n = s.length();
// Compute the Prefix Function
int[] pi = prefixFunction(s);
int[] count = new int[n + 1];
// Count the occurrences of each value in the Prefix
// Function
for (int i = 0; i < n; i++)
count[pi[i]]++;
// Iterate from n-1 to 1 and update the count array
for (int i = n - 1; i > 0; i--)
count[pi[i - 1]] += count[i];
// Increment the count array for each prefix
for (int i = 1; i <= n; i++)
count[i]++;
return count;
}
// Main method to test the functions
public static void main(String[] args)
{
String s = "abababa";
int[] prefix = prefixFunction(s);
int[] occurrence = prefixOccurrence(s);
System.out.println("Prefix Function:");
System.out.println(Arrays.toString(prefix));
System.out.println("Prefix Occurrence:");
System.out.println(Arrays.toString(occurrence));
}
}
// This code is contributed by Rambabu
3. Count the number of occurrences of each prefix in some other string:
Problem: Given a string s, find the number of occurrences of each prefix of string s in the string t.
The idea is to compute the prefix function of the string s#t. Notice that we only care about the value \pi[i]
, where i>n since we need to find number of occurrences of s in t, and t begins from index n+1, where n is the length of string s. Now we can repeat the same procedure as we did in counting the number of occurrences of each prefix in same string.
Below is the implementation of above approach:
C++
#include <bits/stdc++.h>
using namespace std;
// Function to compute the optimized Prefix Function of a
// string in O(N) time
vector<int> prefix_function(string s)
{
int n = s.size();
// Create a vector to store the values of the Prefix
// Function
vector<int> pi(n);
// Iterate through the string starting from the second
// character
for (int i = 1; i < n; i++) {
// Initialize j with the value from the previous
// position
int j = pi[i - 1];
// Continue updating j until a match is found or j
// becomes 0
while (j > 0 && s[i] != s[j])
j = pi[j - 1];
// If a match is found, increment the length of the
// common prefix/suffix
if (s[i] == s[j])
j++;
// Update the Prefix Function value for the current
// position
pi[i] = j;
}
// Return the computed Prefix Function
return pi;
}
// Function to count the number of occurrences of each
// prefix of string s in a different string t
vector<int> prefix_occurrence(string s, string t)
{
int n = s.size();
int m = t.size();
// Combine strings s and t with a separator '#'
string combined_string = s + "#" + t;
// Compute the Prefix Function for the combined string
vector<int> pi = prefix_function(combined_string),
count(n + 1, 0);
// Count the occurrences of each value in the Prefix
// Function
for (int i = n + 1; i <= n + m; i++)
count[pi[i]]++;
// Iterate from n-1 to 1 and update the count array
for (int i = n - 1; i > 0; i--)
count[pi[i - 1]] += count[i];
// Increment the count array for each prefix
for (int i = 1; i <= n; i++)
count[i]++;
return count;
}
// Main function with example
int main()
{
// Example
string s = "aba";
string t = "abacaba";
vector<int> occurrences = prefix_occurrence(s, t);
cout << "Occurrences of prefixes of \"" << s
<< "\" in \"" << t << "\": ";
for (int occ : occurrences) {
cout << occ << " ";
}
cout << endl;
return 0;
}
Java
import java.util.*;
public class PrefixFunction {
// Function to compute the optimized Prefix Function of
// a string in O(N) time
static List<Integer> prefixFunction(String s)
{
int n = s.length();
// Create a list to store the values of the Prefix
// Function
List<Integer> pi = new ArrayList<>(n);
// Initialize the first element of pi with 0
pi.add(0);
// Iterate through the string starting from the
// second character
for (int i = 1; i < n; i++) {
// Initialize j with the value from the previous
// position
int j = pi.get(i - 1);
// Continue updating j until a match is found or
// j becomes 0
while (j > 0 && s.charAt(i) != s.charAt(j))
j = pi.get(j - 1);
// If a match is found, increment the length of
// the common prefix/suffix
if (s.charAt(i) == s.charAt(j))
j++;
// Update the Prefix Function value for the
// current position
pi.add(j);
}
// Return the computed Prefix Function
return pi;
}
// Function to count the number of occurrences of each
// prefix of string s in a different string t
static List<Integer> prefixOccurrence(String s,
String t)
{
int n = s.length();
int m = t.length();
// Combine strings s and t with a separator '#'
String combinedString = s + "#" + t;
// Compute the Prefix Function for the combined
// string
List<Integer> pi = prefixFunction(combinedString);
List<Integer> count = new ArrayList<>(
Collections.nCopies(n + 1, 0));
// Count the occurrences of each value in the Prefix
// Function
for (int i = n + 1; i <= n + m; i++)
count.set(pi.get(i), count.get(pi.get(i)) + 1);
// Iterate from n-1 to 1 and update the count list
for (int i = n - 1; i > 0; i--)
count.set(pi.get(i - 1),
count.get(pi.get(i - 1))
+ count.get(i));
// Increment the count list for each prefix
for (int i = 1; i <= n; i++)
count.set(i, count.get(i) + 1);
return count;
}
// Main method with example
public static void main(String[] args)
{
// Example
String s = "aba";
String t = "abacaba";
List<Integer> occurrences = prefixOccurrence(s, t);
System.out.println("Occurrences of prefixes of \""
+ s + "\" in \"" + t
+ "\": " + occurrences);
}
}
Python
def prefix_function(s):
n = len(s)
pi = [0] * n
for i in range(1, n):
j = pi[i - 1]
while j > 0 and s[i] != s[j]:
j = pi[j - 1]
if s[i] == s[j]:
j += 1
pi[i] = j
return pi
def prefix_occurrence(s, t):
n = len(s)
m = len(t)
combined_string = s + '#' + t
pi = prefix_function(combined_string)
count = [0] * (n + 1)
for i in range(n + 1, n + m + 1):
count[pi[i]] += 1
for i in range(n - 1, 0, -1):
count[pi[i - 1]] += count[i]
for i in range(1, n + 1):
count[i] += 1
return count
# Main method with example
if __name__ == "__main__":
s = "aba"
t = "abacaba"
occurrences = prefix_occurrence(s, t)
print(f'Occurrences of prefixes of "{s}" in "{t}": {occurrences}')
JavaScript
// Function to compute the optimized Prefix Function of a
// string in O(N) time
function prefixFunction(s) {
const n = s.length;
// Create an array to store the values of the Prefix Function
const pi = new Array(n).fill(0);
// Iterate through the string starting from the second character
for (let i = 1; i < n; i++) {
// Initialize j with the value from the previous position
let j = pi[i - 1];
// Continue updating j until a match is found or j becomes 0
while (j > 0 && s[i] !== s[j])
j = pi[j - 1];
// If a match is found, increment the length of the common prefix/suffix
if (s[i] === s[j])
j++;
// Update the Prefix Function value for the current position
pi[i] = j;
}
// Return the computed Prefix Function
return pi;
}
// Function to count the number of occurrences of each
// prefix of string s in a different string t
function prefixOccurrence(s, t) {
const n = s.length;
const m = t.length;
// Combine strings s and t with a separator '#'
const combinedString = s + "#" + t;
// Compute the Prefix Function for the combined string
const pi = prefixFunction(combinedString);
const count = new Array(n + 1).fill(0);
// Count the occurrences of each value in the Prefix Function
for (let i = n + 1; i <= n + m; i++)
count[pi[i]]++;
// Iterate from n-1 to 1 and update the count array
for (let i = n - 1; i > 0; i--)
count[pi[i - 1]] += count[i];
// Increment the count array for each prefix
for (let i = 1; i <= n; i++)
count[i]++;
return count;
}
// Main function with example
function main() {
// Example
const s = "aba";
const t = "abacaba";
const occurrences = prefixOccurrence(s, t);
process.stdout.write("Occurrences of prefixes of \"" + s + "\" in \"" + t + "\": ");
for (const occ of occurrences) {
process.stdout.write(occ + " ");
}
process.stdout.write("\n");
}
// Run main function
main();
//This code is contribited by Prachi.
OutputOccurrences of prefixes of "aba" in "abacaba": 5 3 3 3
4. Count the number of occurrences of each prefix in same string that also occurs as the suffix:
Problem: Given a string s, find the number of occurrences of each prefix of string s in the string s which also occurs as the suffix of string s.
The idea is the compute the prefix function of string s. To find the number of occurrence of each prefix in sting s we can repeat the same procedure as done above. Now to find the lengths of prefix which also appears as suffix in string s,are- \pi[n-1]
, \pi[\pi[n-1]]
,... and so on. The number of times each of these prefixes occurs in string s can be directly determined as we pre computed the array which finds the number of occurrence of each prefix of string s in sting s.
Below is the implementation of above approach:
C++
#include <bits/stdc++.h>
using namespace std;
// Function to compute the optimized Prefix Function of a
// string in O(N) time
vector<int> prefix_function(string s)
{
int n = s.size();
// Create a vector to store the values of the Prefix
// Function
vector<int> pi(n);
// Iterate through the string starting from the second
// character
for (int i = 1; i < n; i++) {
// Initialize j with the value from the previous
// position
int j = pi[i - 1];
// Continue updating j until a match is found or j
// becomes 0
while (j > 0 && s[i] != s[j])
j = pi[j - 1];
// If a match is found, increment the length of the
// common prefix/suffix
if (s[i] == s[j])
j++;
// Update the Prefix Function value for the current
// position
pi[i] = j;
}
// Return the computed Prefix Function
return pi;
}
// Function to count the number of occurrences of each
// prefix of string s in the same string s that also occurs
// as the suffix of s
void prefix_occurrence_with_suffix(string s)
{
int n = s.size();
// Compute the Prefix Function
vector<int> pi = prefix_function(s), count(n + 1, 0);
// Count the occurrences of each value in the Prefix
// Function
for (int i = 0; i < n; i++)
count[pi[i]]++;
// Iterate from n-1 to 1 and update the count array
for (int i = n - 1; i > 0; i--)
count[pi[i - 1]] += count[i];
for (int i = 1; i <= n; i++) {
count[i]++;
}
// Print the lengths and occurrences of prefixes that
// also occur as suffixes
int j = pi[n - 1];
while (j > 0) {
cout << "Length: " << j
<< ", Occurrences: " << count[j] << "\n";
j = pi[j - 1];
}
}
int main()
{
string s = "ABACABA";
prefix_occurrence_with_suffix(s);
return 0;
}
Java
// Java program for the above approach
import java.util.*;
public class GFG {
// Function to compute the optimized Prefix Function of
// a string in O(N) time
static List<Integer> prefix_function(String s)
{
int n = s.length();
List<Integer> pi
= new ArrayList<>(Collections.nCopies(n, 0));
// Iterate through the string starting from the
// second character
for (int i = 1; i < n; i++) {
// Initialize j with the value from the previous
// position
int j = pi.get(i - 1);
// Continue updating j until a match is found or
// j becomes 0
while (j > 0 && s.charAt(i) != s.charAt(j))
j = pi.get(j - 1);
// If a match is found, increment the length of
// the common prefix/suffix
if (s.charAt(i) == s.charAt(j))
j++;
// Update the Prefix Function value for the
// current position
pi.set(i, j);
}
// Return the computed Prefix Function
return pi;
}
// Function to count the number of occurrences of each
// prefix of string s in the same string s that also
// occurs as the suffix of s
static void prefix_occurrence_with_suffix(String s)
{
int n = s.length();
// Compute the Prefix Function
List<Integer> pi = prefix_function(s);
int[] count = new int[n + 1];
// Count the occurrences of each value in the Prefix
// Function
for (int i = 0; i < n; i++)
count[pi.get(i)]++;
// Iterate from n-1 to 1 and update the count array
for (int i = n - 1; i > 0; i--)
count[pi.get(i - 1)] += count[i];
for (int i = 1; i <= n; i++)
count[i]++;
// Print the lengths and occurrences of prefixes
// that also occur as suffixes
int j = pi.get(n - 1);
while (j > 0) {
System.out.println("Length: " + j
+ ", Occurrences: "
+ count[j]);
j = pi.get(j - 1);
}
}
public static void main(String[] args)
{
String s = "ABACABA";
prefix_occurrence_with_suffix(s);
}
}
// This code is contributed by Susobhan Akhuli
Python
def prefix_function(s):
n = len(s)
pi = [0] * n
for i in range(1, n):
j = pi[i - 1]
while j > 0 and s[i] != s[j]:
j = pi[j - 1]
if s[i] == s[j]:
j += 1
pi[i] = j
return pi
def prefix_occurrence_with_suffix(s):
n = len(s)
pi = prefix_function(s)
count = [0] * (n + 1)
for i in range(n):
count[pi[i]] += 1
for i in range(n - 1, 0, -1):
count[pi[i - 1]] += count[i]
for i in range(1, n + 1):
count[i] += 1
j = pi[n - 1]
while j > 0:
print(f'Length: {j}, Occurrences: {count[j]}')
j = pi[j - 1]
if __name__ == "__main__":
s = "ABACABA"
prefix_occurrence_with_suffix(s)
C#
// C# program for the above approach
using System;
using System.Collections.Generic;
public class GFG {
// Function to compute the optimized Prefix Function of
// a string in O(N) time
static List<int> PrefixFunction(string s)
{
int n = s.Length;
// Create a list to store the values of the Prefix
// Function
List<int> pi = new List<int>();
// Initialize the first element of the Prefix
// Function
pi.Add(0);
// Iterate through the string starting from the
// second character
for (int i = 1; i < n; i++) {
// Initialize j with the value from the previous
// position
int j = pi[i - 1];
// Continue updating j until a match is found or
// j becomes 0
while (j > 0 && s[i] != s[j])
j = pi[j - 1];
// If a match is found, increment the length of
// the common prefix/suffix
if (s[i] == s[j])
j++;
// Update the Prefix Function value for the
// current position
pi.Add(j);
}
// Return the computed Prefix Function
return pi;
}
// Function to count the number of occurrences of each
// prefix of string s in the same string s that also
// occurs as the suffix of s
static void PrefixOccurrenceWithSuffix(string s)
{
int n = s.Length;
// Compute the Prefix Function
List<int> pi = PrefixFunction(s);
int[] count = new int[n + 1];
// Count the occurrences of each value in the Prefix
// Function
for (int i = 0; i < n; i++)
count[pi[i]]++;
// Iterate from n-1 to 1 and update the count array
for (int i = n - 1; i > 0; i--)
count[pi[i - 1]] += count[i];
for (int i = 1; i <= n; i++)
count[i]++;
// Print the lengths and occurrences of prefixes
// that also occur as suffixes
int j = pi[n - 1];
while (j > 0) {
Console.WriteLine("Length: " + j
+ ", Occurrences: "
+ count[j]);
j = pi[j - 1];
}
}
static void Main(string[] args)
{
string s = "ABACABA";
PrefixOccurrenceWithSuffix(s);
}
}
// This code is contributed by Susobhan Akhuli
JavaScript
// Function to compute the optimized Prefix Function of a string in O(N) time
function prefix_function(s) {
const n = s.length;
// Create an array to store the values of the Prefix Function
const pi = new Array(n).fill(0);
// Iterate through the string starting from the second character
for (let i = 1; i < n; i++) {
// Initialize j with the value from the previous position
let j = pi[i - 1];
// Continue updating j until a match is found or j becomes 0
while (j > 0 && s[i] !== s[j])
j = pi[j - 1];
// If a match is found, increment the length of the common prefix/suffix
if (s[i] === s[j])
j++;
// Update the Prefix Function value for the current position
pi[i] = j;
}
// Return the computed Prefix Function
return pi;
}
// Function to count the number of occurrences of each prefix of string s
// in the same string s that also occurs as the suffix of s
function prefix_occurrence_with_suffix(s) {
const n = s.length;
// Compute the Prefix Function
const pi = prefix_function(s);
const count = new Array(n + 1).fill(0);
// Count the occurrences of each value in the Prefix Function
for (let i = 0; i < n; i++)
count[pi[i]]++;
// Iterate from n-1 to 1 and update the count array
for (let i = n - 1; i > 0; i--)
count[pi[i - 1]] += count[i];
for (let i = 1; i <= n; i++) {
count[i]++;
}
// Print the lengths and occurrences of prefixes that also occur as suffixes
let j = pi[n - 1];
while (j > 0) {
console.log("Length:", j, ", Occurrences:", count[j]);
j = pi[j - 1];
}
}
// Main function
function main() {
const s = "ABACABA";
prefix_occurrence_with_suffix(s);
}
// Call the main function
main();
OutputLength: 3, Occurrences: 2
Length: 1, Occurrences: 4
Practice Problems of KMP Algorithm for Competitive Programming:
Similar Reads
Dijkstra's Algorithm for Competitive Programming
Dijkstra's algorithm, devised by computer scientist Edsger Dijkstra, is a fundamental graph search algorithm used to find the shortest path between nodes in a weighted graph. In this article, we will learn about how Dijkstra's algorithm can be used for solving problems in Competitive Programming. Ta
15+ min read
Basic Geometry for Competitive Programming
Ever wondered how to tackle tricky problems in competitive programming? Well, basic geometry is your secret weapon! In this article, we're diving into the basics Geometric Algorithms. It's like a power-up for your problem-solving skills, giving you the tools to crack those coding challenges like a p
15+ min read
Learning the art of Competitive Programming
Learning the art of Competitive Programming How to begin with Competitive Programming?Top 10 Algorithms and Data Structures for Competitive ProgrammingHow to prepare for ACM â ICPC?How to prepare for Google Asia Pacific University (APAC) Test ?Remaining Ahead in Competitive Programming:Master in com
2 min read
My Journey of Competitive Programming
Hello geeks, Today I want to share with you my competitive programming journey. Competitive programming means solving problems in different platforms. There are many benefits to do this. Even many companies directly select candidates through their coding profile. And you can also add this profile in
3 min read
Competitive Programming - A Complete Guide
Competitive Programming is a mental sport that enables you to code a given problem under provided constraints. The purpose of this article is to guide every individual possessing a desire to excel in this sport. This article provides a detailed syllabus for Competitive Programming designed by indust
8 min read
Competitive Programming: Conquering a given problem
Programming is the process of developing and implementing sets of instructions to enable a computer to do a certain task.The programming contests like ACM ICPC, Google CodeJam, and IEEE Extreme etc. are delightful playgrounds for the exploration of intelligence of programmers. From knowing the conte
5 min read
Best Courses on Competitive Programming
Competitive programming has gone beyond being a niche interest. Has become a skill, for computer science enthusiasts. Being able to solve algorithmic problems is highly valued in the tech industry. Recognizing this demand various online platforms offer courses tailored to skill levels and learning p
5 min read
Interactive Problems in Competitive Programming
Interactive Problems are those problems in which our solution or code interacts with the judge in real time. When we develop a solution for an Interactive Problem then the input data given to our solution may not be predetermined but is built for that problem specifically. The solution performs a se
6 min read
DP on Trees for Competitive Programming
Dynamic Programming (DP) on trees is a powerful algorithmic technique commonly used in competitive programming. It involves solving various tree-related problems by efficiently calculating and storing intermediate results to optimize time complexity. By using the tree structure, DP on trees allows p
15+ min read
Comparison among Greedy, Divide and Conquer and Dynamic Programming algorithm
Greedy algorithm, divide and conquer algorithm, and dynamic programming algorithm are three common algorithmic paradigms used to solve problems. Here's a comparison among these algorithms: Approach:Greedy algorithm: Makes locally optimal choices at each step with the hope of finding a global optimum
4 min read