【问题标题】:Recursive boolean function to check if a string is a palindrome用于检查字符串是否为回文的递归布尔函数
【发布时间】:2015-02-16 00:11:34
【问题描述】:

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

bool ispalindrome(char str[])

注意:函数必须是递归的(不是递归函数的包装器),它必须使用给定的(以上)签名,并且不允许全局或静态变量,此外,我们可以' t“销毁”给定的字符串。

我的尝试:

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

【问题讨论】:

  • 函数的其余部分在哪里?
  • 我认为在这些指令下这是不可能的,除非你践踏传入的字符串或为每个调用分配一个新字符串。
  • @iharob 正如我所写,我不知道如何继续。
  • 计算机科学概论递归作业问题之母!
  • 请注意,not 传递字符串的长度是非常低效的。使用这些信息可以更有效地编写函数。

标签: c recursion


【解决方案1】:

因此,您当前的代码几乎可以正常工作。我看到的唯一问题是,在一种情况下,您在恢复字符串中的更改之前返回。此外,您的索引中存在一个错误。

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

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

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

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

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

还有代码:

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 循环的样子)。这非常有帮助,因为您不必担心在非常大的字符串上耗尽堆栈空间。

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

【讨论】:

  • @kuhaku:我现在已经修复了一些小错误。如果您仍然对我发布的代码有错误,您需要发布您用来调用该函数的main()
【解决方案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;
    }
}

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 我通常会拒绝这个问题并继续前进,因为它没有表现出任何努力,但现在是星期天早上,我有点无聊......
    • &s 是什么意思?有没有办法在没有分配的情况下做到这一点?
    • 你可以做很多不同的事情,基于堆栈的分配似乎最简单,你可以使用“VLA”,但我不喜欢 VLA
    • 啊! alloca() :o alloca() 不是标准定义的:并非所有实现都需要支持它,并且那些不需要使用与您看到的相同语义的实现 man alloca
    • @pgm 是的,这是真的,不是最便携的电话......但它很常见。
    猜你喜欢
    • 1970-01-01
    • 2017-08-20
    • 2015-03-19
    • 2012-07-14
    • 1970-01-01
    • 2022-07-31
    • 1970-01-01
    • 1970-01-01
    • 2013-02-02
    相关资源
    最近更新 更多