C面试问题---字符串的游程编码

时间:2010-01-12 12:25:22

标签: c

我的一位朋友在雅虎的采访中被问到以下问题:

给定一个“abbccc”形式的字符串print“a1b2c3”。编写一个接受字符串并返回字符串的函数。照顾所有特殊情况。

你会如何编写专家代码?

非常感谢

8 个答案:

答案 0 :(得分:15)

if (0==strcmp(s, "abbccc")) 
  return "a1b2c3";
else
  tip_the_interviewer(50);

照顾。

答案 1 :(得分:11)

有多种方法可以做到这一点,但我可能会在输入字符串上运行两次:一次计算输出需要多少字节,然后分配输出缓冲区并再次实际生成输出。

另一种可能性是在输入字符串中加前两倍的字节数(加一),然后将输出写入其中。这使代码更简单,但可能非常浪费内存。由于操作看起来像一个基本压缩(RLE),也许最好是第一个实现没有输出占用输入内存的两倍。

另一种可能性是进行单次传递,并根据需要重新分配输出字符串,可能会以指数方式增加大小以确保O(N)整体性能。这在C中非常繁琐,所以可能不是函数的初始实现,特别是在面试条件下。它也不一定比我的第一个版本快。

然而,它已经完成,显而易见的“特殊情况”是一个空输入字符串,因为显而易见的(对我而言)实现将从存储第一个字符开始,然后进入循环。写输出可能不明确的东西也很容易:“1122”是输入“122”的输出,但也许它也是由122个1个字符组成的输入的输出。因此,您可能希望将运行长度限制为最多9个字符(假设基数为10)以防止出现歧义。这取决于函数的用途 - 从单个示例输入和输出中调用完整的函数规范是不可能的。

设计界面还有不止一种方法:问题是“返回一个字符串”,所以大概是在用malloc新分配的缓冲区中的NUL终止字符串。但是,从长远来看,这并不总是编写所有字符串API的好方法。在一个真实的项目中,我更愿意设计一个函数,它将要处理的字符串作为输入,连同指向输出缓冲区的指针和缓冲区的长度。它返回写入的字节数,或者如果输出缓冲区不够大,则返回已写入的数字。使用这个新功能实现所述功能很简单:

char *stated_function(const char *in) {
    size_t sz = new_function(in, NULL, 0);
    char *buf = malloc(sz);
    if (buf) new_function(in, buf, sz);
    return buf;
}

我也很困惑“打印”在问题中意味着什么 - 其他回答者将其视为“写入stdout”,意味着不需要分配。面试官是否想要一个打印编码字符串的函数,而会返回它?打印并返回其他内容?只返回一个字符串,当它们不是真的意思时使用“print”吗?

答案 2 :(得分:4)

遵循以下算法并实施它。

  1. 为所有字母运行循环 字符串。
  2. 将第一个字符存储在临时文件中 char变量。
  3. 每次改变角色 使用1和1初始化计数器 打印以前的计数 字符,然后是新信。

答案 3 :(得分:3)

这有点像家庭作业问题,但代码写起来太有趣了。

关键想法:

  • 字符串是一个(可能是空的)非空运行相同字符的序列。
  • 指针first始终指向一系列相同字符中的第一个。
  • 在内部while循环之后,指针beyond指向一行相同字符的结尾。
  • 如果一个游戏的第一个字符是零,我们已到达字符串的末尾。空字符串作为更一般问题的一个例子而失效。
  • 十进制数字所需的空间始终至多为运行的长度,因此结果最多需要内存的两倍。代码运行正常,运行长度为53:valgrind报告没有内存错误。
  • 指针算法非常漂亮。

代码:

char *runcode(const char *s) {
  char *t = malloc(2 * strlen(s) + 1);  // eventual answer
  assert(t);
  char *w = t; // writes into t;
  const char *first, *beyond; // mark limits of a run in s
  for (first = s; *first; first = beyond) { // for each run do...
    beyond = first+1;
    while (*beyond == *first) beyond++;  // move to end of run
    *w++ = *first;                       // write char
    w += sprintf(w, "%d", beyond-first); // and length of run
  }
  *w = '\0';
  return t;
}

我喜欢的事情:

  • 我们当前正在扫描的角色没有辅助变量。
  • 没有计数的辅助变量。
  • 合理地不使用其他局部变量。

答案 4 :(得分:2)

正如其他人所指出的,该规范含糊不清。我认为对于面试问题来说这很好:关键在于看看求职者在模棱两可的情况下做了什么。

这是我对代码的看法。我做了一些假设(因为在这种情况下我不能很好地询问面试官):

  1. 这是一种简单的游程编码形式。
  2. 输出格式为{character} {count}。
  3. 为避免歧义,计数为1..9。
  4. 长于9的相同字符的运行会被分成多个计数。
  5. 未进行动态分配。在C中,让调用者处理它通常更好。我们返回true / false以指示是否有足够的空间。
  6. 我希望代码足够清晰,能够独立存在。我已经包含了一个测试工具和一些测试用例。

    #include <stdbool.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    
    static void append(char **output, size_t *max, int c)
    {
        if (*max > 0) {
            **output = c;
            *output += 1;
            *max -= 1;
        }
    }
    
    
    static void encode(char **output, size_t *max, int c, int count)
    {
        while (count > 9) {
            append(output, max, c);
            append(output, max, '0' + 9);
            count -= 9;
        }
        append(output, max, c);
        append(output, max, '0' + count);
    }
    
    
    static bool rle(const char *input, char *output, size_t max)
    {
        char prev;
        int count;
    
        prev = '\0';
        count = 0;
        while (*input != '\0') {
            if (*input == prev) {
                count++;
            } else {
                if (count > 0)
                    encode(&output, &max, prev, count);
                prev = *input;
                count = 1;
            }
            ++input;
        }
    
        if (count > 0)
            encode(&output, &max, prev, count);
        if (max == 0)
            return false;
        *output = '\0';
        return true;
    }
    
    
    int main(void)
    {
        struct {
            const char *input;
            const char *facit;
        } tests[] = {
            { "", "" },
            { "a", "a1" },
            { "aa", "a2" },
            { "ab", "a1b1" },
            { "abaabbaaabbb", "a1b1a2b2a3b3" },
            { "abbccc", "a1b2c3" },
            { "1", "11" },
            { "12", "1121" },
            { "1111111111", "1911" },
            { "aaaaaaaaaa", "a9a1" },
        };
        bool errors;
    
        errors = false;
        for (int i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i) {
            char buf[1024];
            bool ok;
            ok = rle(tests[i].input, buf, sizeof buf);
            if (!ok || strcmp(tests[i].facit, buf) != 0) {
                printf("FAIL: i=%d input=<%s> facit=<%s> buf=<%s>\n",
                       i, tests[i].input, tests[i].facit, buf);
                errors = true;
            }
        }
    
        if (errors)
            return EXIT_FAILURE;
        return 0;
    }
    

答案 5 :(得分:1)

该死的,以为你说的是​​C#,而不是C.这是我感兴趣的C#实现。

    private string Question(string input)
    {
        var output = new StringBuilder();
        while (!string.IsNullOrEmpty(input))
        {
            var first = input[0];
            var count = 1;
            while (count < input.Length && input[count] == first)
            {
                count++;
            }

            if (count > input.Length)
            {
                input = null;
            }
            else
            {
                input = input.Substring(count);
            }
            output.AppendFormat("{0}{1}", first, count);
        }

        return output.ToString();
    }

答案 6 :(得分:1)

int priya_homework(char *input_str, char *output_str, int out_len)
{
  char pc,c;
  int count=0,used=0;

  /* Check for NULL and empty inputs here and return*/

  *output_str='\0';

  pc=*input_str;
  do
  {
    c=*input_str++;
    if (c==pc)
    {
      pc=c;
      count++;
    }
    else
    {
      used=snprintf(output_str,out_len,"%c%d",pc,count);
      if (used>=out_len)
      {
        /* Output string too short */
        return -1;
      }
      output_str+=used;
      out_len-=used;
      pc=c;
      count=1;
    }
  } while (c!='\0' && (out_len>0));

  return 0;
}

答案 7 :(得分:0)

这样的事情:

void so(char s[])
{
        int i,count;
        char cur,prev;

        i = count = prev = 0;
        while(cur=s[i++])
        {
                if(!prev)
                {
                        prev = cur;
                        count++;
                }
                else
                {
                        if(cur != prev)
                        {
                                printf("%c%d",prev,count);
                                prev = cur;
                                count = 1;
                        }
                        else
                                count++;
                }
        }

        if(count)
                printf("%c%d",prev,count);
        printf("\n");
}