【问题标题】:Recursively removing duplicate characters in a string递归删除字符串中的重复字符
【发布时间】:2020-08-12 20:10:25
【问题描述】:

我正在尝试创建一个递归函数,用于从字符串中删除连续的重复字符。除了前几个字符外,它工作正常。例如,如果我的输入是MMMMMuuuuuOOOOOKKKKLLLEE OOOOLLL 或类似的东西,则输出是MMuOKLE OL。正如您所看到的,除了前两个 M 之外,它工作正常。我怎样才能使第一部分也能完成这项工作? 这是我的代码:

#include <stdio.h>

char* remove_duplicates (char* str){
    if(*(str+1)!='\0'){
        if(*str==*(str+1)){
            *(str+1)=*(str+2);
             remove_duplicates(str+1);
        }
        remove_duplicates(str+1);
    }
    return str;
}

int main()
{
    char sample[] = "MMMMMuuuuuOOOOOKKKKLLLEE OOOOLLL";

    printf("OLD: |%s|\n", sample);
    printf("NEW: |%s|\n", remove_duplicates(sample));

    return 0;
}

【问题讨论】:

  • 除了其他可能出错的情况外,如果您将空字符串 ("") 传递给 remove_duplicates(),会发生什么?
  • 将测试用例简化为查看问题所需的最小字符串。然后在纸上遍历它并在调试器中逐步遍历它。
  • @SteveFriedl 我主要将"" 传递给remove_duplicates()。什么都没有发生。它再次打印菜单。
  • @gokbeykeskin - 我相信你需要更仔细地看看这个。如果第一个字符是 NUL 字节,是什么导致函数停止,而它之后的所有内容都是随机垃圾?
  • 返回参数而不是 void remove_duplicates(char * str) 有什么兴趣?这使得第二次呼叫非终端没有任何意义

标签: c recursion c-strings function-definition


【解决方案1】:

你来了。

#include <stdio.h>

char * remove_duplicates( char *s )
{
    if ( *s )
    {
        if ( *s == *( s + 1 ) )
        {
            *( s + 1 ) = *( s + 2 );
            remove_duplicates( s + 1 );
            remove_duplicates( s );
        }
        else
        {
            remove_duplicates( s + 1 );
        }           
    }

    return s;
}

int main(void) 
{
    char s[] = "MMMMMuuuuuOOOOOKKKKLLLEE";

    remove_duplicates( s );

    puts( s );

    return 0;
}

程序输出是

MuOKLE

【讨论】:

  • 逻辑很痛苦:)——但话又说回来,所有具有多个递归调用的递归逻辑......做得好。
【解决方案2】:

我是这样做的:

#include <stdio.h>

char* remove_duplicates(char* str)
{
    if (*str)
    {
        char* dest = remove_duplicates(str + 1);
        str = (*str == *dest) ? dest : ((*(dest - 1) = *str), (dest - 1));
    }
    return str;
}

int main()
{
    char sample[] = "MMMMMuuuuuOOOOOKKKKLLLEE OOOOLLL";
    char sample2[] = "AA";

    printf("OLD: |%s|\n", sample);
    printf("NEW: |%s|\n", remove_duplicates(sample));

    printf("OLD: |%s|\n", sample2);
    printf("NEW: |%s|\n", remove_duplicates(sample2));

    return 0;
}

输出

OLD: |MMMMMuuuuuOOOOOKKKKLLLEE OOOOLLL|
NEW: |MuOKLE OL|
OLD: |AA|
NEW: |A|

【讨论】:

  • 有趣的是,它将非重复项移到末尾,然后在非重复项开始的字符串中返回一个指针,但原始字符串(例如,如果您再次打印sample)仍然包含重复。
  • @abelenky 您提供了错误的代码。试试下面的 char sample[] = "AA";删除重复项(样本); printf("\"%s\"\n", 示例);
  • @Vlad:我的代码确实修改了sample,但它返回了一个指向数组正确部分的指针。你应该试试printf("\"%s\"\n", remove_duplicates(sample));,你会看到返回值是正确的。
  • @abelenky 这是一种无效的方法。您必须从作为参数传递给函数的指针指向的原始字符串中删除重复项。
  • @Vlad 问题描述中没有指定。我的返回值是正确的。
【解决方案3】:

感谢大家的帮助。正如你所说,我在纸上浏览了我的代码,并意识到问题是它没有比较第一个和最后一个 M。 我添加了一个新的 if 语句 if(*str==*(str-1)) *(str)=*(str+1);,它现在可以工作了。

现在的功能是:

char* remove_duplicates (char* str){
    if(*(str+1)!='\0'){
        if(*str==*(str+1)){
            *(str+1)=*(str+2);
            remove_duplicates(str+1);
        }
        remove_duplicates(str+1);
    }
    if(*str==*(str-1)) *(str)=*(str+1);
    return str;
}

【讨论】:

    【解决方案4】:

    我这里只是添加递归函数(语言:C++)而不是整个代码。

    void removeConsecutiveDuplicates(char input[]) {
       
        if(input[0] == '\0' || input[1]=='\0') return;
        if(input[0]!=input[1]) return removeConsecutiveDuplicates(input+1);
        else
        {
            for(int i=1;i<=strlen(input);i++)
            {
                input[i-1] = input[i];
            }
           return removeConsecutiveDuplicates(input);
        }  
        return; 
    }
    

    【讨论】:

    • 您好,欢迎来到 Stack Overflow!请拨打tour。感谢您提供答案,但您是否还可以添加有关您的代码如何解决问题的解释?检查此help center erticle 以获取格式化代码的帮助。
    【解决方案5】:

    我觉得递归太复杂了。

    让我们从 str 开头的 2 个光标开始

    首先在字符串上循环。 虽然我们没有到达字符串的结尾*p,但请期待p++

    while (*p++) {
        if (*p == *current)
            continue;
    

    如果下一个字符与当前字符相同,则继续搜索下一个不同的字符。

    current++;
    *current = *p;
    

    当找到不同的字符时,只需将其放在当前字符之后。

    #include <stdio.h>
    
    char* remove_duplicates (char* str){
        char *p = str;
        char *current = p;
        while (*p++) {
            if (*p == *current)
                continue;
            current++;
            *current = *p;
        }
    
        return str;
    }
    
    int main()
    {
        char sample[] = "MMMMMuuuuuOOOOOKKKKLLLEE OOOOLLL";
    
        printf("OLD: |%s|\n", sample);
        printf("NEW: |%s|\n", remove_duplicates(sample));
        printf("NEW: |%s|\n", remove_duplicates(""));
    
        return 0;
    }
    
    
    OLD: |MMMMMuuuuuOOOOOKKKKLLLEE OOOOLLL|
    NEW: |MuOKLE OL|
    NEW: ||
    

    详细信息与AAAB c为电流

    p
    v
    AAAB0
    ^
    c
    
       p
       v
    AAAB0
    ^
    c
    
       p
       v
    AAAB0
     ^
     c
    
       p
       v
    ABAB0
     ^
     c
    
        p
        v
    ABAB0
     ^
     c
    
    
        p
        v
    ABAB0
      ^
      c
    
    
        p
        v
    AB0B0
      ^
      c
    

    我们得到AB

    【讨论】:

    • 太复杂了?我的函数是一个 if 语句中的 4 行代码,并且根据要求是递归的。
    • @abelenky 见 David C. Rankin 的评论,我认为这个主题的递归并不简单,4 行和一个大三元不确定它是否简单。
    猜你喜欢
    • 1970-01-01
    • 2022-01-26
    • 2013-02-05
    • 2011-10-20
    • 2018-05-01
    • 2013-11-12
    • 1970-01-01
    • 2020-03-30
    • 1970-01-01
    相关资源
    最近更新 更多