[JavaScript / leetcode] 481. 神奇字符串

85 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第30天,点击查看活动详情

每日刷题 2022.10.31

题目

  • 神奇字符串 s 仅由 '1''2' 组成,并需要遵守下面的规则:
  • 神奇字符串 s 的神奇之处在于,串联字符串中 '1''2' 的连续出现次数可以生成该字符串。
  • s 的前几个元素是 s = "1221121221221121122……" 。如果将 s 中连续的若干 12 进行分组,可以得到 "1 22 11 2 1 22 1 22 11 2 11 22 ......" 。每组中 1 或者 2 的出现次数分别是 "1 2 2 1 1 2 1 2 2 1 2 2 ......" 。上面的出现次数正是 s 自身。
  • 给你一个整数 n ,返回在神奇字符串 s 的前 n 个数字中 1 的数目。

示例

  • 示例1
输入: n = 6
输出: 3
解释: 神奇字符串 s 的前 6 个元素是 “122112”,它包含三个 1,因此返回 3 。 
  • 示例2
输入: n = 1
输出: 1

提示

  • 1 <= n <= 10^5

解题思路

  • 类似于找规律的题目,根据题目可知:神奇字符串中的12是交替出现的。
  • 可以发现,从字符串的第3位开始,即:122。此时第3位数字为2,也就表示:字符串后面新追加的数字个数为2,那么数值是1(因为12是交替出现的)。此时字符串改变为:12211
  • 继续走到第4位数字(值为1),表示:字符串后面新追加的数字个数为1,值为2(因为12是交替出现的)。此时字符串转变为122112
  • 一直循环这样的操作,直到字符串的长度为n
  • 还需要注意⚠️:最后可能会出现多出来的1,题目中要求统计前n个中的数值1的个数,因此需要将多出来的部分减去。

小优化点

  • 需求:想要第一次为1,下一次为2,一直这样交替填充数组。
    • 实现:可以使用boolean标记符,进行切换。当前为1,则flag = true;当前为2,则flag = false
    • 更巧妙的实现方式:异或运算符C^3,进行切换。初始化C为第一个值1,则c^3 = 2,此时转换为2;下一次C^3的时候,因为当前C = 2,因此得到了C^3 = 1
    • 还可以通过数字的奇偶性,来切换12,取模% 或者 >>&1的方式.

AC代码

/**
 * @param {number} n
 * @return {number}
 */
var magicalString = function(n) {
  if(n <= 3) return 1;
  let arr = new Array(n + 1).fill(0), l = 2, r = 2, sum = 1,c = 2;
  arr[0] = 1, arr[1] = 2, arr[2] = 2;
  while(r < n) {
    let cur = arr[l++];
    c ^= 3;
    arr[++r] = c;
    if(c === 1) sum++;
    if(cur === 2) {
      arr[++r] = c;
      if(c === 1) sum++;
    }
  }
  // console.log(r, sum)
  while(r >= n && arr[r--] === 1) {
    sum--;
  }
  return sum;
};