

1.拿到本题后看到"迭代"的进阶提示,想到可以使用for循环来进行迭代,只需要将迭代的代码解决即可。迭代逻辑不难理解,遍历当前的字符串,记录当前元素重复的次数与本身的值,传入结果字符串即可。为了每次操作的时候不破坏原有字符串的结构,需要额外创建一个字符串来进行操作,操作完成后拷贝到结果字符串中。
2.基于以上思想,可写出完整代码如下:
cpp
1. char* countAndSay(int n) {
2. // 分配结果字符串内存(n≤30 时最长约 4000+,5000 足够)
3. char* res = (char*)calloc(5000, sizeof(char));
4. // 临时字符串:用于存储每一轮的编码结果
5. char* tmp = (char*)calloc(5000, sizeof(char));
6. // 初始值:countAndSay(1) = "1"
7. res[0] = '1';
8.
9. // 从第 2 项迭代到第 n 项(共 n-1 轮)
10. for (int i = 1; i < n; i++){
11. int len = strlen(res); // 当前 res 的长度
12. int cur1 = 0; // 遍历 res 的指针
13. int cur2 = 0; // 填充 tmp 的指针
14.
15. // 核心:对 res 进行行程长度编码(RLE)
16. while (cur1 < len){
17. int cnt = 0; // 连续相同字符的计数
18. char cur_char = res[cur1];// 当前要统计的字符
19. // 统计连续相同字符的个数
20. while (cur1 < len && res[cur1] == cur_char){
21. cur1++;
22. cnt++;
23. }
24. // 把「次数 + 字符」写入 tmp
25. tmp[cur2++] = cnt + '0'; // 数字转字符:cnt + '0'
26. tmp[cur2++] = cur_char;
27. }
28. tmp[cur2] = '\0'; // 给 tmp 加上字符串结束符
29. strcpy(res, tmp); // 把本轮编码结果拷贝回 res,作为下一轮的输入
30. }
31.
32. return res; // 返回最终第 n 项
33. }
该算法的时间复杂度为O(N×L),其中N是迭代次数n,L是每一轮字符串的平均长度,空间复杂度为O(L),是本题的标准解法。
3.在编写代码的过程中有以下几点需要注意:
①在进行重复个数计数时,不要"向后比",应该"向前看"。先记住当前长什么样的字符,然后往后数有多少个和它一样的,数完同时游标也就跟着走完了。这样是最稳妥的做法,以免出现越界、死循环等情况。
②开辟内存的时候,要注意本题的字符串长度增长得非常快,所以要开辟大一些的空间。
③字符串拷贝的时候最好使用strcpy而不是memcpy,因为strcpy会自动找到'\0',并在复制完成后自动补'\0',而memcpy还需要注意额外开辟放置'\0'的空间,并且最后手动补'\0':
cpp
1. strcpy(res, tmp);
2. memcpy(res, tmp, sizeof(char) * cur2);
4.官方还给出了一种查表的方法,因为本题输入的最大迭代次数为30,情况不算多,所以可以将所有情况全都枚举出来,根据输入的迭代次数进行查表后输出对应字符串。这种方法的时间复杂度为O(1),空间复杂度为O(C×M),其中C是N是上界,在本题中C=30,M为生成的字符串中的最大长度。属于是用空间换时间了。