如果字符串重复,是否有办法只返回重复的字母一次?

时间:2018-12-21 21:53:04

标签: c

我编写的代码将为字符串“ aabbcc”返回“ abc”,但是如果有更多的字母(如“ aaa”),它将返回“ aa”而不是一个。

这是我编写的代码。

void Ponavljanje(char *s, char *p) {
  int i, j = 0, k = 0, br = 0, m = 0;
  for (i = 0; i < strlen(s) - 1; i++) {
    for (j = i + 1; j < strlen(s); j++) {
      if (s[i] == s[j]) {
        br++;
        if (br == 1) {
          p[k++] = s[i];
        }
      }

    }
    br = 0;
  }
  p[k] = '\0';
  puts(p);
}

对于“ 112233”输出应为“ 123”,对于“ 11122333”输出也应为“ 123”。

5 个答案:

答案 0 :(得分:1)

做这项工作的复杂度为O(n) 我想编程可以给rmg

void Ponavljanje(char *s,char *p)
{
  char n[256] = {0};
  int i = 0;

  while (*s) {
    switch (n[(unsigned char) *s]) {
    case 0:
      n[(unsigned char) *s] = 1;
      break;
    case 1:
      p[i++] = *s;
      n[(unsigned char) *s] = 2;
    }    
    s += 1;
  }

  p[i] = 0;

  puts(p);
}

答案 1 :(得分:1)

  • 避免重复调用strlen(s)。弱小的编译器可能看不到s不变,并多次调用strlen(s),每次调用都保证了n操作的成本-效率很低。 @arkku 1 而是在检测到空字符时停止迭代。

  • 将所有char的标志的布尔值列表初始化为false。出现字符时,设置标志以防止后续使用。将列表索引为char可能为负时要小心。

  • 使用const char *s可以扩大分配范围,并有助于编译器优化。

示例:

#include <stdbool.h>
#include <limits.h>

void Ponavljanje(const char *s, char *p) {
  const char *p_original = p;
  bool occurred[CHAR_MAX - CHAR_MIN + 1] = { 0 }; // all values set to 0 (false)
  while (*s) {
    if (!occurred[*s - CHAR_MIN]) {
      occurred[*s - CHAR_MIN] = true;
      *p++ = *s;
    }
    s++; 
  }
  *p = '\0';
  puts(p_original);
}

1 @wrongway4you的评论是,许多编译器可能会假设字符串没有变化,并优化了重复的strlen()调用。兼容编译器无法这样做,尽管没有restrict,除非知道,在所有调用中,sp不会重叠。否则,编译器需要假设p 可能影响s,并保证重复进行strlen()调用。

答案 2 :(得分:0)

虽然内部循环检查br仅在第一次重复时复制输出,但在以后的迭代中,外部循环仍会越过s中的每个重复。因此,br重置后,每次出现相同的字符都会运行一个单独的内部循环。

使用aaa作为输入,第一个a和第二个aa都会使内部循环找到重复,给您clone。实际上,输出中每个字符总是比输入少一个出现,这意味着它只能在输入中出现1或2个出现(输出中分别出现0和1个出现)。

答案 3 :(得分:0)

这是不管顺序如何都可以起作用的东西:

#include <stdio.h>
#include <string.h>

void
repeat(char *s, char *p)
{
    int slen;
    int sidx;
    int pidx;
    int plen;
    int schr;

    slen = strlen(s);
    plen = 0;

    for (sidx = 0; sidx < slen; ++sidx) {
        schr = s[sidx];

        // look for duplicate char
        int dupflg = 0;
        for (pidx = 0;  pidx < plen;  ++pidx) {
            if (p[pidx] == schr) {
                dupflg = 1;
                break;
            }
        }

        // skip duplicate chars
        if (dupflg)
            continue;

        p[plen++] = schr;
    }

    p[plen] = 0;

    puts(p);
}

int
main(void)
{
    char p[100];

    repeat("112233",p);
    repeat("123123",p);

    return 0;
}

注意:正如其他人所提到的,strlen不应放在for的循环条件子句中,因为s的长度是不变的]。将strlen(s)保存到一个单独的变量中并循环到该限制


以下是使用直方图的其他/更快的版本,因此只需要一个循环:

#include <stdio.h>
#include <string.h>

void
repeat(char *s, char *p)
{
    char dups[256] = { 0 };
    int slen;
    int sidx;
    int pidx;
    int plen;
    int schr;

    slen = strlen(s);

    sidx = 0;
    plen = 0;

    for (sidx = 0; sidx < slen; ++sidx) {
        schr = s[sidx] & 0xFF;

        // look for duplicate char
        if (dups[schr])
            continue;
        dups[schr] = 1;

        p[plen++] = schr;
    }

    p[plen] = 0;

    puts(p);
}

int
main(void)
{
    char p[100];

    repeat("112233",p);
    repeat("123123",p);

    return 0;
}

更新#2:

  

我建议迭代直到终止的NUL字节

好的,这是一个完整的指针版本,其速度与我所知道的一样快:

#include <stdio.h>
#include <string.h>

void
repeat(char *s, char *p)
{
    char dups[256] = { 0 };
    char *pp;
    int schr;

    pp = p;

    for (schr = *s++;  schr != 0;  schr = *s++) {
        schr &= 0xFF;

        // look for duplicate char
        if (dups[schr])
            continue;
        dups[schr] = 1;

        *pp++ = schr;
    }

    *pp = 0;

    puts(p);
}

int
main(void)
{
    char p[100];

    repeat("112233",p);
    repeat("123123",p);

    return 0;
}

答案 4 :(得分:0)

如果您只想删除连续的双字母,那么此功能就足够了,问题中给出的示例将适用:

#include <stdio.h>
void Ponavljanje(char *s,char *p)
{
  char dd = '\0';
  char *r;
  if(s == NULL || p == NULL)
    return;
  r = p;
  while(*s){
    if(*s != dd){
      *r = *s;
      dd = *s;
      r++;
    }
    s++;
  }
  *r = '\0';
  puts(p);
}
int main(void)
{
  char s[20] = "1111332222";
  char p[20];
  Ponavljanje(s,p);
}