每日知识积累 Day 5

166 阅读6分钟

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

1. 一个类型体操

类型体操题目集合

Exclude

题目

实现内置的Exclude <T, U>类型,但不能直接使用它本身。

从联合类型T中排除U的类型成员,来构造一个新的类型。

type Result = MyExclude<'a' | 'b' | 'c', 'a'> // 'b' | 'c'

分析

联合类型的本质是在同一时间可以同时表示多个类型,对于 Ts 而言,会自动遍历联合类型的每一种可能,然后将各个计算结果再联合起来输出。

尝试写出

type MyExclude<T, K> = T excludes K ? never : T;

测试用例

type Result = MyExclude<'a' | 'b' | 'c', 'a'> // 'b' | 'c'

参考答案

type MyExclude<T, U> = T extends U ? never : T;

经验总结

使用 in 操作符也可以遍历联合类型。

type Up<T> = {
  [K in T]: Uppercase<K>
}[T];

type C = Up<"a" | "b" | "c">

2. 两个 Leetcode 题目

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

2.1 [41] 缺失的第一个正数

给你一个未排序的整数数组 `nums` ,请你找出其中没有出现的最小的正整数。

请你实现时间复杂度为 `O(n)` 并且只使用常数级别额外空间的解决方案。

 

**示例 1:**

输入: nums = [1,2,0]
输出: 3
解释: 范围 [1,2] 中的数字都在数组中。

**示例 2:**

输入: nums = [3,4,-1,1]
输出: 2
解释: 1 在数组中,但 2 没有。

**示例 3:**

输入: nums = [7,8,9,11,12]
输出: 1
解释: 最小的正数 1 没有出现。


**提示:**

-   `1 <= nums.length <= 105`
-   `-231 <= nums[i] <= 231 - 1`

尝试实现:

/**
 * @param {number[]} nums
 * @return {number}
 */
var firstMissingPositive = function (nums) {
  const length = nums.length;

  for (let i = 0; i < length; i++) {
    const num = nums[i];
    if (num >= 1 && num <= length) {

    } else {
      nums[i] = undefined;
    }
  }

  for (let i = 0; i < length; i++) {
    const num = nums[i];
    if (num) {
      const _i = Math.abs(num) - 1;
      const _num = nums[_i];
      if (typeof _num === 'undefined') nums[_i] = null;
      if (_num > 0) nums[_i] = -_num;
    }
  }

  for (let i = 0; i < length; i++) {
    const num = nums[i];
    if (num > 0 || num === undefined) {
      return i + 1;
    }
  }

  return length + 1;
};

我的思路:

  1. 第 1 次遍历:清除数组中的冗余元素;根据题意,冗余元素指的就是那些在 [1,n] 之外的元素,将其替换成 undefined, 其中 n 为输入数组的长度。
  2. 第 2 次遍历:现在只剩下在 [1,n] 之间的元素和 undefined 元素了, 遍历的时候,对每一个元素做如下处理:如果为数字,则取绝对值 - 1,记为 _i, 找到 _i 对应的元素,如果为正数则变成相反数,如果为 undefined 则变成 null
  3. 第 3 次遍历:上次遍历之后,剩下的正数或者 undefined 元素的下标值 + 1 对应不存在的正数,找到最小的这个数即可。

得分结果: 56.74% 60.53%

经验总结: 少些了一个 Math.abs

2.2 [274] H 指数

给你一个整数数组 citations ,其中 citations[i] 表示研究者的第 i 篇论文被引用的次数。计算并返回该研究者的 **h 指数

根据维基百科上 h 指数的定义h 代表“高引用次数” ,一名科研人员的 h 指数 是指他(她)至少发表了 h 篇论文,并且 至少 有 h 篇论文被引用次数大于等于 h 。如果 h 有多种可能的值,h 指数** 是其中最大的那个。

示例 1:

输入: citations = [3,0,6,1,5]
输出: 3 
解释: 给定数组表示研究者总共有 5 篇论文,每篇论文相应的被引用了 3, 0, 6, 1, 5 次。
     由于研究者有 3 篇论文每篇 至少 被引用了 3 次,其余两篇论文每篇被引用 不多于 3 次,所以她的 h 指数是 3。

示例 2:

输入: citations = [1,3,1]
输出: 1

**提示:**

-   `n == citations.length`
-   `1 <= n <= 5000`
-   `0 <= citations[i] <= 1000`

尝试完成:

/**
 * @param {number[]} citations
 * @return {number}
 */
var hIndex = function (citations) {
  citations.sort((a, b) => b - a);
  let H = 0;
  for (let i = 0; i < citations.length; i++) {
    if (citations[i] >= i + 1) {
      H = i + 1;
    } else {
      return H;
    }
  }

  return H;
};

我的思路:

  1. 将输入的数组从大到小进行排列
  2. 排列完毕之后进行遍历,提供几个测试用例,考虑极端情况,满足即可,例如 [0] [3, 3] [1] [2,2,2,2] [3,2,1]
  3. [3,2,1] 为例,我们比较当前元素和其下标值+1的大小,如果前者大于等于后者,则记录下标值+1,以其作为最新 H 指数;
  4. H 指数从最小值 0 开始随着遍历增加,如果上述条件均不满足,则返回当前 H 指数的值。

得分结果: 49.59% 31.29%

经验总结: 自己给自己提供一些极端情况下的测试用例. 特别是边界值,需要额外考虑,这样呢能够在考虑的时候完善逻辑。

3. 三个前端题目

  1. 如何获取安全的 undefined 的值? 在回答这个问题之前,先看一些事实:
  • 如果在浏览器中运行 const undefined = 20; 则浏览器报错:Identifier 'undefined' has already been declared'; 而如果运行的是:const null = 20;浏览器报错为:unexpected token 'null';
  • 也就是说对于浏览器来说 undefined 只是一个普通的 identifier 而不是 token;也就是说** undefined 是标识符而不是保留字**!
  • 这一点在 node 环境中表现的更加的透彻:
let undefined = 20;
console.log(undefined); // 20
  • 所以 undefined作 为标识符其值是有被篡改的风险的。在实际中一般使用 void 0 或者 void(0) 表示 undefined 的含义,因为这个表达式的返回值恒为此。
  1. typeof NaN 的结果是什么? 先说结论,返回值为:'number' 注意这里的字符串和小写。

NaN 有几个特性,一个是不和自身相等;第二个是在 Object.is 中又是相等的;第三个是表示的语义为: not a number

  1. isNaN 和 Number.isNaN 的区别是什么?
  • 两者表示完全不同的语义,是完全不相同的两个方法!
  • isNaN(x) 是在判断 x is not a number 的正确性;
  • 而 Number.isNaN(x) 是在判断 x is NaN 的正确性;
  1. 对于 isNaN(x) 来说,只要 x 不是一个 num 就会返回 true,反之返回 false。(注意这里我用的是num,也就是一种独特的东西,和 number 类型不是一回事)

    那么,isNaN 对于 x 的判定规则是什么呢?其实非常简单,首先 x 如果值为 NaN,则 isNaN 认为 x 不是一个 num;其次,如果 x 不为 NaN,但却是 number 类型,则 isNaN 认为 x 是一个 num;最后,倘若 x 不是 number 类型的,isNaN 会尝试将 x 转成 number 类型(这种转化不同于 Number(x) 的强制类型转化,是内部机制),而转化的结果有三种:①NaN,②报错,③其他;

    如果是第一种则 isNaN 认为 x 不是 num,如果是第三种,isNaN 认为 x 是 num。什么时候会出现情况 ② 呢,如果 x 的类型是 bigint 或者 symbol 就会使 isNaN 报错。

  2. 对于 Number.isNaN(x) 来说,情况就简单的多了,只要 x 不是 NaN 就返回 false,否则返回 true.

这里补充js中的哪些计算会返回 NaN 来:

  • NaN
  • Number.NaN
  • 'abc' - 1
  • 0 / 0
  • Math.aqrt(-1)
  • Number({})
  • Number('abc')

4.四句英语积累

  1. fill in for somebody -- 代理某人工作
    • Susan is on holiday this week, so [I'm filling in for her].
    • The boss asked me to [fill in for him] next week, because he has to go to an important conference.
  2. look into something -- try to find more info about something
    • The customer didn't accept our new offer. [We're not sure why], so the boss has asked me to [look into it].
    • I'm very sorry about the delay. I'll look into it immediately and get back to you within the next 2 hour.