每日知识积累 Day 3

148 阅读6分钟

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

1. 一个类型体操

类型体操题目集合

If

题目

实现一个 IF 类型,它接收一个条件类型 C ,一个判断为真时的返回类型 T ,以及一个判断为假时的返回类型 F。 C 只能是 true 或者 false, T 和 F 可以是任意类型。

例如:

type A = If<true, "a", "b">; // expected to be 'a'
type B = If<false, "a", "b">; // expected to be 'b'

分析

接受三个泛型,根据第一个泛型是否为 true 决定返回后面两个中的一个。使用 extends 即可,在 Ts 中三目运算和相等都使用 extends.

尝试写出

type If<Condition, Candidate1, Candidate2> = Condition extends true
  ? Candidate1
  : Candidate2;

测试用例

type C = If<true, "a", "b">; // "a"
type D = If<false, "a", "b">; // "b"

参考答案

type If<C extends boolean, T, F> = C extends true ? T : F;

经验总结

在 Ts 中三目运算和相等都使用 extends.

2. 两个 Leetcode 题目

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

2.1 [645] 错误的集合

集合 s 包含从 1 到 n 的整数。不幸的是,因为数据错误,导致集合里面某一个数字复制了成了集合里面的另外一个数字的值,导致集合 丢失了一个数字 并且 有一个数字重复 。

给定一个数组 nums 代表了集合 S 发生错误后的结果。

请你找出重复出现的整数,再找到丢失的整数,将它们以数组的形式返回。


示例 1:

输入:nums = [1,2,2,4]
输出:[2,3]
示例 2:

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


提示:

2 <= nums.length <= 104
1 <= nums[i] <= 104

尝试实现:

/**
 * @param {number[]} nums
 * @return {number[]}
 */
var findErrorNums = function (nums) {
  nums.sort((a, b) => a - b);
  var length = nums.length;
  var wrongnum;
  var total = nums[0];
  for (var i = 1; i < length; i++) {
    if (nums[i] === nums[i - 1]) {
      wrongnum = nums[i];
    }
    total += nums[i];
  }
  return [wrongnum, wrongnum - (total - ((1 + length) * length) / 2)];
};

我的思路:

  1. 先排序,找到那个重复的数字
  2. 然后求和,计算出多了多少或者少了多少
  3. 根据重复的数字和差值找到正确的数字

得分结果: 42.74% 67.74%

经验总结: 题目一定要好好审,不然会事倍功半。

2.2 [697] 数组的度

给定一个非空且只包含非负数的整数数组 nums,数组的 度 的定义是指数组里任一元素出现频数的最大值。

你的任务是在 nums 中找到与 nums 拥有相同大小的度的最短连续子数组,返回其长度。

示例 1:

输入:nums = [1,2,2,3,1] 输出:2 解释: 输入数组的度是 2 ,因为元素 1 和 2 的出现频数最大,均为 2 。 连续子数组里面拥有相同度的有如下所示: [1, 2, 2, 3, 1], [1, 2, 2, 3], [2, 2, 3, 1], [1, 2, 2], [2, 2, 3], [2, 2] 最短连续子数组 [2, 2] 的长度为 2 ,所以返回 2 。 示例 2:

输入:nums = [1,2,2,3,1,4,2] 输出:6 解释: 数组的度是 3 ,因为元素 2 重复出现 3 次。 所以 [2,2,3,1,4,2] 是最短子数组,因此返回 6 。

提示:

nums.length 在 1 到 50,000 范围内。 nums[i] 是一个在 0 到 49,999 范围内的整数。

尝试完成:

/**
 * @param {number[]} nums
 * @return {number}
 */
var findShortestSubArray = function (nums) {};

我的思路:

  1. 遍历一次数组,使用一个对象 info 统计如下信息,每一个元素的频数以及最开始出现的位置和最后一次出现的位置
  2. 使用一个数组 maxNums 记录频数最大的元素们(可能有同时为最大频数的元素),使用 maxCount 记录但付钱的最大频数,并保持更新

得分结果: 37.50% 15.39%

经验总结: 在初始化的时候,应该是:

if (!info[_num]) {
  info[_num] = {
    count: 1,
    start: i,
    end: i,
  };
}

而不是:

if (!info[_num]) {
  info[_num] = {
    count: 1,
    start: i,
    end: null,
  };
}

空间得分比较低的原因可能是保存多余的数据。

3. 三个前端题目

  1. 为什么在 js 中 0.1+0.2!==0.3?如何使其相等?
  • js 中存储数据遵循 IEEE754 双精度浮点数标准。这个规定要求使用 64bit 存储一个双精度的浮点数,其中 1bit 表示符号位,11bit 表示指数位,剩下的 52 位表示尾数,也就是说 js 中对于一个浮点数的存储是有限位的;
  • 0.1 虽然在十进制中很好表示,但是在二进制中却是一个无限循环小数,因为不论 2 的几次方都不可能凑到 10;所以使用0.1.toString(2)可以清楚的看到这个截断了的无限循环小数;同理 0.2 也是这样;
  • 所以两个无限小数相加并且被截断之后,其结果必然产生截断误差,所以 0.1+0.2 才不等于 0.3;
  • 为了避免这种情况,应该手动设置一个最小误差,比如 1e-9:
function add(a, b) {
  return parseFloat((a + b).toFixed(9));
}
// 验证
console.log(add(0.1, 0.2) === 0.3);
  1. 手写一个函数,实现 Object.create 方法。

Object.create 方法的作用为:

Object.create() 方法是 JavaScript 中用于创建一个新对象的方法。它的作用是以指定的原型对象作为新对象的原型,并可选择性地为新对象定义属性和方法。 Object.create(proto, [propertiesObject]) 接受两个参数:

  1. proto:必需,表示新对象的原型。它可以是一个对象字面量、null 或者其他已存在的对象。新对象将继承 proto 对象的属性和方法。
  2. propertiesObject(可选):一个可选的对象,用于定义新对象的属性和方法。该对象的每个属性都是通过属性描述符来定义的,类似于 Object.defineProperty()的第二个参数。

借用原型设计模式实现 Object.create:

function myCreate(proto, propertiesObject) {
  if (Object(proto) !== proto && proto !== null) {
    throw new TypeError("Object prototype may only be an Object or null");
  }
  // 创建一个空函数
  function F() {}
  // 指定此函数的原型
  F.prototype = proto;
  // 创建待返回实例
  const obj = new F();
  // 往实例对象上添加属性
  if (propertiesObject !== undefined) {
    Object.defineProperties(obj, propertiesObject);
  }
  // 返回实例对象
  return obj;
}
  1. 手写一个函数,实现 instanceof 操作符。
  • x instanceof y 的作用原理就是,在 x 的原型链上寻找 y,如果找到了就返回 true,如果找不到就返回 false;
  • 根据其作用原理,其实现过程也就呼之欲出了:首先判断 x 是不是 object 类型的,如果不是直接返回 false 就可以了。如果是的话,则逐级比较 x 的原型和 y 是否相等,知道 x 原型链的尽头,也就是 null。如果此时 y 与任何一层原型都不相等,则返回 false,否则返回 true。
  • 实现代码如下:
function myInstanceof(obj, cons) {
  if (Object(obj) !== obj) return false;
  let _p = obj.__proto__;
  while (_p !== null) {
    if (_p == cons.prototype) return true;
    _p = _p.__proto__;
  }
  return false;
}

4.四句英语积累

  1. analyse -- examine or study in details
    • We [analysed the results] of the survey and found that most of our customers are satisfied with our products.
    • The new software will help us to [analyse market data].
  2. approach -- to deal with
    • We need to find a different way of [approaching this problem].
    • Jack, do you have a suggestion on how we can [approach this situation]?