# 4260-实现全组合

# 题目描述

Implement type AllCombinations<S> that return all combinations of strings which use characters from S at most once.

For example:

type AllCombinations_ABC = AllCombinations<'ABC'>;
// should be '' | 'A' | 'B' | 'C' | 'AB' | 'AC' | 'BA' | 'BC' | 'CA' | 'CB' | 'ABC' | 'ACB' | 'BAC' | 'BCA' | 'CAB' | 'CBA'

# 分析

这一题是实现全组合,之前有一题是实现 全排列。巧妙的借助联合的分发特性以很少的代码实现了全排列。

那么全组合呢?说实话,全排列全组合这几道题我在做的时候也头大,思路也很少,因为感觉就是挺难的。

也是重复借助联合的分发特性进行实现。第一步,将字符转成联合类型,可以参考 531-字符转联合

第二步,触发分发特性,选择一个元素,对剩余元素进行递归。这一过程中,由于分发后的 T 仅仅表示当前的元素,所以还需要增加一个参数保留完整的字符。

可以直接看题解。

# 题解

// string 转 联合
// 同时塞进了一个 空字符,这是因为所有组合中包含了全空这个选项,和排列不同
type StringToUnion<T extends string> = T extends `${infer F}${infer R}`
  ? F | StringToUnion<R>
  : '';

type AllCombinations<
  S extends string,
  // 默认值是转换后的元组,之后 S 的值其实并不重要
  U extends string = StringToUnion<S>,
  C extends string = U,
> =
  // 触发分发特性
  U extends any
    ? // 组成新的联合类型,注意 Exclude<C, U>,此时的  U 是当前元素,C 是当前元组所有元素,故 Exclude<C, U> 就是剩余元素
      U | `${U}${AllCombinations<'', Exclude<C, U>>}`
    : never;

细心的同学可能会发现,这里没有处理 never 的场景,这是因为 A | never = never,不像全排列中 [1, ...never] = never 所以不需要处理该情况。

# 知识点

  1. 充分理解分发特性
  2. 全排列
  3. 531-字符转联合
Last Updated: 2023/5/16 06:00:28