38. 外观数列|刷题打卡

138 阅读2分钟

掘金团队号上线,助你 Offer 临门! 点击 查看详情

一、题目描述:

给定一个正整数 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"
要 描述 一个数字字符串,首先要将字符串分割为 最小 数量的组,每个组都由连续的最多 相同字符 组成。然后对于每个组,先描述字符的数量,然后描述字符,形成一个描述组。要将描述转换为数字字符串,先将每组中的字符数量用数字替换,再将所有描述组连接起来。
  • 示例  
示例 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

 

二、思路分析:

  • 感觉有点难度,刚开始也是没写出来,
  • 后来参考别人的
  • 1.递归+双指针算法
leftright 来确定每个字符的重复数
当 leftright 所指字符相同时,right 向右移动一位,直到 right 所指与 left 不同。
确定相同字符的个数,既 right - left 的值,该值表示的即是 left 所指字符的个数。
将结果转为以字符的形式储存。
继续历遍,因为 leftright 之间的字符已经历遍过了,所以更新指针 leftright。
当 right 超出字符范围时,结束循环。

。

三、AC 代码

/**
 * @param {number} n
 * @return {string}
 */
var countAndSay = function(n) {
    let num = "1";
    let sum = ""
    for(let l=0;l<n-1;l++){
        let sum = ""
        for(let i =0,j=0;i<num.length;){
            if(num[i]==num[i+j]){
                j++;
            }else{
                sum = sum +j+""+num[i]; 
                i += j;
                j=1;
            }
        }
        num = sum;
    }
    return num;

};

状态:通过
执行用时: 88 ms
内存消耗: 40.6 MB


四、总结

  • 下面递归;
/**
 * @param {number} n
 * @return {string}
 */
var countAndSay = function(n) {
  if (n === 1) {
        return "1";
    };
    let pre = countAndSay(n - 1);
    let result = "", left = 0, right = 0;
    console.log(pre)
    while (right < pre.length) {
        while (pre[left] === pre[right] && right < pre.length) {
            right++;
        };
        result += (right - left).toString() + pre[left];
        left = right;
    }
    return result;

};
  • 也看到用正则的
/**
 * @param {number} n
 * @return {string}
 */
var countAndSay = function(n) {
   var s="1"
    while(--n)s=s.replace(/(.)\1*/g,(m,d)=>m.length+d)
    return s

};
感觉不是很好理解

仅供学习参考

参考题目