每日知识积累 Day 23

139 阅读7分钟

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

1. 一个类型体操

类型体操题目集合 Pop

实现一个通用 Pop<T>,它接受一个数组 T ,并返回一个由数组 T 的前 length-1 项以相同的顺序组成的数组。

例如:

type arr1 = ["a", "b", "c", "d"];
type arr2 = [3, 2, 1];

type re1 = Pop<arr1>; // expected to be ['a', 'b', 'c']
type re2 = Pop<arr2>; // expected to be [3, 2]

分析

这没什么好说的。

尝试写出

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

测试用例

type re1 = Pop<arr1>; // ['a', 'b', 'c']
type re2 = Pop<arr2>; // [3, 2]

参考答案

type Pop<T extends any[]> = T extends [...infer R, infer E] ? [...R] : never;

经验总结

  1. 这里的 [...R] 有什么特殊的含义么?

另外一个类型体操

类型体操题目集合

Last of Array

实现一个通用 Last,它接受一个数组 T 并返回其最后一个元素的类型。

例如:

type arr1 = ["a", "b", "c"];
type arr2 = [3, 2, 1];

type tail1 = Last<arr1>; // expected to be 'c'
type tail2 = Last<arr2>; // expected to be 1

分析

这没什么好说的。

尝试写出

type Last<T extends any[]> = T extends [...infer R, infer L] ? L : never;

测试用例

type arr1 = ["a", "b", "c"];
type arr2 = [3, 2, 1];

type tail1 = Last<arr1>; // 'c'
type tail2 = Last<arr2>; // 1

参考答案

type Last<T extends any[]> = T extends [infer L, ...infer R]
  ? R["length"] extends 0
    ? L
    : Last<R>
  : never;

经验总结

  1. 是答案搞复杂了么?

2. 两个 Leetcode 题目

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

2.1 [13] 罗马数字转整数

罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。

字符          数值
I             1
V             5
X             10
L             50
C             100
D             500
M             1000
例如, 罗马数字 2 写做 II ,即为两个并列的 1 。12 写做 XII ,即为 X + II 。 27 写做  XXVII, 即为 XX + V + II 。

通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:

I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数。



示例 1:

输入: s = "III"
输出: 3
示例 2:

输入: s = "IV"
输出: 4
示例 3:

输入: s = "IX"
输出: 9
示例 4:

输入: s = "LVIII"
输出: 58
解释: L = 50, V= 5, III = 3.
示例 5:

输入: s = "MCMXCIV"
输出: 1994
解释: M = 1000, CM = 900, XC = 90, IV = 4.


提示:

1 <= s.length <= 15
s 仅含字符 ('I', 'V', 'X', 'L', 'C', 'D', 'M')
题目数据保证 s 是一个有效的罗马数字,且表示整数在范围 [1, 3999] 内
题目所给测试用例皆符合罗马数字书写规则,不会出现跨位等情况。
IL 和 IM 这样的例子并不符合题目要求,49 应该写作 XLIX,999 应该写作 CMXCIX 。
关于罗马数字的详尽书写规则,可以参考 罗马数字 - 百度百科。

尝试实现:

/**
 * @param {string} s
 * @return {number}
 */
var romanToInt = function (s) {
  let sum = 0;
  const rec = {
    I: 1,
    IV: 4,
    V: 5,
    IX: 9,
    X: 10,
    XL: 40,
    L: 50,
    XC: 90,
    C: 100,
    CD: 400,
    D: 500,
    CM: 900,
    M: 1000,
  };
  while (s.length) {
    if (s.startsWith("CM")) {
      sum += 900;
      s = s.slice(2);
      continue;
    }
    if (s.startsWith("CD")) {
      sum += 400;
      s = s.slice(2);
      continue;
    }
    if (s.startsWith("XC")) {
      sum += 90;
      s = s.slice(2);
      continue;
    }
    if (s.startsWith("XL")) {
      sum += 40;
      s = s.slice(2);
      continue;
    }
    if (s.startsWith("IX")) {
      sum += 9;
      s = s.slice(2);
      continue;
    }
    if (s.startsWith("IV")) {
      sum += 4;
      s = s.slice(2);
      continue;
    }

    sum += rec[s[0]];
    s = s.slice(1);
  }

  return sum;
};

我的思路: 不了解罗马数字可能会被吓唬住,但是其实罗马数字就是表意的,从头遍历一遍即可得到答案。

得分结果: 8.92% 13.90%

2.2 [12] 整数转罗马数字

七个不同的符号代表罗马数字,其值如下:

符号	值
I	1
V	5
X	10
L	50
C	100
D	500
M	1000
罗马数字是通过添加从最高到最低的小数位值的转换而形成的。将小数位值转换为罗马数字有以下规则:

如果该值不是以 4 或 9 开头,请选择可以从输入中减去的最大值的符号,将该符号附加到结果,减去其值,然后将其余部分转换为罗马数字。
如果该值以 4 或 9 开头,使用 减法形式,表示从以下符号中减去一个符号,例如 4 是 5 (V) 减 1 (I): IV ,9 是 10 (X) 减 1 (I):IX。仅使用以下减法形式:4 (IV),9 (IX),40 (XL),90 (XC),400 (CD) 和 900 (CM)。
只有 10 的次方(I, X, C, M)最多可以连续附加 3 次以代表 10 的倍数。你不能多次附加 5 (V),50 (L) 或 500 (D)。如果需要将符号附加4次,请使用 减法形式。
给定一个整数,将其转换为罗马数字。



示例 1:

输入:num = 3749

输出: "MMMDCCXLIX"

解释:

3000 = MMM 由于 1000 (M) + 1000 (M) + 1000 (M)
 700 = DCC 由于 500 (D) + 100 (C) + 100 (C)
  40 = XL 由于 50 (L) 减 10 (X)
   9 = IX 由于 10 (X) 减 1 (I)
注意:49 不是 50 (L) 减 1 (I) 因为转换是基于小数位
示例 2:

输入:num = 58

输出:"LVIII"

解释:

50 = L
 8 = VIII
示例 3:

输入:num = 1994

输出:"MCMXCIV"

解释:

1000 = M
 900 = CM
  90 = XC
   4 = IV

提示:

1 <= num <= 3999

尝试完成:

/**
 * @param {number} num
 * @return {string}
 */
var intToRoman = function (num) {
  const arr = (num + "").split("");
  const n = arr.length;
  const g = arr[n - 1];
  const s = arr[n - 2] ?? "0";
  const b = arr[n - 3] ?? "0";
  const q = arr[n - 4] ?? "0";

  let rst = "";
  const qq = {
    0: "",
    1: "M",
    2: "MM",
    3: "MMM",
  };
  if (q) {
    let _q = qq[q];

    rst += _q;
  }
  const bb = {
    0: "",
    1: "C",
    2: "CC",
    3: "CCC",
    4: "CD",
    5: "D",
    6: "DC",
    7: "DCC",
    8: "DCCC",
    9: "CM",
  };

  if (b) {
    let _b = bb[b];

    rst += _b;
  }

  const ss = {
    0: "",
    1: "X",
    2: "XX",
    3: "XXX",
    4: "XL",
    5: "L",
    6: "LX",
    7: "LXX",
    8: "LXXX",
    9: "XC",
  };
  if (s) {
    let _s = ss[s];

    rst += _s;
  }

  const gg = {
    0: "",
    1: "I",
    2: "II",
    3: "III",
    4: "IV",
    5: "V",
    6: "VI",
    7: "VII",
    8: "VIII",
    9: "IX",
  };
  if (g) {
    let _g = gg[g];

    rst += _g;
  }

  return rst;
};

我的思路:

  1. 和上面那个题差不多,只要罗马数字是从左到右读的,那就和阿拉伯数字差不多;
  2. 考虑到最大值为 4000,我们可以先得到各个位上的数字并且不用考虑 0,因为题目给了数字的范围。

得分结果: 97.41% 25.03%

3. 六个 vue2.x 面试题

  1. Vue2.x 生命周期有哪些? 系统自带:
  • beforeCreate
  • created
  • beforeMount
  • mounted
  • beforeUpdate
  • updated
  • beforeDestroy
  • destroyed
  1. Vue2.x 一旦进入到页面或者组件,会执行哪些生命周期,它们的顺序又是什么?
  • beforeCreate
  • created
  • beforeMount
  • mounted
  1. Vue2.x 在哪个阶段有el,在哪个阶段有el,在哪个阶段有data?
  • beforeCreate 啥也没有
  • created 有 data 没有 el
  • beforeMount 有 data 没有 el
  • mounted 都有
  1. Vue2.x 如果加入了 keep-alive 会多俩个生命周期?
  • activated
  • deactivated
  1. Vue2.x 如果加入了 keep-alive,第一次进入组件会执行哪些生命?
  • beforeCreate
  • created
  • beforeMount
  • mounted
  • activated
  1. 如果加入了 keep-alive,第二次或者第 N 次进入组件会执行哪些生命周期? 只执行一个生命周期:activated

4.四句英语积累

  • Health or sanitary means '卫生' in Chinese。
  • If we [get a chance] [maybe someday] we can [hangout together].
  • [seems] you [have been to] [all places in Hangzhou].
  • yeah [I went once there] [when there was a holiday].