题目描述:
第一时间想到的两种暴力解法:
- 递归出所有结果, 组合成二维数组, 最后返回对应值:
// 暴力 递归 超时...
const res: number[][] = [];
const fn = (nums: number[], i: number) => {
if (i >= n) return;
res[i] = Array.isArray(res[i]) ? [...res[i], ...nums] : nums;
nums.forEach((item) => {
if (item === 0) fn([0, 1], i + 1);
if (item === 1) fn([1, 0], i + 1);
});
};
fn([0], 0);
return res[n - 1]?.[k - 1] ?? 0;
- reduce 返回第n行的结果, 用数组接收:
//超出数组长度...
const res = Array.from({ length: n }).reduce((res: number[], current) => {
const tmp: number[] = [];
res.forEach((item) => {
item === 0 ? tmp.push(...[0, 1]) : tmp.push(...[1, 0]);
});
return tmp;
}, [0]);
return res[k - 1] ?? 0;
- 找规律: 第一行: 0
第二行: 01
第三行: 01 10
第四行: 01 10 10 01
第五行: 01 10 10 01 10 01 01 10
第六行: 01 10 10 01 10 01 01 10 10 01 01 10 01 10 10 01
可以看到开头部分其实完全相同, 并且后半部分和前半部分刚好对称, 于是得出代码:
function kthGrammar(n: number, k: number): number {
//递归结束条件
if (k === 1) return 0;
if (k === 2) return 1;
const len = Math.pow(2, n - 1);
if (k > len / 2) {
//位于后半部分, 找出前半部分的值, 然后取相反值, 因为是对称的
return kthGrammar(n - 1, k - len / 2) === 0 ? 1 : 0;
}
//位于前半部分, 直接返回前半部分的值
return kthGrammar(n - 1, k);
}