5

I'm trying to solve a problem that asks to find the largest palindrome in a string up to 20,000 characters. I've tried to check every sub string whether it's a palindrome, that worked, but obviously was too slow. After a little googling I found this nice algorithm http://stevekrenzel.com/articles/longest-palnidrome. I've tried to implement it, however I can't get it to work. Also the given string contains illegal characters, so I have to convert it to only legal characters and output the longest palindrome with all characters.

Here's my attempt:

int len = original.length();
int longest = 0;
string answer;

for (int i = 0; i < len-1; i++){

    int lower(0), upper(0);

    if (len % 2 == 0){
        lower = i;
        upper = i+1;
    } else {
        lower = i;
        upper = i;
    }

    while (lower >= 0 && upper <= len){
        string s2 = original.substr(lower,upper-lower+1);
        string s = convert(s2);

        if (s[0] == s[s.length()-1]){
            lower -= 1;
            upper += 1;
        } else {
            if (s.length() > longest){
                longest = s.length();
                answer = s2;
            }
            break;
        }


    }
}

I can't get it to work, I've tried using this exact algorithm on paper and it worked, please help. Here's full code if you need it : http://pastebin.com/sSskr3GY

EDIT:

int longest = 0;
string answer;
string converted = convert(original);
int len = converted.length();

if (len % 2 == 0){
    for (int i = 0; i < len - 1; i++){
        int lower(i),upper(i+1);
        while (lower >= 0 && upper <= len && converted[lower] == converted[upper]){
            lower -= 1;
            upper += 1;
        }
        string s = converted.substr(lower+1,upper-lower-1);
        if (s.length() > longest){
            longest = s.length();
            answer = s;
        }
    }
} else {
    for (int i = 0; i < len; i++){
        int lower(i), upper(i);
        while (lower >= 0 && upper <= len && converted[lower] == converted[upper]){
            lower -= 1;
            upper += 1;
        }
        string s = converted.substr(lower+1,upper-lower-1);
        if (s.length() > longest){
            longest = s.length();
            answer = s;
        }
    }
}

Okay so I fixed the problems, it works perfectly fine but only if the length of converted string is odd. Please help.

Constantin
  • 8,721
  • 13
  • 75
  • 126
Marijus
  • 4,195
  • 15
  • 52
  • 87

3 Answers3

3

I can see two major errors:

  1. Whether you initialise your upper/lower pointers to i,i or i,i+1 depends on the parity of the palindrome's length you want to find, not the original string. So (without any further optimisations) you'll need two separate loops with i going from 0 to len (len-1), one for odd palindrome lengths and another one for even.
  2. The algorithms should be executed on the converted string only. You have to convert the original string first for it to work.

Consider this string: abc^ba (where ^ is an illegal character), the longest palindrome excluding illegal characters is clearly abcba, but when you get to i==2, and move your lower/upper bounds out by one, they will define the bc^ substring, after conversion it becomes bc, and b != c so you concede this palindrome can't be extended.

biziclop
  • 48,926
  • 12
  • 77
  • 104
  • Thanks a lot, I fixed the problems, however I can't get it to work when converted string's length is odd. I've updated my question, please take look when you can. – Marijus Mar 14 '11 at 22:12
  • @Marijus See part 1 of my answer: just remove the `if( len % 2 == 0 )` and the `else`, you don't need it. The length of the string doesn't matter, you always need to run both loops. – biziclop Mar 14 '11 at 22:22
  • Thanks, any suggestions on how I could quickly convert it back to the original format, with all illegal characters ? I've tried converting every possible sub-string of original to check if it's equal to the answer, but it's obviously too slow. – Marijus Mar 14 '11 at 22:29
  • @Marijus The only way to do it is to preserve the original indexes of characters during the conversion. So for example instead of returning just the converted string, you return a struct containing the converted string and an int array of the same length where every value is the index of the `nth` character of the converted string in the original. – biziclop Mar 14 '11 at 22:42
0
#include <iostream>
using namespace std;

int main() 
{

 string s;
 cin >> s;  
 signed int i=1;
 signed int k=0;
 int ml=0;
 int mi=0;
 bool f=0;

while(i<s.length())
{
    if(s[i]!=s[i+1])
    {
        for(k=1;;k++)
            {
                if(!(s[i-k]==s[i+k] && (i-k)>=0 && (i+k)<s.length()))
                {               
                    break;
                }   
            else if(ml < k)
                {
                    ml=k;
                    mi=i;
                    f=1;
                }
            }
    }   
i++;
}

i=0;

while(i<s.length())
{
    if(s[i]==s[i+1])
    {
         for(k=1;;k++)
         {
                if(!(s[i-k]==s[k+1+i] && (i-k)>=0 && (k+i)<s.length()))
                {
                    break;
                }
                else if(ml < k)
                {
                ml=k;
                    mi=i;
                }
            }                       
    }
    i++;
}

if(ml < 1)
{
  cout << "No Planidrom found";
  return 0;
}

if(f==0)
{
cout << s.substr(mi-ml,2*ml+2);
}
else
{
cout << s.substr(mi-ml,2*ml+1);
}

return 0;

}

@biziclop : As you said.. i used 2 while loops. one for even and one for old palindrom string. finally i was able to fix it. thanks for your suggestion.

LOGAN
  • 1,025
  • 2
  • 10
  • 14
0
 public void LongestPalindrome()
    {
        string str = "abbagdghhkjkjbbbbabaabbbbbba";

        StringBuilder str1=new StringBuilder();
        StringBuilder str2= new StringBuilder();

        for (int i = 0; i < str.Length; i++)
        {
            str1.Append((str[i]));
            for (int j = i + 1; j < str.Length; j++)
            {
                str1.Append((str[j]));
                if (Checkpalindrome(str1))
                {
                    str2.Append(str1);
                    str2.Append(" ");
                }
            }

            str1.Clear();
        }

        var Palstr = str2.ToString().Split(' ');
        var Longestpal = Palstr.Where(a => a.Length >= (Palstr.Max(y => y.Length)));
        foreach (var s in Longestpal)
        {
            Console.WriteLine(s);
        }
    }

    public bool Checkpalindrome(StringBuilder str)
    {
        string str1 = str.ToString();
        StringBuilder str2=new StringBuilder();
        var revstr = str1.Reverse();
        foreach (var c in revstr )
        {
            str2.Append(c);
        }

        if (str1.Equals(str2.ToString()))
        {
            return true;
        }

        return false;
    }