Prefix Function and KMP Algorithm for Competitive Programming

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.

Table of Content

  • What is KMP Algorithm?
  • What is Prefix Function in KMP Algorithm?
  • Use Cases of Prefix Function and KMP Algorithm in Competitive Programming
  • Practice Problems of KMP Algorithm for Competitive Programming

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 , where is the length of the longest proper prefix of the substring     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 because a string of length has no proper prefixes.

Examples:

Example 1: s=”xyzxyzx" 

Prefix Function for s will be =[0,0,0,1,2,3,4]

Example 2: s=”xxyxxxy”

Prefix Function for s will be =[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(" "));

Output
0 0 0 1 2 3 4 5 6 

Find Prefix Function in O(N2) time:

It can be observed that . This can be proved by contradiction. If \pi[i]+1 " title="Rendered by QuickLaTeX.com" height="27" width="203" style="vertical-align: 26px;">, then we can take the suffix of length that is ending at index i+1, remove the last character from it, then we get a better suffix of length ending at position i, which is better than the value , 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

Output
Prefix Function: 0 0 0 1 2 3 4

Find Prefix Function (Linear approach):

We can optimize the above approach to O(N). To compute , if , then , otherwise then we need to find the largest index j, such that and . Then we can compare characters at index j and i+1, if they are equal then , otherwise we need to find the next shortest j and repeat the procedure. If j becomes 0, then if , then 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: , this value is nothing but .

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: .
    • 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();

Output
Prefix 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 , at any position i, that means a match is found, i.e., occurrence of patter p in text t. Notice the , 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 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 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 of final answer array by .

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 , 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.

Output
Occurrences 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- , ,… 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();

Output
Length: 3, Occurrences: 2
Length: 1, Occurrences: 4

Practice Problems of KMP Algorithm for Competitive Programming:

Contact Us