
- DSA - Home
- DSA - Overview
- DSA - Environment Setup
- DSA - Algorithms Basics
- DSA - Asymptotic Analysis
- Data Structures
- DSA - Data Structure Basics
- DSA - Data Structures and Types
- DSA - Array Data Structure
- DSA - Skip List Data Structure
- Linked Lists
- DSA - Linked List Data Structure
- DSA - Doubly Linked List Data Structure
- DSA - Circular Linked List Data Structure
- Stack & Queue
- DSA - Stack Data Structure
- DSA - Expression Parsing
- DSA - Queue Data Structure
- DSA - Circular Queue Data Structure
- DSA - Priority Queue Data Structure
- DSA - Deque Data Structure
- Searching Algorithms
- DSA - Searching Algorithms
- DSA - Linear Search Algorithm
- DSA - Binary Search Algorithm
- DSA - Interpolation Search
- DSA - Jump Search Algorithm
- DSA - Exponential Search
- DSA - Fibonacci Search
- DSA - Sublist Search
- DSA - Hash Table
- Sorting Algorithms
- DSA - Sorting Algorithms
- DSA - Bubble Sort Algorithm
- DSA - Insertion Sort Algorithm
- DSA - Selection Sort Algorithm
- DSA - Merge Sort Algorithm
- DSA - Shell Sort Algorithm
- DSA - Heap Sort Algorithm
- DSA - Bucket Sort Algorithm
- DSA - Counting Sort Algorithm
- DSA - Radix Sort Algorithm
- DSA - Quick Sort Algorithm
- Matrices Data Structure
- DSA - Matrices Data Structure
- DSA - Lup Decomposition In Matrices
- DSA - Lu Decomposition In Matrices
- Graph Data Structure
- DSA - Graph Data Structure
- DSA - Depth First Traversal
- DSA - Breadth First Traversal
- DSA - Spanning Tree
- DSA - Topological Sorting
- DSA - Strongly Connected Components
- DSA - Biconnected Components
- DSA - Augmenting Path
- DSA - Network Flow Problems
- DSA - Flow Networks In Data Structures
- DSA - Edmonds Blossom Algorithm
- DSA - Maxflow Mincut Theorem
- Tree Data Structure
- DSA - Tree Data Structure
- DSA - Tree Traversal
- DSA - Binary Search Tree
- DSA - AVL Tree
- DSA - Red Black Trees
- DSA - B Trees
- DSA - B+ Trees
- DSA - Splay Trees
- DSA - Range Queries
- DSA - Segment Trees
- DSA - Fenwick Tree
- DSA - Fusion Tree
- DSA - Hashed Array Tree
- DSA - K-Ary Tree
- DSA - Kd Trees
- DSA - Priority Search Tree Data Structure
- Recursion
- DSA - Recursion Algorithms
- DSA - Tower of Hanoi Using Recursion
- DSA - Fibonacci Series Using Recursion
- Divide and Conquer
- DSA - Divide and Conquer
- DSA - Max-Min Problem
- DSA - Strassen's Matrix Multiplication
- DSA - Karatsuba Algorithm
- Greedy Algorithms
- DSA - Greedy Algorithms
- DSA - Travelling Salesman Problem (Greedy Approach)
- DSA - Prim's Minimal Spanning Tree
- DSA - Kruskal's Minimal Spanning Tree
- DSA - Dijkstra's Shortest Path Algorithm
- DSA - Map Colouring Algorithm
- DSA - Fractional Knapsack Problem
- DSA - Job Sequencing with Deadline
- DSA - Optimal Merge Pattern Algorithm
- Dynamic Programming
- DSA - Dynamic Programming
- DSA - Matrix Chain Multiplication
- DSA - Floyd Warshall Algorithm
- DSA - 0-1 Knapsack Problem
- DSA - Longest Common Sub-sequence Algorithm
- DSA - Travelling Salesman Problem (Dynamic Approach)
- Hashing
- DSA - Hashing Data Structure
- DSA - Collision In Hashing
- Disjoint Set
- DSA - Disjoint Set
- DSA - Path Compression And Union By Rank
- Heap
- DSA - Heap Data Structure
- DSA - Binary Heap
- DSA - Binomial Heap
- DSA - Fibonacci Heap
- Tries Data Structure
- DSA - Tries
- DSA - Standard Tries
- DSA - Compressed Tries
- DSA - Suffix Tries
- Treaps
- DSA - Treaps Data Structure
- Bit Mask
- DSA - Bit Mask In Data Structures
- Bloom Filter
- DSA - Bloom Filter Data Structure
- Approximation Algorithms
- DSA - Approximation Algorithms
- DSA - Vertex Cover Algorithm
- DSA - Set Cover Problem
- DSA - Travelling Salesman Problem (Approximation Approach)
- Randomized Algorithms
- DSA - Randomized Algorithms
- DSA - Randomized Quick Sort Algorithm
- DSA - Karger’s Minimum Cut Algorithm
- DSA - Fisher-Yates Shuffle Algorithm
- Miscellaneous
- DSA - Infix to Postfix
- DSA - Bellmon Ford Shortest Path
- DSA - Maximum Bipartite Matching
- DSA Useful Resources
- DSA - Questions and Answers
- DSA - Selection Sort Interview Questions
- DSA - Merge Sort Interview Questions
- DSA - Insertion Sort Interview Questions
- DSA - Heap Sort Interview Questions
- DSA - Bubble Sort Interview Questions
- DSA - Bucket Sort Interview Questions
- DSA - Radix Sort Interview Questions
- DSA - Cycle Sort Interview Questions
- DSA - Quick Guide
- DSA - Useful Resources
- DSA - Discussion
Manacher's Algorithm
Manacher's algorithm is used to find the longest palindromic substring in a given string. A palindrome is a string that is equal to its reverse and a palindromic substring is a substring of a string that is also a palindrome, such as "aabaa" in "aabaaccaabaa". This algorithm was proposed by Glenn K. Manacher in the year 1975.
How Manacher's Algorithm works?
The naive approach to finding the longest palindromic substring is to check every possible substring of the given string and then verify whether it is a palindrome or not. However, this would consume more time and space.
The Manacher's Algorithm solves this problem in linear time, i.e. O(n), by using some observations and tricks. The main idea is to use the symmetry property of palindromes to avoid unnecessary comparisons.
Algorithm
The following steps are involved in the Manacher's Algorithm −
First, we preprocess the given string by inserting a special character, such as '#' between every pair of characters and at the beginning and end of the string. This ensures that every palindrome in the new string has an odd length and a unique centre. For example, the string "abba" becomes "#a#b#b#a#".
Next, we create an array named P[] of the same length as the new string, where P[i] stores the length of the longest palindromic substring centred at position i in the new string. We initialize P[0] = 0 and P[1] = 1, since the first two characters are always single-character palindromes.
Then, we iterate over the new string from left to right.
For each position i, find the mirror position j of i with respect to the center of the current rightmost palindrome.
Next, copy the value of P[j] to P[i], unless it exceeds the boundary R.
Expand the palindrome centred at i by comparing the characters on both sides of i + P[i]. If they match, we increment P[i] by 1 and repeat this step until they do not match or we reach the ends of the string.
Example
In the following example, we will practically demonstrate how Manacher's algorithm works in various programming languages.
#include<stdio.h> #include<string.h> // Function to return the minimum of two integers int minm(int a, int b) { return (a<b)?a:b; } // Function to find longest palindromic substring void findLongPalindrome(char orgnlString[]) { int n = strlen(orgnlString); if(n == 0) // If the string is empty, return an empty string return; n = 2*n + 1; // Array to store the length of palindrome int lenPalndrm[n]; // Initialization of first two positions lenPalndrm[0] = 0; lenPalndrm[1] = 1; int centerIndex = 1; int rightIndex = 2; int right = 0, left; int maxPalLength = 0, maxCenterIndex = 0; int start = -1, end = -1, diff = -1; // Loop through the string for (right = 2; right < n; right++) { left = 2*centerIndex-right; lenPalndrm[right] = 0; diff = rightIndex - right; // If difference is greater than 0, update length at current position if(diff > 0) lenPalndrm[right] = minm(lenPalndrm[left], diff); // While the palindrome can be extended, extend it while ( ((right + lenPalndrm[right]) < n && (right - lenPalndrm[right]) > 0) && ( ((right + lenPalndrm[right] + 1) % 2 == 0) || (orgnlString[(right + lenPalndrm[right] + 1)/2] == orgnlString[(right - lenPalndrm[right] - 1)/2] ))) { lenPalndrm[right]++; } // If the palindrome length at the current position is greater than the maximum palindrome length, update the maximum palindrome length and its center index if(lenPalndrm[right] > maxPalLength) { maxPalLength = lenPalndrm[right]; maxCenterIndex = right; } // If the right boundary of the palindrome at the current position is greater than the right index, update the center index and the right index if (right + lenPalndrm[right] > rightIndex) { centerIndex = right; rightIndex = right + lenPalndrm[right]; } } start = (maxCenterIndex - maxPalLength)/2; end = start + maxPalLength - 1; // maximum palindrome char maxPalindrm[end-start+2]; strncpy(maxPalindrm, &orgnlString[start], end-start+1); maxPalindrm[end-start+1] = '\0'; printf("Longest palindrome is: %s\n", maxPalindrm); } int main() { char orgnlString[] = "AAAABCAEAAABCBDDAAAAABC"; // method calling findLongPalindrome(orgnlString); return 0; }
#include<iostream> using namespace std; // Function to return the minimum of two integers int minm(int a, int b) { return (a<b)?a:b; } // Function to find longest palindromic substring string findLongPalindrome(string orgnlString) { int n = orgnlString.size(); if(n == 0) // If the string is empty, return an empty string return ""; n = 2*n + 1; // Array to store the length of palindrome int lenPalndrm[n]; // Initialization of first two positions lenPalndrm[0] = 0; lenPalndrm[1] = 1; int centerIndex = 1; int rightIndex = 2; // Variables to store the current right and left positions int right = 0, left; // Variables to store maximum palindrome length and its center index int maxPalLength = 0, maxCenterIndex = 0; int start = -1, end = -1, diff = -1; // Loop through the string for (right = 2; right < n; right++) { // Calculate the corresponding left position left = 2*centerIndex-right; lenPalndrm[right] = 0; diff = rightIndex - right; // If difference is greater than 0, update length at current position if(diff > 0) lenPalndrm[right] = min(lenPalndrm[left], diff); // While the palindrome can be extended, extend it while ( ((right + lenPalndrm[right]) < n && (right - lenPalndrm[right]) > 0) && ( ((right + lenPalndrm[right] + 1) % 2 == 0) || (orgnlString[(right + lenPalndrm[right] + 1)/2] == orgnlString[(right - lenPalndrm[right] - 1)/2] ))) { lenPalndrm[right]++; } // If the palindrome length at the current position is greater than the maximum palindrome length, update the maximum palindrome length and its center index if(lenPalndrm[right] > maxPalLength) { maxPalLength = lenPalndrm[right]; maxCenterIndex = right; } // If the right boundary of the palindrome at the current position is greater than the right index, update the center index and the right index if (right + lenPalndrm[right] > rightIndex) { centerIndex = right; rightIndex = right + lenPalndrm[right]; } } // Calculate the start and end indices of the maximum palindrome start = (maxCenterIndex - maxPalLength)/2; end = start + maxPalLength - 1; string maxPalindrm; // Construct the maximum palindrome for(int i=start; i<=end; i++) maxPalindrm += orgnlString[i]; // Returning maximum palindrome return maxPalindrm; } int main(int argc, char *argv[]) { string orgnlString, palindrome; orgnlString = "AAAABCAEAAABCBDDAAAAABC"; // method calling palindrome = findLongPalindrome(orgnlString); cout << "Longest palindrome is: " << palindrome << endl; }
import java.util.Arrays; public class Main { // Function to find longest palindromic substring public static String findLongestPalindrome(String orgnlString) { // If the string is null or empty, return an empty string if (orgnlString == null || orgnlString.length() == 0) return ""; char[] s2 = addBoundaries(orgnlString.toCharArray()); // Array to store the length of palindrome int[] lenPlandrm = new int[s2.length]; int centerIndex = 0, right = 0; // to compare if two elements are the same int m = 0, n = 0; // Loop through the string for (int i = 1; i<s2.length; i++) { if (i > right) { lenPlandrm[i] = 0; m = i - 1; n = i + 1; } else { int i2 = centerIndex * 2 - i; if (lenPlandrm[i2] < (right - i - 1)) { lenPlandrm[i] = lenPlandrm[i2]; m = -1; } else { lenPlandrm[i] = right - i; n = right + 1; m = i * 2 - n; } } // While the palindrome can be extended, extend it while (m >= 0 && n < s2.length && s2[m] == s2[n]) { lenPlandrm[i]++; m--; n++; } // If the right boundary of the palindrome at the current position is greater than the right index, update the center index and the right index if ((i + lenPlandrm[i]) > right) { centerIndex = i; right = i + lenPlandrm[i]; } } int len = 0; centerIndex = 0; // Find the maximum palindrome length and its center index for (int i = 1; i<s2.length; i++) { if (len < lenPlandrm[i]) { len = lenPlandrm[i]; centerIndex = i; } } // Construct the maximum palindrome char[] maxPalindrm = Arrays.copyOfRange(s2, centerIndex - len, centerIndex + len + 1); // Returning maximum palindrome return String.valueOf(removeBoundaries(maxPalindrm)); } // Function to add boundaries to handle even length palindromes private static char[] addBoundaries(char[] cs) { if (cs == null || cs.length == 0) return "||".toCharArray(); char[] cs2 = new char[cs.length * 2 + 1]; for (int i = 0; i < (cs2.length - 1); i = i + 2) { cs2[i] = '|'; cs2[i + 1] = cs[i / 2]; } cs2[cs2.length - 1] = '|'; return cs2; } // Function to remove the added boundaries from the result private static char[] removeBoundaries(char[] cs) { if (cs == null || cs.length < 3) return "".toCharArray(); char[] cs2 = new char[(cs.length - 1) / 2]; for (int i = 0; i < cs2.length; i++) { cs2[i] = cs[i * 2 + 1]; } return cs2; } public static void main(String[] args) { String orgnlString = "AAAABCAEAAABCBDDAAAAABC"; System.out.println("Longest palindrome is: " + findLongestPalindrome(orgnlString)); } }
def add_boundaries(cs): if cs is None or len(cs) == 0: return ['|', '|'] cs2 = ['|'] * (len(cs) * 2 + 1) for i in range(len(cs)): cs2[i * 2 + 1] = cs[i] return cs2 def remove_boundaries(cs): if cs is None or len(cs) < 3: return "" cs2 = [''] * ((len(cs) - 1) // 2) for i in range(len(cs2)): cs2[i] = cs[i * 2 + 1] return ''.join(cs2) def find_longest_palindrome(orgnl_string): if orgnl_string is None or len(orgnl_string) == 0: return "" s2 = add_boundaries(list(orgnl_string)) len_palandrm = [0] * len(s2) center_index = 0 right = 0 m = 0 n = 0 for i in range(1, len(s2)): if i > right: len_palandrm[i] = 0 m = i - 1 n = i + 1 else: i2 = center_index * 2 - i if len_palandrm[i2] < (right - i - 1): len_palandrm[i] = len_palandrm[i2] m = -1 else: len_palandrm[i] = right - i n = right + 1 m = i * 2 - n while m >= 0 and n < len(s2) and s2[m] == s2[n]: len_palandrm[i] += 1 m -= 1 n += 1 if (i + len_palandrm[i]) > right: center_index = i right = i + len_palandrm[i] length = 0 center_index = 0 for i in range(1, len(s2)): if length < len_palandrm[i]: length = len_palandrm[i] center_index = i max_palindrm = s2[center_index - length : center_index + length + 1] return remove_boundaries(max_palindrm) orgnl_string = "AAAABCAEAAABCBDDAAAAABC" print("Longest palindrome is:", find_longest_palindrome(orgnl_string))
Output
Longest palindrome is: AAAAA