「这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战」
题目描述
给定一个正整数
n,输出外观数列的第n项。「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。
你可以将其视作是由递归公式定义的数字字符串序列:
countAndSay(1) = "1"countAndSay(n)是对countAndSay(n-1)的描述,然后转换成另一个数字字符串。
示例 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:递归
分析:思路很简单,递归每一项,但建议使用StringBuilder,频繁操作String使用普通拼接效率极低。
- 一次递归遍历字符串的一个元素。
- 每次遍历可得到数字计数及数字(占2个长度)
- 然后StringBuilder append()
class Solution {
public String countAndSay(int n) {
if(n == 1) return "1";
else {
StringBuilder builder = new StringBuilder();
String str = countAndSay(n-1);
char pre = str.charAt(0);
int count = 1;
for (int j = 1; j < str.length(); j++) {
char c = str.charAt(j);
if (c == pre) {
count++;
} else {
builder.append(count).append(pre);
pre = c;
count = 1;
}
}
builder.append(count).append(pre);
str = builder.toString();
return str;
}
}
}
思路2:双指针法
分析:通过双指针去找到重复的数的个数。而且我们得必须由前往后迭代,所以用countAndSay作为迭代函数,而具体的迭代过程放在change函数中进行递归调用。
具体步骤
-
慢指针i由前往后,快指针j以慢指针为出发点,直至找到不等于慢指针相等的数;
-
将当前找的数加入res。
class Solution { public String countAndSay(int n) { String pre = "1"; for(int i=1;i<n;i++){ StringBuffer sb = new StringBuffer(""); int pre_len = pre.length(); int count = 1; char c = pre.charAt(0); for(int j=1;j<pre_len;j++){ if(pre.charAt(j)==c){ count++; }else{ sb.append(count).append(c); c = pre.charAt(j); count = 1; } } pre = sb.append(count).append(c).toString(); } return pre; } }
最后分析
执行用时:0 ms, 在所有Java 提交中击败了100.00%的用户
内存消耗:6.4 MB, 在所有Java 提交中击败了64.15%的用户
用递归解决问题,将n-1步的字符串作为处理对象,‘0‘ 字符的ASCII码是48
整体的时间复杂度也不高,也可能是数据太弱了,通过空间换时间的方式。相比之下更推荐双指针的方法。
从第一项向后推最后一项。