递归布尔函数,用于检查字符串是否为回文结构

时间:2015-02-15 14:59:01

标签: c recursion

  

写一个递归布尔函数,如果字符串是回文,则返回1,否则返回0。

bool ispalindrome(char str[])

注意:函数必须是递归的(不是递归函数的包装器),它必须使用给定的(上面)签名,不允许全局或静态变量,我们也可以' ''破坏'给定的字符串。

我的尝试:

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

现在我陷入了困境,我想到了一个使用动态数组的辅助函数,它会删除原始字符串中的第一个和最后一个元素,并在递归调用中使用它,但我不认为这是预期的解决方案

编辑:我已经取得了一些进展,但它不起作用:

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;
    }
}

3 个答案:

答案 0 :(得分:5)

因此,您当前的代码几乎可以正常工作。我看到的唯一问题是,在一个案例中,您在还原字符串中的更改之前返回。此外,索引中有一个错误。

我们还要注意一些风格修复:

  1. *(str + 1)确实应该是str[1]。它们是等价的,但后者是预期的。

  2. 由于您已经计算了l = strlen(str),因此您可以将其用作第一个条件,因为它的可读性更高一些。

  3. 您还可以使用更长的变量名称。它们并不贵。

  4. 就我个人而言,如果您将空字符写入字符串,我会喜欢使用空字符而不是0。那是'\0'。但那只是我。

  5. 代码:

    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]);
    }
    

    我们可以对代码的运行时间做一点改进吗?

    代码工作原理的一个令人讨厌的特性是我们总是会有strlen(str) / 2个递归调用。我们可以在"abracadabra"之类的示例中使代码运行得更快,其中字符串的第二个字母会导致回文测试失败。

    加快速度的一种方法是在递归调用之前进行测试(str[0] == str[l - 1]) 。我们可以相当容易地实现它,它可能看起来像这样:

    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;
    }
    

    所有这一切都说......

    我已经在stackoverflow上看过几次这个问题了,我总是很好奇教练正在寻找什么。通过将字符串长度作为附加参数传递来解决此问题的经典版本。通过这样做,我们可以节省的工作。

    到目前为止发布的每个解决方案(包括我的)都会在每次递归调用时调用strlen()。这意味着所有这些解决方案至少为O(n^2)。如果我们可以将长度传递给递归调用,我们可以轻松解决O(n)中的问题。这将极大地减少工作量。

    此外,您还可以以尾递归方式编写代码。这可以允许编译器生成对处理器执行更好的代码。 (基本上,它会将代码转换为for循环的样子)。这非常有用,因为您没有太多关于在非常大的字符串上用完堆栈空间的问题。

    但是,由于教师的限制,我们不能做任何这些事情。这有点蹩脚。

答案 1 :(得分:2)

没有编译器......

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;
    }
}

答案 2 :(得分:0)

psuedocode(意思是,在C中没有名为string的东西,我没有尝试编译它,我的虚拟库调用类似于真正的库调用可能有错误的命令中的参数等等):

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;
}