shinzou
shinzou

Reputation: 6222

Recursive boolean function to check if a string is a palindrome

Write a recursive boolean function that returns 1 if a string is a palindrome and 0 if not.

bool ispalindrome(char str[])

Notes: the function must be recursive (not a wrapper for recursive function), it has to use the given (above) signature and no global or static variables are allowed, also, we can't 'destroy' the given string.

My attempt:

bool ispalindrome(char str[]){
    bool res;
    if (*str == 0 || *(str + 1) == 0)
        return 1;
    else{
        res = ispalindrome(str + 1);

Now I'm stuck, I thought of making a helper function that uses dynamic arrays that would have the first and last elements from the original string removed and use that in the recursive call but I don't think that's the intended solution.

EDIT: I've made some progress, but it doesn't work:

bool ispalindrome(char str[]){
    bool res;
    int l = strlen(str);
    char t;
    if (*str == 0 || *(str + 1) == 0)
        return 1;
    else{
        t = str[l-1];
        str[l-1] = 0;
        res = ispalindrome(str + 1);
        if (res == 0)
            return 0;

        if (str[0] == str[l - 2])
            res =1;
        else 
            res=0;
        str[l] = t;
        return res;
    }
}

Upvotes: 2

Views: 7010

Answers (3)

Bill Lynch
Bill Lynch

Reputation: 81986

So, your current code almost works. The only issues that I see is that in one case you return before you revert the changes in the string. Also, you have an off by one error in your indexing.

Let's also note some stylistic fixes:

  1. *(str + 1) really should be str[1]. They're equivalent, but the latter is what is expected.

  2. Since you've already calculated l = strlen(str), you could use that for your first conditional, since it's a bit more readable what that means.

  3. You can also use longer variable names. They aren't more expensive.

  4. Personally, I like that if you're writing the null character into a string, that you use the null character instead of 0. That is '\0'. But that's just me.

And the code:

bool ispalindrome(char str[]){
    int l = strlen(str);

    // Recusive Base Case
    if (l == 0 || l == 1)
        return true;

    // Save the last character of the string
    char t = str[l-1];
    str[l-1] = '\0';

    // Recursive call on the substring
    bool res = ispalindrome(str + 1);

    // Now, this is where you messed up. Before we return,
    // we need to fix the string!
    str[l-1] = t;

    // If the recursive call thinks that it's not a palindrome,
    // then we won't disagree.
    if (res == false)
        return res;

    // Check the (current) first position of the string against the last
    // You had an off by one error here.
    return (str[0] == str[l - 1]);
}

Can we make a small improvement to the runtime of the code?

One annoying property of how your code works is that we will always have around strlen(str) / 2 recursive calls. Could we make the code run faster on an example like "abracadabra", where the second letter of the string causes the palindrome test to fail.

One way to speed it up would be to do the test (str[0] == str[l - 1]) before the recursive call. We could implement this fairly easily, and it might looks something like this:

bool ispalindrome(char str[]){
    int length = strlen(str);

    // Recursive Base Case
    if (length == 0 || length == 1)
        return true;

    // Check our case.
    // Note that this is occuring __before__ the recursive call
    if (str[0] != str[length - 1])
        return false;

    // Save the last character of the string
    char t = str[length - 1];
    str[length - 1] = '\0';

    // Recursive call on the substring
    bool res = ispalindrome(str + 1);

    // We need to fix the string
    str[length - 1] = t;

    return res;
}

All of this being said...

I've seen this question a couple of times on stackoverflow, and I'm always curious what the instructor is looking for. The classic version of this problem is solved by passing the string length as an additional parameter. By doing this, we save a ton of work.

Every solution posted so far (including mine) calls strlen() on every recursive call. That means that all of these solutions are at least O(n^2). If we could pass the length to the recursive call, we could easily solve the problem in O(n). This would be an extremely large reduction in work.

Additionally, you could also then write the code in a tail recursive manner. This can allow the compiler to generate code that is much nicer for the processor to execute. (Basically, it will transform the code into what a for-loop would look like). This is very helpful because you then don't have as many concerns about running out of stack space on very large strings.

But, because of the limitations that your instructor has placed, we can't do any of these things. Which is kind of lame.

Upvotes: 5

AK_
AK_

Reputation: 8099

without a compiler...

bool ispalindrome(char str[])
{
    int len = strlen(str);

    if( len <= 1)
    {
        return TRUE;
    }
    else if (str[0] != str[len - 1])
    {
        reutrn FALSE;
    }
    else
    {
        char *str2 = malloc(len - 1);
        strncpy(str2, str + 1, len - 2);
        str2[len - 2] = NULL;
        BOOL result = ispalindrome(str2); 
        free(str2);
        return result;
    }
}

Upvotes: 2

Grady Player
Grady Player

Reputation: 14549

psuedocode (meaning, there is no thing called string in C, and I didn't try to compile it, and my imaginary library calls that are similar to real library calls could have the params in the wrong orders, etc):

bool isPalendrome(string s)
{
    if (s[0] == s[strlen(s)-1]) // if the value of the first is the same as the last
    {
        if ((&s[strlen(s)-1] - &s[0]) < 3)// if the address of the end and the address of the start are 1, or 2, we have a palindrome of 1 or 2 chars..
        {
            return true;
        }
        s2 = alloca(strlen(s) - 1);// or VLA , -1 because -2 char, +1 for null
        s2[strlen(s) - 2] = '\0';
        strncpy(s+1,s2,strlen(s)-2);
        return isPalendrome(s2)
    }
    return false;
}

Upvotes: 0

Related Questions