持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第30天,点击查看活动详情
每日刷题 2022.10.31
- leetcode原题链接:leetcode.cn/problems/ma…
- 难度:中等
题目
- 神奇字符串
s
仅由'1'
和'2'
组成,并需要遵守下面的规则: - 神奇字符串
s
的神奇之处在于,串联字符串中'1'
和'2'
的连续出现次数可以生成该字符串。 s
的前几个元素是s = "1221121221221121122……"
。如果将s
中连续的若干1
和2
进行分组,可以得到"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
解题思路
- 类似于找规律的题目,根据题目可知:神奇字符串中的
1
和2
是交替出现的。 - 可以发现,从字符串的第
3
位开始,即:122
。此时第3
位数字为2
,也就表示:字符串后面新追加的数字个数为2
,那么数值是1
(因为1
和2
是交替出现的)。此时字符串改变为:12211
。 - 继续走到第
4
位数字(值为1
),表示:字符串后面新追加的数字个数为1
,值为2
(因为1
和2
是交替出现的)。此时字符串转变为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
。 - 还可以通过数字的奇偶性,来切换
1
和2
,取模%
或者>>
后&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;
};