每日知识积累 Day 15

118 阅读5分钟

每日的知识积累,包括 1 个 Ts 类型体操,两个 Leetcode 算法题,三个前端八股文题,四个英语表达积累。

1. 一个类型体操

类型体操题目集合

Flatten

在这个挑战中,你需要写一个接受数组的类型,并且返回扁平化的数组类型。

例如:

type flatten = Flatten<[1, 2, [3, 4], [[[5]]]]>; // [1, 2, 3, 4, 5]

分析

这个是数组的遍历,基本上和字符串遍历是一样的吧,注意出口值。

尝试写出

type Flatten<T extends unknown[]> = T extends [infer F, ...infer R]
  ? F extends any[]
    ? [...Flatten<F>, ...Flatten<R>]
    : [F, ...Flatten<R>]
  : T;

测试用例

type flatten = Flatten<[1, 2, [3, 4], [[[5]]]]>; // [1, 2, 3, 4, 5]

参考答案

type Flatten<T extends any[]> = T extends [infer L, ...infer R]
  ? [...(L extends any[] ? Flatten<L> : [L]), ...Flatten<R>]
  : [];

经验总结

  1. 参考答案中的:
...(L extends any[] ? Flatten<L> : [L])

写的非常的好。这表明,在 扩展运算符对于三目运算具有分配性。

  1. 由于 T extends unknown[],所以 T extends [infer L, ...infer R] 的出口是 T = [] 的时候,而不是 T["length"] === 1 的时候。
type Flatten<T extends any[]> = T extends [infer L, ...infer R] ? L : T;

type C = Flatten<[1]>; // type C = 1

2. 两个 Leetcode 题目

刷题的顺序参考这篇文章 LeeCode 刷题顺序

2.1 [520] 检测大写字母

我们定义,在以下情况时,单词的大写用法是正确的:

全部字母都是大写,比如 "USA" 。
单词中所有字母都不是大写,比如 "leetcode" 。
如果单词不只含有一个字母,只有首字母大写, 比如 "Google" 。
给你一个字符串 word 。如果大写用法正确,返回 true ;否则,返回 false 。

 

示例 1:

输入:word = "USA"
输出:true
示例 2:

输入:word = "FlaG"
输出:false
 

提示:

1 <= word.length <= 100
word 由小写和大写英文字母组成

尝试实现:

/**
 * @param {string} word
 * @return {boolean}
 */
var detectCapitalUse = function (word) {
  const n = word.length;
  if (n === 1) return true;
  if (n === 2) {
    // aA
    if (word.charCodeAt(0) >= 97 && word.charCodeAt(1) <= 90) {
      return false;
    } else {
      return true;
    }
  }
  const f = word.charCodeAt(0);
  const s = word.charCodeAt(1);
  if (f >= 97 && s <= 90) return false;

  let cls;
  if (f <= 90 && s <= 90) cls = 1;
  if (f <= 90 && s >= 97) cls = 2;
  if (f >= 97 && s >= 97) cls = 3;

  for (let i = 2; i < n; i++) {
    const cur = word.charCodeAt(i);
    if (cls === 1 && cur >= 97) return false;
    if (cls === 2 || cls === 3) {
      if (cur <= 90) {
        return false;
      }
    }
  }
  return true;
};

我的思路:

  1. 如果只有一个字符,直接返回 true
  2. 如果有两个字符,除了 aA 这种返回 false 其余返回 true
  3. 三个以上的字符,设置 cls 然后检测前两个字符,AA cls=1 Aa cls=2 aa cls=3
  4. 从第三个开始遍历, cls 为 1 的时候,剩下字符中出现一个小写则返回 false;
  5. cls 为 2,3 的时候,剩下字符中出现一个大写则返回 false;
  6. 遍历完成则返回 true

得分结果: 70.73% 46.45%

总结提升:

  1. 当一个字符的 code 大于等于 97 为小写;小于等于 90 为大写。需要牢记! 65-90 97-122

2.2 [125] 验证回文串

如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。

字母和数字都属于字母数字字符。

给你一个字符串 s,如果它是 回文串 ,返回 true ;否则,返回 false 。


示例 1:

输入: s = "A man, a plan, a canal: Panama"
输出:true
解释:"amanaplanacanalpanama" 是回文串。
示例 2:

输入:s = "race a car"
输出:false
解释:"raceacar" 不是回文串。
示例 3:

输入:s = " "
输出:true
解释:在移除非字母数字字符之后,s 是一个空字符串 "" 。
由于空字符串正着反着读都一样,所以是回文串。


提示:

1 <= s.length <= 2 * 105
s 仅由可打印的 ASCII 字符组成

尝试完成:

/**
 * @param {string} s
 * @return {boolean}
 */
var isPalindrome = function (s) {
  let i = 0;
  let j = s.length - 1;

  while (j > i) {
    let p = s.charCodeAt(i);
    if (p >= 48 && p <= 57) {
    } else {
      if (p < 97) {
        p += 32;
      }
      if (p < 97 || p > 122) {
        i += 1;
        continue;
      }
    }

    let q = s.charCodeAt(j);
    if (q >= 48 && q <= 57) {
    } else {
      if (q < 97) {
        q += 32;
      }
      if (q < 97 || q > 122) {
        j -= 1;
        continue;
      }
    }
    if (p !== q) return false;
    i++;
    j--;
  }

  return true;
};

我的思路:

  1. 题目虽然不难,但是想要使用一遍遍历就通过却是也是有点难度的
  2. 采用双指针方法:i j
  3. 由于有非字符以及大小写的问题,所以对于每一个字符增加预先校验的步骤
  4. 使用 while 更加合适
  5. 这里扫盲一个 【字符数字】 的概念

得分结果: 84.85% 99.95%

总结提升:

  1. 当一个字符的 code 大于等于 97 为小写;小于等于 90 为大写。需要牢记!一个字符数字,即 '0' - '9' 的 code 是 48 - 57.
  2. 在 js 中 if(3 < q < 9) 是非法的!不要这样写!

3. 三个前端题目

  1. 实现 Array.prototype.every 基本上和 some 的实现过程相同,不同之处仅仅在于什么时候返回 true 以及什么时候返回 false
function myEvery(test) {
  if (!Array.isArray(this)) throw new Error("must be called by array");
  const _stack = [...this];
  if (_stack.length === 0) return false;
  while (_stack.length) {
    const _value = _stack.pop();
    if (!test(_value, _stack.length - 1, _stack)) return false;
  }
  return true;
}
  1. 实现 Array.prototype.find 和 some 以及 every 没有什么本质上的区别,同样也是经过检测函数之后的返回值有所变化
function myFind(test) {
  if (!Array.isArray(this)) throw new Error("must be called by array");
  const _stack = [...this];
  while (_stack.length) {
    const _value = _stack.pop();
    if (test(_value, _stack.length - 1, _stack)) return _value;
  }
  return undefined;
}
  1. 实现 Array.prototype.findIndex 仅仅和 find 的返回值有所差别
function myFindIndex(test) {
  if (!Array.isArray(this)) throw new Error("must be called by array");
  const _stack = [...this];
  while (_stack.length) {
    const _value = _stack.pop();
    if (test(_value, _stack.length - 1, _stack)) return _stack.length - 1;
  }
  return -1;
}

4.四句英语积累

  1. no wonder -- [no wonder] that you don't naps.
  2. time goes fast -- [time goes fast] when you are a wake.
  3. time is up -- how time files, already [break time is up].
  4. is not so right -- second him here is not so right.