Amazon Interview Question
Software Engineer / DevelopersCountry: United States
Interview Type: Phone Interview
Here is an implementation
Use Manacer's algorithm to find them in O(n)
public class ManacerLongestPalindromicSubstring{
public static String void preprocess(String in){
StringBuffer sb = new StringBuffer();
sb.append’#’);
for(int i=0; i<in.length(); i++){
sb.append(in.charAt(i));
sb.append(‘#’);
}
return sb.toString();
}
public static String LongestPalindrome(String in){
/*Preprocess the string to insert special character ‘#’ in the spaced between characters in input and the two outside edges. This is done merely to make the computation identical for both odd and even length input string. */
String S = preprocess(in);
int C = 0; //contains center of current palindrome
int R = 0; //contains the right edge of current palindrome
int[] P = new int[S.length()];
// P[i] contains the length of longest palindrome (in S not original in) centered at i
for(int i=0;i<P.length(); i++)
P[i] = 0;
// for each position find longest palindrome centered at the position, save length in P
for(int i=0; i<S.length; i++){
int i_mirror = 2*C-i; // as C - i_mirror = i - C due to symmetric property
/*When R-i > P[i_mirror] then palindrome at center i_prime contained completely within palindrome centered at C. Otherwise R-i <= P[i_mirror] means that the palindrome at ceter i_mirror doesn’t fully contained in the palindrome centered at C. In this case palindrome at i is extendable past R*/
P[i] = (R>i) ? min(P[i_mirror], R-i) : 0;
// if palindrome centered at i is extendable past R then extend R to the right edge of newly extended palindrome
while(S[i+P[i]+1] == S[i-P[i]-1])
P[i]++;
// If palindrome centered at i extend past R then update Center to i
if(i+P[i] > R){
C = i;
R = i+P[i];
}
}
return extractLongest(in, P);
}
public int extractLongest(String in, int[] P){
int longestCenter = 0;
int longestLength = 0;
for(int i=0; i<P.length; i++){
if(P[i] > longestLength){
longestLongest = P[i];
longestCenter = i;
}
}
return in.substring((longestCenter-longestLength-1)/2, longestLemgth);
}
public Set<String> allPalindromicSubstring(String in, int[] P){
HashSet<String> all = new HashSet<String>();
for(int i=0; i<P.length; i++){
if(P[i] != 0)
all.add(in.substring((i-P[i]-1)/2, P[i]));
}
return all;
}
}
There are 2 ways.
Either use suffix tree.
Use DFS. Remove last and first character of the strings and create 2 other strings and check for palindrome.Keep doing this for all the substring, until the palindrome is found
Actually, I didn't realize that you could get O(n) until I read some paper on it. Yet another cool use of Suffix Trees.
Use two index values to traverse over the string as "the middle values" and then use those index values to sprawl outwards from the middle to the end. You could also just get away with one index value. You just need to be aware of even/odd length palindromes.
For example,
a = {d,a,b,b,a,c}
Here you'll check [i,j] = {0,0} and [i,j] = {0,1}.
Now sprawl outwards from these two indexes. For i=0, you're limited to d since i will be less than 0 when you decrement it. For {0,0}, you'll get d and this will be your max palindrome until you get to {a,b,b,a}.
Progressing through the iterations, you'll eventually get something like [i,j] = {2,2} and {2,3}.
For {2,2}, you won't get a valid search. For {2,3}, you'll get {a,b,b,a}. Note, you'll also get {b,b} within your {2,3} search.
This should be O(N^2) time.
Nice.
I think this is basically the best way that doesn't require the slickness (i.e. trick) of Manacher's (which is either just "known" or needs "a bit of time to think of").
Manac. is basically an optimization on nothing's alg to cut out some redundancies.
returns the actual palandrome for which you can just call length
def largestPalandrome (str)
start = 0
finish = str.length -1
length = 0
maxS = 0
maxE = 0
maxL = 0
i = 0
j = 0
found = false
while (start < finish - 1)
if (str[start] == str[start+1])
found = true
i = start
j = start+1
else if (start>0 && str[start-1] = str[start+1])
found = true
i = start - 1
i = start + 1
end
if found
while (i>0 && j<finish && str[i] == str[j])
i--
j++
length += 2
end
if length > maxL
maxL = length
maxS = i
maxE = j
end
i = 0
j = 0
found = false
end
start++
end
return str[maxS, maxE]
end
pal = largestPalandrome(yourString)
pal.length
public class Longest_Palindrome_subsequence {//Using Dynamic Programming and filling //upper half of the diagonal table at the end the table[0][n-1] will give the result
int lps_DP(char [] str)
{ int n = str.length;
int [][] table = new int[n][n] ;
for(int i = 0;i<n;i++)
table[i][i] = 1;
for(int len = 2;len <=n;len++)
{
for(int i = 0;i <n-len+1;i++)
{
int j = i + len - 1;
if(str[i]==str[j] && len ==2)
table[i][j] = 2;
else if(str[i]==str[j])
table[i][j] = table[i+1][j-1]+2;
else
table[i][j] =Math.max(table[i][j-1],table[i+1][j]);
}
}
return table[0][n-1];
}
}
Dynamic programming based solution. This prints the longest palindrome.
/*
* palindrome: output the longest contiguous palindrome in the
* input string.
*
* Usage: palindrome string
*/
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
/* bounds of a substring (both indexes inclusive) */
struct bounds {
int start;
int end;
};
/*
* palindrome: Determine the longest contiguous palindrome in
* the substring starting at index start through index end,
* both inclusive. Use dynamic programming (top-down with
* memoization).
*
* If s[start] == s[end], and s[start+1]..s[end-1] is a
* palindrome, then the longest palindrome is s[start]..s[end].
* Otherwise, the longest palindrome is the longer of the
* longest palindrome in s[start]..s[end-1] and s[start+1]..s[end].
* Simple cases: every single character string (start == end)
* is a palindrome. Empty string is a palindrome.
*
* Return the longest palindrome indexes in b.
*
* Maintain a cache of longest palindrome indexes in pcache.
*/
void
palindrome(const char *s, struct bounds *b, struct bounds *pcache)
{
assert(s);
assert(b);
assert(pcache);
size_t len = strlen(s);
assert(b->start >= -1 && b->start <= len);
assert(b->end >= -1 && b->end <= len);
int start = b->start, end = b->end;
/*
* If start > end, we have an empty string which is a palindrome.
* Single character strings are palindromes.
*/
if (start >= end)
return;
/* is the result already cached? */
if (pcache[start*len + end].start != -1) {
*b = pcache[start*len + end];
return;
}
/* is the whole substring a palindrome? */
if (s[start] == s[end]) {
struct bounds inner = {start+1, end-1};
palindrome(s, &inner, pcache);
if (inner.start == start+1 && inner.end == end-1) {
/* s[start]..s[end] is a palindrome */
pcache[start*len + end] = *b;
return;
}
}
struct bounds inner1 = {start+1, end};
palindrome(s, &inner1, pcache);
struct bounds inner2 = {start, end-1};
palindrome(s, &inner2, pcache);
int len1 = inner1.end - inner1.start;
int len2 = inner2.end - inner2.start;
if (len1 > len2)
pcache[start*len + end] = *b = inner1;
else
pcache[start*len + end] = *b = inner2;
}
/*
* longest_palindrome: Allocate the cache and then call palindrome to
* get the longest palindrome. Finally, free the cache.
*/
void
longest_palindrome(const char *s, struct bounds *b)
{
assert(s);
assert(b);
size_t len = strlen(s);
assert(b->start == 0);
assert(b->end == len-1);
struct bounds *pcache = malloc(len * len * sizeof(struct bounds));
assert(pcache);
for (int i = 0; i < len; i++)
for (int j = 0; j < len; j++)
pcache[i*len + j].start = pcache[i*len + j].end = -1;
palindrome(s, b, pcache);
free(pcache);
}
int
main(int argc, const char *argv[])
{
if (argc != 2) {
fprintf(stderr, "Usage: palindrome string\n");
return 1;
}
const char *s = argv[1];
struct bounds b = {0, strlen(s)-1};
longest_palindrome(s, &b);
printf("Longest palindrome of %s is ", s);
const int end = b.end;
for (int i = b.start; i <= end; i++)
printf("%c", s[i]);
printf("\n");
return 0;
}
private static boolean isSubstringPalyndrome(char[] charSeq, int start, int end) {
while(start<end) {
if(charSeq[start] != charSeq[end]) return false;
start++;
end--;
}
return true;
}
private static int findLengthOfMaxLengthPalyndrome(String s) {
char[] stringAsCharSeq = s.toCharArray();
int maxLength = 1;
for(int i = 0; i < stringAsCharSeq.length; i++) {
for(int j = i+maxLength ; j < stringAsCharSeq.length; j++) {
if( isSubstringPalyndrome(stringAsCharSeq, i, j) ) maxLength = j - i + 1;
}
}
return maxLength;
}
Search term: Manacher's algorithm.
- S O U N D W A V E November 03, 2013O(N).