3

I have been given a task to create a class that given a String will create a palindrome with minimum number of assertions.

Example Runs:

Input: 123333
Output: 12333321

Input: 789
Output: 78987

Input: 1221
Output: 1221221

**Note a Palindrome should NOT return the same Palindrome.

I tried using a modified KMP algorithm as stated here.

I revert the string and compare it to the reverse + original string and then add the mismatches to the original string.

However my function only works for inputs with trailing digits (first example input) however an input like 1234 will return 1234123, '92837465' will return '928374659283746'

public static int[] computelps(String sample){
    int[] lps = new int[sample.length()];
    lps[0] = 0;
    int i = 1;
    int len = 0; // length of previous longest prefix suffix
    while (i < sample.length()) {
        if (sample.charAt(i) == sample.charAt(len)) {
            len++;
            lps[i] = len;
            i++;
        }
        else
        {
            if (len != 0) {
                len = lps[len - 1];
            }
            else {
                lps[i] = 0;
                i++;
            }
        }
    }
    return lps;
}

public static void Solution(File samplefile) throws Exception {
    BufferedReader br = new BufferedReader(new FileReader(samplefile));

    String firstline = br.readLine();
    String line;


    while ((line = br.readLine()) != null) {
        String reverse_str = "";
        String newline = line.replace(".", "");

        for (int i = newline.length() - 1; i >= 0; i--) {
            reverse_str += newline.charAt(i);
        }

        int [] lps = computelps(reverse_str); // computes the lps of the pattern string
        String tot = reverse_str + newline;

        // KMP Algorithm modified.

        int x = 0; // index for total_string(tot)
        int y = 0; // index for pattern
        String palindrome = newline;

        while (x < tot.length()){
            if(reverse_str.charAt(y) == tot.charAt(x)){
                y++;
                x++;
            }
            if(y == reverse_str.length()) {
                y = lps[y - 1];
            }


            else if( x < tot.length() && (reverse_str.charAt(y) != tot.charAt(x))){
                palindrome += tot.charAt(x);
                if ( y!= 0){
                    y = lps[y-1];
                }
                else{
                    x += 1;
                }
            }
        }
        System.out.println(palindrome);
    }
}

I would appreciate any help. I find algorithms very challenging so please bear with me if my approach or code is sub-par.

*I fixed sample inputs and outputs as well as added my results.

Reemz
  • 51
  • 4
  • 2
    Are you sure the inputs and expected outputs you listed are correct? For example, why should an input of `1221` result in an output of `12211221`? Shouldn't it be `1221221`, since that is the minimum number of additions needed to create a palindrome? – Jordan Sep 11 '19 at 15:11
  • what should computelps("4321") return? – wi2ard Sep 11 '19 at 16:06
  • computelps("4321.") will return [ 0, 0, 0, 0 ] – Reemz Sep 11 '19 at 16:25

2 Answers2

1

It helps to split this problem in smaller problems, implement a separate method for each and check to see if each method works as expected. What will really help you will be to learn to use the debugger in your Ide. But until you do that you can test that each part of your code works as expected. So I simplified a little your code and split it up :

public static void main(String[] args){
        System.out.println("computelps " + ("[0, 0, 0, 0]".equals(Arrays.toString(computelps("4321"))) ? "works" : "doesn't work" ));   
        System.out.println("reverse " + ("4321".equals(reverse("1234")) ? "works" : "doesn't work" ));
        System.out.println("Solution " + ("1234321".equals(Solution("1234")) ? "works" : "doesn't work" ));
    }

    public static int[] computelps(String sample){
        int[] lps = new int[sample.length()];
        lps[0] = 0;
        int i = 1;
        int len = 0; // length of previous longest prefix suffix
        while (i < sample.length()) {
            if (sample.charAt(i) == sample.charAt(len)) {
                len++;
                lps[i] = len;
                i++;
            }
            else
            {
                if (len != 0) {
                    len = lps[len - 1];
                }
                else {
                    lps[i] = 0;
                    i++;
                }
            }
        }
        return lps;
    }

    public static String Solution(String line) {
        String newline = line.replace(".", "");
        String reverse_str = reverse(newline);

        int [] lps = computelps(reverse_str); // computes the lps of the pattern string

        // KMP Algorithm modified.

        return kpmModified(newline, reverse_str, lps);

    }

    private static String kpmModified(String newline, String reverse_str, int[] lps) {
        int x = 0; // index for total_string(tot)
        int y = 0; // index for pattern
        String tot = reverse_str + newline;
        String palindrome = newline;

        while (x < tot.length()){
            if(reverse_str.charAt(y) == tot.charAt(x)){
                y++;
                x++;
            }
            if(y == reverse_str.length()) {
                y = lps[y - 1];
            }


            else if( x < tot.length() && (reverse_str.charAt(y) != tot.charAt(x))){
                palindrome += tot.charAt(x);
                if ( y!= 0){
                    y = lps[y-1];
                }
                else{
                    x += 1;
                }
            }
        }
        return palindrome;
    }

    private static String reverse(String newline) {
        String reverse_str = "";

        for (int i = newline.length() - 1; i >= 0; i--) {
            reverse_str += newline.charAt(i);
        }
        return reverse_str;
    }

And the result is

computelps works
reverse works
Solution doesn't work

So your bug is in kpmModified method. I can't spend more time and I'm not familiar with the algorithm but you should continue like this and figure our what part of that method has the bug.

wi2ard
  • 1,471
  • 13
  • 24
0

I think you overthink the problem. The question is basically adding a string's reversed version back to it's original, but not every character, right? So you might need to find something like a pointer to tell the function where to start to reverse.

One example. Let the string be 12333. If we add every character from the index string.length() to 0, it will be 1233333321, which is not correct, since there are duplicated 3's. We need to ignore those, so we need to add characters from string.length() - numOfDuplicateAtEnd to 0.

    public String palindromic(String num) {
        int i = num.length() - 1;
        while (i > -1 && num.charAt(i) == num.charAt(num.length() - 1))  
            i--;

        for (int k = i; k > -1; --k) 
            num += num.substring(k, k + 1);

        return num;
    }
Will
  • 113
  • 1
  • 8