Sunday, July 26, 2015

SPOJ Problem EPALIN

Extend to Palindrome

Explanation:

This problem ask us to add minimum number of characters at the end of the string s to make it a palindrome. So, basically, we need to prepare a palindrome of minimum whose prefix should be s.

A very basic approach would be to take the reverse of the string and append it to the original string. Believe me, that's a correct solution. It would give you a palindrome, but not really a palindrome with minimum length. If still not sure, try examples 'abcd''abcc'. Now, I will leave it to you to decide, if the approach is correct or not.

But, we will be working very close to the first approach we had. That is, we would be taking the reverse of original string s and appending it to the original one and then trying to form a palindrome of minimum length.

Let's take a few examples to get to a solution.

Example # 1.
original string: abcd
reverse string: dcba
palindrome after appending: abcddcba
minimum length palindrome: abcdcba

Here, we can say that, if we remove the first character from the reverse, it might work. Correct, but partially. Let's take another example.

Example # 2.
original string: abcc
reverse string: ccba
palindrome after appending: abccccba
minimum length palindrome: abccba

Looking at this example, first thing which came to my mind was, we could have had a palindrome of a smaller length, which is 'abcba'(isn't it a palindrome and also smaller than 'abccba'?). Then, what's the reason, we have 'abccba'. Just a hint. string s should be a part of palindrome.

Okay, now moving ahead, here we had to remove two characters from the reverse which contradicts the conclusions from example 1. So, there must be something else which we need to check. Let's take one more example, and we will be clear what needs to be done.

Example # 3.
original string: amanaplanacanal
reverse string: lanacanalpanama
palindrome after appending: amanaplanacanallanacanalpanama
minimum length palindrome: amanaplanacanalpanama

I guess, by now, you must have guessed, what we need to remove from the reverse string. Its the longest palindrome which is also suffix of original string or prefix of its reverse. So, going ahead with above examples.

Example # 1. Result would be 'd'.
Example # 2. Result would be 'cc'.
Example # 3. Result would be 'lanacanal'.

So, now we know what needs to be done. We need to find the longest palindrome of string s which is suffix of original string s. Now, how to find the longest suffix palindrome. We know, it would be the prefix of reverse of the string. So, do we have something which takes into consideration, the prefix as well as suffix. Yes, we do have, and that's KMP algorithm (those who are not aware, check the links provided below). Not exactly KMP algorithm, but its first part, which calculates the longest suffix which is also the prefix of the string.

So, to achieve our purpose,we take string "rev(s)+#+s" (adding a # because we only need the longest prefix of the reverse of the string and not the whole string "rev(s)+s"). The maximum length we receive is the length of palindromic suffix of the string. Now, things become easy, isn't it. I will leave further part to you to implement. You can refer the solution which I used.

KMP algorithm links.
1. Part-1: https://www.youtube.com/watch?v=GTJr8OvyEVQ&index=2&list=PLrmLmBdmIlpvxhscYQdvfFNWU_pdkG5de
2. Part-2: https://www.youtube.com/watch?v=KG44VoDtsAA&index=1&list=PLrmLmBdmIlpvxhscYQdvfFNWU_pdkG5de
3. http://www.geeksforgeeks.org/searching-for-patterns-set-2-kmp-algorithm/

Solution:

#include<cstdio>
#include<iostream>
#include<string>
#include<cstdlib>
#include<queue>
#include<stack>
#include<utility>
#include<string>
#include<cstring>
#include<set>
#include<cmath>
#include<vector>
#include<fstream>
#include<map>
#include<list>
#include<algorithm>
#define SIZE 100005

typedef long long int LLD;
typedef unsigned long long int LLU;

using namespace std;

int prepareLPSArray(string pattern){
    /* Returns the length of longest suffix which is also prefix of the string.
       Since, we have appended original string to its reverse, we would be able
       to get the length of longest suffix of original string which is also a 
       palindrome. Below is the basic implementation of prefix array calculation 
       used in KMP algorithm. */

    int len = pattern.length();
    vector<int> lsp(len);
    lsp[0] = 0;
    for(int j=0, i=1;i<len;i++){
        if(pattern[i] == pattern[j]){
            lsp[i] = j + 1;
            j++;
        }
        else{
            while(true){
                if(j == 0 || pattern[j] == pattern[i])
                    break;
                j = lsp[j-1];
            }
            if(pattern[j] == pattern[i]){
                lsp[i] = j + 1;
                j++;
            }
            else
                lsp[i] = 0;
        }
    }
    return lsp[len - 1];
}

string findPalin(string s){
    string res = s;
    // Obtain the reverse of string.
    string revS = string(s.rbegin(), s.rend());
    // Find the no. of chars to be appended to original string.
    int noOfChars = s.length() - prepareLPSArray(revS + "#" + s);
    // Append noOfChars from original string to the result in reverse order.
    for(int i=noOfChars - 1;i>=0;i--)
        res.append(1, s[i]);
    return res;
}

int main(){
    char str[SIZE];
    // Take input until EOF.
    while(scanf("%s", str) != EOF){
        string s = str;
        // Find minimum length for s.
        cout << findPalin(s) << endl;
    }
    return 0;
}

Any suggestions are welcome.

4 comments:

  1. why we have used prepareLPSArray(revS + s).how lps of revs+s will give the no.of charcter which need to be need to be removed

    ReplyDelete
    Replies
    1. Hi,
      As per the explanation, to find the shortest palindrome, we need to remove the longest string which is suffix of the original and prefix of the reverse string. i-th value of LPS array provides the number of characters which are suffix of the string as well as form its prefix too.
      Below is the computation for an example.

      Let's say, s = abcdccc. Thus, it's reverse would become, revS = cccdcba. And, revS + s = cccdcbaabcdccc.

      String: c c c d c b a a b c d c c c
      LPS Array: 0 1 2 0 1 0 0 0 0 1 0 1 2 3

      As per the calculation above, we can see the longest string which is suffix of s and prefix of revS, is of length 3, which would be "ccc". Thus, when finding palindrome, we need to remove "ccc" from s + revS = "abcdccccccdcba" and hence, we get the shortest palindrome, which is "abcdcccdcba".

      Delete
  2. Your code's output is wrong for string "abaa"

    ReplyDelete
  3. Hi Aggelos,
    Thanks for pointing out the case. Updated it. :)

    ReplyDelete

SPOJ Problem ONEZERO

Ones and zeros Explanation: A very good problem to practice BFS skills. I think that much hint is good to give the problem a shot. An...