# 4518-fill

# 题目描述

Fill, a common JavaScript function, now let us implement it with types. Fill<T, N, Start?, End?>, as you can see,Fill accepts four types of parameters, of which T and N are required parameters, and Start and End are optional parameters. The requirements for these parameters are: T must be a tuple, N can be any type of value, Start and End must be integers greater than or equal to 0.

type exp = Fill<[1, 2, 3], 0>; // expected to be [0, 0, 0]

In order to simulate the real function, the test may contain some boundary conditions, I hope you can enjoy it 😃

# 分析

这题题目太长可以不看,可以再多看几道用例即可明白题目的意思:

Expect<Equal<Fill<[], 0>, []>>,
  Expect<Equal<Fill<[], 0, 0, 3>, []>>,
  Expect<Equal<Fill<[1, 2, 3], 0, 0, 0>, [1, 2, 3]>>,
  Expect<Equal<Fill<[1, 2, 3], 0, 2, 2>, [1, 2, 3]>>,
  Expect<Equal<Fill<[1, 2, 3], 0>, [0, 0, 0]>>,
  Expect<Equal<Fill<[1, 2, 3], true>, [true, true, true]>>,
  Expect<Equal<Fill<[1, 2, 3], true, 0, 1>, [true, 2, 3]>>,
  Expect<Equal<Fill<[1, 2, 3], true, 1, 3>, [1, true, true]>>,
  Expect<Equal<Fill<[1, 2, 3], true, 10, 0>, [1, 2, 3]>>,
  Expect<Equal<Fill<[1, 2, 3], true, 10, 20>, [1, 2, 3]>>,
  Expect<Equal<Fill<[1, 2, 3], true, 0, 10>, [true, true, true]>>;

一共四个入参,第一个为元组 T,第二个为要替换成的类型,第三四为开始和结束的位置,默认是整个长度。

这个题目其实还是比较有趣,其实本质就是遍历元组,判断当前元素的位置是否位于目标区间内(左开右闭),如果位于,则替换元素,否则保留原本的元素。

用 js 实现的话,可谓是非常简单,但是 ts 没有比较的方法,虽然可以通过 4425-实现比较 来完成比较,但是比较本身借助了递归,性能相对差点但是也没太大问题。感兴趣的同学可以尝试,题目用例也不长,递归没有问题。

所以需要换一种思路,增加一个元组进行计数,并增加一个标志位,默认是 false,如果元组长度达到了起始值,就把标记位设为 true,如果达到了结束值,就把标记为设为 false。这样就可以比较简单的解决该问题了。

# 题解

type Fill<
  T extends unknown[],
  N,
  Start extends number = 0,
  End extends number = T['length'],
  // 计数
  Arr extends number[] = [],
  // 标记位
  replace extends boolean = false,
> = Start extends End
  ? T
  : // 遍历
  T extends [infer F, ...infer R]
  ? // 如果当前到了起始值
    Arr['length'] extends Start
    ? // 替换当前元素,并将标志位置为 true,递归剩余元素
      [N, ...Fill<R, N, Start, End, [...Arr, 1], true>]
    : // 如果到了结束值
    Arr['length'] extends End
    ? // 保留当前元素(右闭),并将标志位置为 false,递归剩余元素
      [F, ...Fill<R, N, Start, End, [...Arr, 1], false>]
    : // 不是起始位也不是结束位,根据 标记位决定是否对当前元素替换,并保留当前标记位递归剩余元素
      [
        replace extends true ? N : F,
        ...Fill<R, N, Start, End, [...Arr, 1], replace>,
      ]
  : [];

上述解法中,当起始位和结束位相同时也顺带进行了处理,思路还是非常清晰的。

# 知识点

  1. 元组遍历老套路
  2. 元组计数
Last Updated: 2023/5/16 06:00:28