本文执行环境typescript,版本4.7.4
不使用typescript的计算能力,通过类型来实现ThreeSum
实现ThreeSum之前我们先降低下难度,实现TwoSum,因为TwoSum可以作为ThreeSum的基础泛型
TwoSum需要准备什么呢?
完成TwoSum后如何实现ThreeSum?
因为元组下标是递增有序数列,我们在每次递归的时候返回一个长度+1的新元组并获取长度,就可以对非负整数依次点名了
如求A - B,我们假设A - B永远是非负整数数,无限递归产生新元祖的过程中,排查掉A和B相等后,必定是先点名到B,然后点名到A,而B 到 A的递归次数就是差值,也就是求得的结果
实现这个差值的计算
type GetLen<A extends number, R extends number[], Z extends number[] = []> = A extends R['length'] ? Z['length'] : GetLen<A, [...R, 0], [...Z, 0]>;
减法如下:
type Subtract<A extends number, B extends number, R extends number[] = []> = A extends B ? 0 : A extends R['length'] ? never : B extends R['length'] ? GetLen<A, R> : Subtract<A, B, [...R, 0]>;
求出每一项的差值后,需要判断元组中是否存在,存在则满足 被减数和减数 都存在元祖,作为复合条件的一组返回
type Includes<A extends number[], T extends number, L extends number[] = []> = A['length'] extends L['length'] ? false : A[L['length']] extends T ? true : Includes<A, T, [...L, 0]>;
根据最开始的思路可以实现:
type TwoSum< T extends number, L extends number[], R extends number[][] = [], N extends number[] = [], Item extends number = L[N['length']], SubItem extends number = Subtract<T, Item>, > = L['length'] extends N['length'] ? R : TwoSum< T, L, Includes<L, SubItem> extends true ? [ ...R, [Item, SubItem] ] : R, [...N, 0] >; type t1 = TwoSum<4, [1, 2, 3]>; // [[1, 3], [2, 2], [3, 1]]
存在缺陷:
出现这两个问题,是因为递归过的被减数仍然保留在元祖中,所以我们需要把递归过的被减数移除掉
优化一下:
type GetNext<T extends number[]> = T extends [number, ...infer U] ? U : []; type TwoSum< T extends number, L extends number[], R extends number[][] = [], Item extends number = L[0], SubItem extends number = Subtract<T, Item>, NextL extends number[] = GetNext<L>, > = L['length'] extends 0 ? R : TwoSum< T, NextL, Includes<NextL, SubItem> extends true ? [ ...R, [Item, SubItem] ] : R >;
type t1 = TwoSum<7, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>; // [[0, 7], [1, 6], [2, 5], [3, 4]] type t2 = TwoSum<12, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>; // [[3, 9], [4, 8], [5, 7]] type t3 = TwoSum<20, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>; // [] type t4 = TwoSum<10, [0, 8, 2, 1, 4, 7, 6, 3, 4, 9]>; // [[8, 2], [1, 9], [4, 6], [7, 3], [6, 4]]
之前已经实现typescript的快排,移步:用typescript类型来实现快排
为什么需要实现排序,因为上文中 TwoSum泛型的实现,需要满足
所以排序后可以直接使用TwoSum泛型
// 合并参数到TwoSum的结果,因为TwoSum返回的二元数组 type GetNewList< A extends number, T extends number[][], N extends number[] = [], R extends number[][] = [] > = T['length'] extends N['length'] ? R : GetNewList<A, T, [...N, 0], [...R, [A, ...T[N['length']]]]>; type IsArray<T> = T extends number[] ? T : []; type IsArray2<T> = T extends number[][] ? T : []; type ThreeSumLoop< L extends number[], R extends number[][] = [], NextL extends number[] = GetNext<L>, NewList extends number[][] = IsArray2<TwoSum<L[0], NextL>> > = L['length'] extends 0 | 1 ? R : ThreeSumLoop<NextL, NewList['length'] extends 0 ? R : IsArray2<[...R, ...GetNewList<L[0], NewList>]>>; type ThreeSum<L extends number[]> = ThreeSumLoop<IsArray<QuickSort<L>>>;
type l1 = ThreeSum<[1, 3, 2, 4]>; // [[4, 3, 1], [3, 2, 1]] type l2 = ThreeSum<[1, 6, 3, 7, 5, 4, 2]>; // [[7, 6, 1], [7, 5, 2], [7, 4, 3], [6, 5, 1], [6, 4, 2], [5, 4, 1], [5, 3, 2], [4, 3, 1], [3, 2, 1]] type l3 = ThreeSum<[0, 5, 15, 10, 5, 25, 20]>; // [[25, 20, 5], [25, 15, 10], [20, 15, 5], [15, 10, 5], [10, 5, 5], [5, 5, 0]] type l4 = ThreeSum<[1, 16, 3, 17, 5, 4, 21]>; // [[21, 17, 4], [21, 16, 5], [17, 16, 1], [5, 4, 1], [4, 3, 1]]
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
长按识别二维码并关注微信
更方便到期提醒、手机管理