每日一道算法Day17

112 阅读1分钟

题目描述:

截屏2021-08-12 下午11.26.14.png

第一时间想到的两种暴力解法:

  1. 递归出所有结果, 组合成二维数组, 最后返回对应值:
  // 暴力 递归 超时...
   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;
  1. 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;
  1. 找规律: 第一行: 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);
}