Open In App

Prefix Function and KMP Algorithm for Competitive Programming

Last Updated : 23 Apr, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

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 [Tex]\pi [/Tex], where [Tex]\pi[i] [/Tex] is the length of the longest proper prefix of the substring [Tex]s[0…i] [/Tex]    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 [Tex]\pi[0]=0 [/Tex] because a string of length [Tex]1 [/Tex] has no proper prefixes.

Examples:

Example 1: s=”xyzxyzx" 

Prefix Function for s will be [Tex]\pi [/Tex]=[0,0,0,1,2,3,4]

Example 2: s=”xxyxxxy”

Prefix Function for s will be [Tex]\pi [/Tex]=[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

Python3

# 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 [Tex]\pi[i+1]<=\pi[i]+1 [/Tex]. This can be proved by contradiction. If [Tex]\pi[i+1]>\pi[i]+1 [/Tex], then we can take the suffix of length [Tex]\pi[i+1] [/Tex] that is ending at index i+1, remove the last character from it, then we get a better suffix of length [Tex]\pi[i+1]-1 [/Tex] ending at position i, which is better than the value [Tex]\pi[i] [/Tex], 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)); } }

Python3

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)


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 [Tex]\pi[i+1] [/Tex], if [Tex]s[i+1]=s[\pi[i]] [/Tex], then [Tex]\pi[i+1]=\pi[i]+1 [/Tex], otherwise then we need to find the largest index j, such that [Tex]j<\pi[i] [/Tex] and [Tex]s[0…j-1]=s[i-j+1….i] [/Tex]. Then we can compare characters at index j and i+1, if they are equal then [Tex]\pi[i+1]=j+1 [/Tex], otherwise we need to find the next shortest j and repeat the procedure. If j becomes 0, then if [Tex]s[i+1]=s[0] [/Tex], then [Tex]\pi[i+1] [/Tex] 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: [Tex]s[0…j-1]=s[i-j+1….i] [/Tex], this value is nothing but [Tex]\pi[i-1] [/Tex].

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: [Tex]s[0…j-1]=s[i-j+1….i] [/Tex].
    • 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++

// 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; }

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 [Tex]\pi[i]=n [/Tex], at any position i, that means a match is found, i.e., occurrence of patter p in text t. Notice the [Tex]\pi[i]=n [/Tex], 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++

// 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 find all occurrences of pattern p in text t // using KMP algorithm vector<int> pattern_searching(string t, string p) { int n = p.size(), m = t.size(); // Combine pattern p, separator '#', and text t string s = p + "#&" + t; // Compute the Prefix Function for the combined string vector& lt; int& gt; pi = prefix_function(s), ans; // Iterate through the Prefix Function results to find // pattern occurrences for (int i = n + 1; i <= n + m; i++) { if (pi[i] == n) { ans.push_back( i - 2 * n); // Record the starting position // of the pattern occurrence } } // Return the positions where the pattern is found in // the text return ans; }

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 [Tex]\pi[i] [/Tex] 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 [Tex]\pi[j-1] [/Tex] 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 [Tex]\pi[i-1] [/Tex] of final answer array by [Tex]\pi[i] [/Tex].

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; }

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 [Tex]\pi[i] [/Tex], 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); } }

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- [Tex]\pi[n-1] [/Tex], [Tex]\pi[\pi[n-1]] [/Tex],… 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

# Python program for the above approach # Function to compute the optimized Prefix Function of a string def prefix_function(s): n = len(s) pi = [0] * n j = 0 for i in range(1, n): while j > 0 and s[i] != s[j]: j = pi[j - 1] if s[i] == s[j]: j += 1 pi[i] = j return pi # Function to count the number of occurrences of each prefix of the string def prefix_occurrence_with_suffix(s): n = len(s) pi = prefix_function(s) count = [0] * (n + 1) # Count the occurrences of each value in the Prefix Function for i in range(n): count[pi[i]] += 1 # Iterate from n-1 to 1 and update the count array for i in range(n - 1, 0, -1): count[pi[i - 1]] += count[i] # Increment all counts by 1 count = [x + 1 for x in count] # Print the lengths and occurrences of prefixes # that also occur as suffixes j = pi[n - 1] while j > 0: print(f"Length: {j}, Occurrences: {count[j]}") j = pi[j - 1] s = "ABACABA" prefix_occurrence_with_suffix(s) # This code is contributed by Susobhan Akhuli

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


Output

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

Practice Problems of KMP Algorithm for Competitive Programming:

Problem

Problem Link

Minimum characters to be added at front to make string palindrome

Practice

Minimum size substring to be removed to make a given string palindromic

Practice

Maximum number of given operations to remove the entire string

Practice




Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads