LeetCode-简单-38-外观数列(C)

这题想把内存降低的话,一个很邪道的方法,是把结果长度遍历出来然后按需分配。
这个按需分配不是realloc,这个函数在LeetCode里面消耗内存很大,我也不清楚是这函数特性还是LeetCode特性。

题目

给定一个正整数 n ,输出外观数列的第 n 项。 「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。 你可以将其视作是由递归公式定义的数字字符串序列: countAndSay(1) = “1”
countAndSay(n) 是对 countAndSay(n-1) 的描述,然后转换成另一个数字字符串。
前五项如下:

  1. 1
  2. 11
  3. 21
  4. 1211
  5. 111221
    第一项是数字 1
    描述前一项,这个数是 1 即 “ 一 个 1 ”,记作 “11”
    描述前一项,这个数是 11 即 “ 二 个 1 ” ,记作 “21”
    描述前一项,这个数是 21 即 “ 一 个 2 + 一 个 1 ” ,记作 “1211”
    描述前一项,这个数是 1211 即 “ 一 个 1 + 一 个 2 + 二 个 1 ” ,记作 “111221”
    要 描述 一个数字字符串,首先要将字符串分割为 最小 数量的组,每个组都由连续的最多 相同字符 组成。然后对于每个组,先描述字符的数量,然后描述字符,形成一个描述组。要将描述转换为数字字符串,先将每组中的字符数量用数字替换,再将所有描述组连接起来。
例如,数字字符串 “3322251” 的描述如下图: 示例 1: 输入:n = 1
输出:”1″
解释:这是一个基本样例。
示例 2: 输入:n = 4
输出:”1211″
解释:
countAndSay(1) = “1”
countAndSay(2) = 读 “1” = 一 个 1 = “11”
countAndSay(3) = 读 “11” = 二 个 1 = “21”
countAndSay(4) = 读 “21” = 一 个 2 + 一 个 1 = “12” + “11” = “1211”
  提示: 1 <= n <= 30 来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/count-and-say
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

  • 一个result存放递归(n)的描述字符串,一个say存放递归(n-1)的描述字符串。
  • 从say的第2位开始循环,直到strlen(say)+1:
    • 每次循环都判断该位与前位是否相同,不同就将result新增,相同就计数。
    • 在result新增的部分,先增加相同数量,再增加相同的字符。
    • 当循环到say的第strlen(say)+1时,直接添加result,不然会出错,因为say没有那么长。
  • 减少内存消耗的话,可以将所有的情况分配的空间都遍历出来,就像倒数第四行被注释的代码一样。
    • 不过效果和分段划分大小差不多,我测试了一下,switch代码和下面的if代码效果相似,都能0ms,6MB,所以为了显得我正常一点点,就用了if的。
switch(n){
case 2: resultLen=3; break;
case 3: resultLen=3; break;
case 4: resultLen=5; break;
case 5: resultLen=7; break;
case 6: resultLen=7; break;
case 7: resultLen=9; break;
case 8: resultLen=11; break;
case 9: resultLen=15; break;
case 10: resultLen=21; break;
case 11: resultLen=27; break;
case 12: resultLen=35; break;
case 13: resultLen=47; break;
case 14: resultLen=63; break;
case 15: resultLen=79; break;
case 16: resultLen=103; break;
case 17: resultLen=135; break;
case 18: resultLen=177; break;
case 19: resultLen=227; break;
case 20: resultLen=303; break;
case 21: resultLen=409; break;
case 22: resultLen=529; break;
case 23: resultLen=679; break;
case 24: resultLen=905; break;
case 25: resultLen=1183; break;
case 26: resultLen=1541; break;
case 27: resultLen=2013; break;
case 28: resultLen=2607; break;
case 29: resultLen=3411; break;
case 30: resultLen=4463; break;
}

代码

char * countAndSay(int n){
    if(n==1){
        return "1";
    }
    else{
        int num=1, len, pos, resultPos=0, resultLen;
        if(n<=15) resultLen=79;
        else if(n<=20) resultLen=303;
        else if(n<=25) resultLen=1183;
        else if(n<=27) resultLen=2021;
        else if(n<=30) resultLen=4463;
        char* say = countAndSay(n-1);
        char* result = (char*)malloc(resultLen);
        result[0]='\0';
        for(len = strlen(say), pos=1;    pos<=len;    pos++){
            if(pos==len){
                result[resultPos*2] = '0'+num;
                result[resultPos*2+1] = say[pos-1];
                result[resultPos*2+2] = '\0';
                resultPos++;
            }
            else if(say[pos] == say[pos-1]){
                num+=1;
            }
            else{
                result[resultPos*2] = '0'+num;
                result[resultPos*2+1] = say[pos-1];
                result[resultPos*2+2] = '\0';
                resultPos++;
                num=1;
            }
        }
        //printf("case %d: resultLen=%d; break;\n", n, strlen(result)+1);
        return result;
    }
}

You may also like...

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注