每日知识积累 Day 1

282 阅读8分钟

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

1. 一个类型体操

Tuple To Union

实现泛型 TupleToUnion<T>,它返回元组所有值的合集。

例如:

type Arr = ["1", "2", "3"];

type Test = TupleToUnion<Arr>; // expected to be '1' | '2' | '3'

分析

显然这是一个降维的过程,一个 1 维数组降级为 0 维,通常我们使用递归的方式实现,假想的过程如下:

数组长度大于 0 ? ['1', '2', '3']
数组长度大于 0 ? ['1', '2'] | '3'
数组长度大于 0 ? ['1'] | '2' | '3'
数组长度等于 0 ? [] | '1' | '2' | '3'
'1' | '2' | '3'

尝试写出

type TupleToUnion<T extends string[], K = never> = {
  0: K;
  1: T extends [...infer Rest, infer Last]
    ? Rest extends string[]
      ? TupleToUnion<Rest, K | Last>
      : never
    : never;
}[T["length"] extends 0 ? 0 : 1];

简化写法

type TupleToUnion<T extends string[], K = never> = T["length"] extends 0
  ? K
  : T extends [...infer Rest, infer Last]
  ? Rest extends string[]
    ? TupleToUnion<Rest, K | Last>
    : never
  : never;

测试用例

type C = TupleToUnion<["1", "2", "3"]>; // "1" | "2" | "3"

参考答案

type TupleToUnion<T extends unknown[]> = T[number];
type C = TupleToUnion<["1", "2", "3"]>; // "1" | "2" | "3"

经验总结

  1. never 在类型联合的时候是透明的。
  2. T[number] 自带降维的作用,union 过程是自动进行的。

2. 两个 Leetcode 题目

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

2.1 最大连续 1 的个数

给定一个二进制数组 nums , 计算其中最大连续 1 的个数。

示例 1:

输入:nums = [1,1,0,1,1,1]
输出:3
解释:开头的两位和最后的三位都是连续 1 ,所以最大连续 1 的个数是 3.
示例 2:

输入:nums = [1,0,1,1,0,1]
输出:2

提示:

1 <= nums.length <= 105
nums[i] 不是 0 就是 1.

尝试实现:

var findMaxConsecutiveOnes = function (nums) {
  var max = 0;
  var curretMax = 0;
  var len = nums.length;
  for (var i = 0; i < len; i++) {
    if (nums[i]) {
      curretMax++;
    } else {
      max = curretMax > max ? curretMax : max;
      curretMax = 0;
    }
  }
  return curretMax > max ? curretMax : max;
};

我的思路:

  1. 初始化两个变量 maxcurretMax 为 0。max 用于存储迄今为止找到的最长连续 1 的数量,而 curretMax 用于记录当前连续 1 的数量。

  2. 通过一个 for 循环遍历整个数组 nums

  3. 在循环内部:

    • 如果当前元素 nums[i] 等于 1,则 curretMax 加 1。
    • 如果当前元素不等于 1(即数组中的 0),则执行以下操作:
      • 更新 maxcurretMaxmax 中的较大值。
      • 重置 curretMax 为 0,因为连续序列被打断。
  4. 在循环结束后,再次检查并更新 max,以确保覆盖最后一次连续 1 的计数(如果数组以 1 结尾)。

  5. 函数返回 max,即数组中连续 1 的最大数量。

后记:代码中 curretMax 存在拼写错误,应该是 currentMax

2.2 提莫攻击

在《英雄联盟》的世界中,有一个叫 “提莫” 的英雄。他的攻击可以让敌方英雄艾希(编者注:寒冰射手)进入中毒状态。

当提莫攻击艾希,艾希的中毒状态正好持续 duration 秒。

正式地讲,提莫在 t 发起攻击意味着艾希在时间区间 [t, t + duration - 1](含 t 和 t + duration - 1)处于中毒状态。如果提莫在中毒影响结束 前 再次攻击,中毒状态计时器将会 重置 ,在新的攻击之后,中毒影响将会在 duration 秒后结束。

给你一个 非递减 的整数数组 timeSeries ,其中 timeSeries[i] 表示提莫在 timeSeries[i] 秒时对艾希发起攻击,以及一个表示中毒持续时间的整数 duration 。

返回艾希处于中毒状态的 总 秒数。


示例 1:

输入:timeSeries = [1,4], duration = 2

输出:4

解释:提莫攻击对艾希的影响如下:
- 第 1 秒,提莫攻击艾希并使其立即中毒。中毒状态会维持 2 秒,即第 1 秒和第 2 秒。
- 第 4 秒,提莫再次攻击艾希,艾希中毒状态又持续 2 秒,即第 4 秒和第 5 秒。
艾希在第 1、2、4、5 秒处于中毒状态,所以总中毒秒数是 4 。

示例 2:

输入:timeSeries = [1,2], duration = 2

输出:3

解释:提莫攻击对艾希的影响如下:
- 第 1 秒,提莫攻击艾希并使其立即中毒。中毒状态会维持 2 秒,即第 1 秒和第 2 秒。
- 第 2 秒,提莫再次攻击艾希,并重置中毒计时器,艾希中毒状态需要持续 2 秒,即第 2 秒和第 3 秒。
艾希在第 1、2、3 秒处于中毒状态,所以总中毒秒数是 3 。


提示:

1 <= timeSeries.length <= 104

0 <= timeSeries[i], duration <= 107

timeSeries 按 非递减 顺序排列

尝试完成:

/**
 * @param {number[]} timeSeries
 * @param {number} duration
 * @return {number}
 */
var findPoisonedDuration = function (timeSeries, duration) {
  var len = timeSeries.length;
  var acc = 0;

  function min(a, b) {
    return a > b ? b : a;
  }

  for (var i = 0; i < len; i++) {
    if (i === len - 1) {
      acc += duration;
    } else {
      acc += min(duration, timeSeries[i + 1] - timeSeries[i]);
    }
  }
  return acc;
};

console.log(findPoisonedDuration([1, 2, 2, 3, 7], 3)); // 8

我的思路:

  1. 初始化:定义一个变量 len 存储 timeSeries 数组的长度,以及一个变量 acc 用于累计计算毒药作用的总时长,初始值为 0。

  2. 辅助函数:定义一个内部函数 min(a, b),用于返回两个数 ab 中的较小值。

  3. 遍历数组:使用一个 for 循环遍历 timeSeries 数组。

  4. 处理当前时间点

    • 如果当前索引 i 等于数组长度减去 1(即数组的最后一个元素),则直接将 duration 加到 acc 上。这是因为在数组的最后一个时间点,毒药可以持续作用到 duration 结束,没有后续时间点限制毒药的作用时间。
    • 如果当前索引 i 不是最后一个元素,计算当前时间点之后毒药的持续时间。使用 min 函数获取 durationtimeSeries[i + 1] - timeSeries[i](即当前时间点与下一个时间点之间的时间差)中的较小值,并将结果加到 acc 上。这样做是为了确保毒药作用时间不会超过到下一个时间点的时间。
  5. 返回结果:循环结束后,返回 acc,即毒药作用的总时长。

这个函数的核心在于计算每个时间点上毒药的作用时间,并累加这些时间以得到总时长。对于数组中的最后一个时间点,毒药可以完整地作用 duration 时长,因为后面没有时间点限制它。对于其他时间点,毒药的作用时间可能受到下一个时间点的限制,因此需要取 duration 和两个时间点间隔中的较小值。

3. 三个前端题目

  1. js 中的数据类型检测方法都有哪些? 首先,用于检测 js 中数据类型的方法一般来说有四种,分别为:
    • tyepof x
    • x instanceof y
    • x.constructor?.name
    • Object.prototype.toString.call(x).slice(8, -1);

前两个是操作符,中间的是属性,而最后一个是方法。

  1. 先说 typeof: typeof x 的返回值可能为:'object' 'undefined' 'number' 'string' 'symbol' 'bigint' 'boolean' 'function'。注意它们都是首字母小写的字符串。
  • 使用 typeof x 判断类型有两个问题,问题一在于:对 null 的判断结果是 'object',这个是不正确的;第二个问题是:只能判断出对象的类型为 'object',无法进一步得到更加具体的结论。
  • typeof x 有一个优点那就是在判断基本类型的时候非常的方便(除了 null),并且在判断 'function' 类型的时候也非常方便(唯一一个给出具体类型的 object)。
  • 对于 typeof x 判断方法的缺点的处理方法就是采用更加合适的其它判别方法。
  1. x instanceof y 判别方法的问题在于只对 object 类型生效,只能判断表达式是否成立,而不能直接告诉调用者到底是谁。其原理是通过原型链查找,所以 y 只要在 x 的原型链上都会返回 true,总之这种判别法只能用来排除,因为给出的结论都是模糊性的。
  2. ?.constructor?.name 这种方法对于对象类型和包装类型都生效,返回的是首字母大写的字符串。缺点在于无法分辨 null 和 undefined,并且 constructor 属性值可以被篡改。不考虑其缺点的时候比 typeof 好用一些。
  3. 最后的 Object.prototype.toString.call(x).slice(8, -1) 方法是王炸,是唯一一种能够判断出 null 数据类型的方法。返回值为首字母大写的字符串,列举其可能的返回值:'String' 'Null' 'Undefined' 'Number' 'String' 'Symbol' 'Bigint' 'Boolean' 'Array' 'Date' 'RegExp' 'Error' 'Function'。可惜这个方法还是有缺点的const a = {}; a 可以通过修改[Symbol.toStringTag]的值改变此方法的返回值。

总结下来,这四个方法各有各的用武之地,但是如果想要清晰的知道 x 的类型的话,推荐使用最后一种方式。

  1. 判断 x 为数组的方法都有哪些? 总结下来就是:toString 方法,ES6 方法和原型相关的方法。
    1. Object.prototype.toString.call(x).slice(8, -1) === "Array";
    1. Array.isArray(x);
    1. x instanceof Array;
    1. x.__proto__ == Array.prototype;
    1. x.constructor.name === "Array";
    1. Array.prototype.isPrototypeof(x);
  1. null 和 undefined 的区别是什么?
    1. 语义上:null 表示有值,但是值为空,而 undefined 则表示没有值。
    1. 语法上:形参或者变量的值为 null 的时候并不会触发默认值,但是如果值为 undefined 会强制触发默认值。
    1. typeof检测的时候,一个结果是正确的,另外一个结果不正确。
    1. 两者虽然都是基本类型,但是 undefined 不是保留字,这意味着你可以为其赋值,或者声明其为变量,这是不安全的,所以一般使用 void 0 作为 undefined 的替代。

4.四句英语积累

  • brainstorm
  1. Let's brainstorm some ideas for the new campaign [kæmˈpeɪn]. campaign 在这里做【活动】来讲。
  2. We need to start brainstorming solutions to the problem right now!
  • review
  1. I think we need more time to review the situation.
  2. Robert, have you already reviewed the new IT security guidelines? 【IT 安全指导方针】