LeetCode-38-外觀數列(C)
阿新 • • 發佈:2021-02-01
文章首發及後續更新:https://mwhls.top/1577.html
新的更新內容請到mwhls.top檢視。
無圖/無目錄/格式錯誤/更多相關請到上方的文章首發頁面檢視。
這題想把記憶體降低的話,一個很邪道的方法,是把結果長度遍歷出來然後按需分配。
這個按需分配不是realloc,這個函式在LeetCode裡面消耗記憶體很大,我也不清楚是這函式特性還是LeetCode特性。
題目
給定一個正整數 n ,輸出外觀數列的第 n 項。
「外觀數列」是一個整數序列,從數字 1 開始,序列中的每一項都是對前一項的描述。
你可以將其視作是由遞迴公式定義的數字字串序列:
countAndSay(1) = "1"
countAndSay(n) 是對 countAndSay(n-1) 的描述,然後轉換成另一個數字字串。
前五項如下:
- 1
- 11
- 21
- 1211
- 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(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;
}
}