1. 程式人生 > 其它 >LeetCode-38-外觀數列(C)

LeetCode-38-外觀數列(C)

技術標籤:Cleetcodec語言

文章首發及後續更新:https://mwhls.top/1577.html
新的更新內容請到mwhls.top檢視。
無圖/無目錄/格式錯誤/更多相關請到上方的文章首發頁面檢視。

這題想把記憶體降低的話,一個很邪道的方法,是把結果長度遍歷出來然後按需分配。
這個按需分配不是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;
    }
}