├── .github └── workflows │ └── nodejs.yml ├── .gitignore ├── .gitpod.yml ├── .vscode ├── launch.json └── settings.json ├── LICENSE ├── README.md ├── images ├── array │ ├── 4sum-ii.jpeg │ ├── contains-duplicate-iii.jpeg │ ├── count-good-triplets.jpeg │ ├── defuse-the-bomb.jpeg │ ├── distance-between-bus-stops.jpeg │ ├── fruit-into-baskets.jpeg │ ├── house-robber.jpeg │ ├── maximum-length-of-pair-chain.jpeg │ ├── minimum-cost-to-hire-k-workers.jpeg │ ├── number-of-boomerangs.jpeg │ ├── shortest-word-distance.jpeg │ ├── special-positions-in-a-binary-matrix.jpeg │ └── spiral-matrix.jpeg ├── graphs │ ├── find-the-town-judge.jpeg │ ├── minimize-the-total-price-of-the-trips.jpeg │ └── possible-bipartition.jpeg ├── list │ ├── delete-node-in-a-linked-list.jpeg │ └── reverse-linked-list.jpeg ├── map │ ├── check-if-one-string-swap-can-make-strings-equal.jpeg │ ├── largest-substring-between-two-equal-characters.jpeg │ └── remove-letter-to-equalize-frequency.jpeg ├── math │ ├── max-points-on-a-line.jpeg │ └── ugly-number.jpeg ├── search │ └── array-nesting.jpeg ├── sort │ └── minimum-absolute-difference.jpeg ├── stack │ ├── build-an-array-with-stack-operations.jpeg │ ├── dinner-plate-stacks.jpeg │ └── simplify-path.jpeg ├── string │ ├── check-if-binary-string-has-at-most-one-segment-of-ones.jpeg │ ├── generate-a-string-with-characters-that-have-odd-counts.jpeg │ └── string-matching-in-an-array.jpeg └── tree │ ├── my-calendar-i.jpeg │ ├── same-tree.jpeg │ └── trim-a-binary-search-tree.jpeg ├── package.json ├── src ├── array │ ├── 01-matrix.ts │ ├── 4sum-ii.ts │ ├── best-time-to-buy-and-sell-stock-ii.ts │ ├── binary-search.ts │ ├── bubble-sort.ts │ ├── can-place-flowers.ts │ ├── circular-array-loop.ts │ ├── container-with-most-water.ts │ ├── contains-duplicate-iii.ts │ ├── count-good-triplets.ts │ ├── count-number-of-nice-subarrays.ts │ ├── count-the-repetitions.ts │ ├── daily-temperatures.ts │ ├── defuse-the-bomb.ts │ ├── distance-between-bus-stops.ts │ ├── find-common-characters.ts │ ├── find-in-mountain-array.ts │ ├── find-the-duplicate-number.ts │ ├── first-missing-positive.ts │ ├── first-missing-prime-number.ts │ ├── first-unique-character-in-a-string.ts │ ├── first-unique-number-in-data-stream.ts │ ├── fruit-into-baskets.ts │ ├── gray-code.ts │ ├── happy-number.ts │ ├── highest-frequency-ip.ts │ ├── house-robber.ts │ ├── jump-game-ii.ts │ ├── jump-game.ts │ ├── kids-with-the-greatest-number-of-candies.ts │ ├── kth-largest-element-in-an-array.ts │ ├── kth-smallest-element-in-a-sorted-matrix.ts │ ├── lemonade-change.ts │ ├── letter-combinations-of-a-phone-number.ts │ ├── longest-uncommon-subsequence-ii.ts │ ├── loop-asc-array.ts │ ├── lru-cache.ts │ ├── majority-element.ts │ ├── maximal-square.ts │ ├── maximum-and-minimum.ts │ ├── maximum-gap.ts │ ├── maximum-length-of-pair-chain.ts │ ├── maximum-length-of-repeated-subarray.ts │ ├── maximum-product-subarray.ts │ ├── maximum-subarray.ts │ ├── merge-intervals.ts │ ├── minimum-cost-for-tickets.ts │ ├── minimum-cost-to-hire-k-workers.ts │ ├── number-of-boomerangs.ts │ ├── number-of-islands.ts │ ├── partition-array.ts │ ├── product-of-array-except-self.ts │ ├── random-pick-with-blacklist.ts │ ├── remove-duplicates-from-sorted-array.ts │ ├── reverse-pairs.ts │ ├── rotate-array.ts │ ├── search-in-rotated-sorted-array.ts │ ├── search-insert-position.ts │ ├── select-sort.ts │ ├── shortest-word-distance.ts │ ├── shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof.ts │ ├── single-number.ts │ ├── sort-array-by-parity.ts │ ├── sort-transformed-array.ts │ ├── special-positions-in-a-binary-matrix.ts │ ├── spiral-matrix.ts │ ├── subarray-sums-divisible-by-k.ts │ ├── substring-with-concatenation-of-all-words.ts │ ├── wiggle-sort-ii.ts │ ├── x-of-a-kind-in-a-deck-of-cards.ts │ └── zigzag-conversion.ts ├── graphs │ ├── course-schedule-ii.ts │ ├── find-the-town-judge.ts │ ├── minimize-the-total-price-of-the-trips.ts │ └── possible-bipartition.ts ├── heap │ └── super-ugly-number.ts ├── lib │ ├── Heap.ts │ ├── ListNode.ts │ ├── MaxPriorityQueue.ts │ ├── MinPriorityQueue.ts │ ├── TreeNode.ts │ └── splice.ts ├── list │ ├── delete-node-in-a-linked-list.ts │ ├── linked-list-cycle.ts │ ├── merge-k-sorted-lists.ts │ ├── merge-two-sorted-lists.ts │ ├── middle-of-the-linked-list.ts │ ├── reverse-linked-list.ts │ ├── reverse-nodes-in-k-group.ts │ ├── sort-list.ts │ └── swap-nodes-in-pairs.ts ├── map │ ├── check-if-one-string-swap-can-make-strings-equal.ts │ ├── largest-substring-between-two-equal-characters.ts │ ├── longest-substring-with-at-most-k-distinct-characters.ts │ └── remove-letter-to-equalize-frequency.ts ├── math │ ├── 3sum-closest.ts │ ├── 3sum.ts │ ├── 4sum.ts │ ├── add-binary.ts │ ├── coin-lcci.ts │ ├── factorial-trailing-zeroes.ts │ ├── max-points-on-a-line.ts │ ├── maximum-lcci.ts │ ├── median-of-two-sorted-arrays.ts │ ├── next-greater-element-iii.ts │ ├── palindrome-number.ts │ ├── perfect-number.ts │ ├── permutations.ts │ ├── powx-n.ts │ ├── subarray-sum-equals-k.ts │ ├── ugly-number-ii.ts │ └── ugly-number.ts ├── other │ └── minimum-number-of-refueling-stops.ts ├── search │ └── array-nesting.ts ├── sort │ ├── bubbleSort.ts │ ├── insertSort.ts │ ├── mergeSort.ts │ ├── minimum-absolute-difference.ts │ ├── quickSort.ts │ └── selectSort.ts ├── stack │ ├── build-an-array-with-stack-operations.ts │ ├── decode-string.ts │ ├── dinner-plate-stacks.ts │ ├── maximal-rectangle.ts │ ├── min-stack.ts │ ├── simplify-path.ts │ └── yong-liang-ge-zhan-shi-xian-dui-lie-lcof.ts ├── string │ ├── check-if-a-word-occurs-as-a-prefix-of-any-word-in-a-sentence.ts │ ├── check-if-binary-string-has-at-most-one-segment-of-ones.ts │ ├── compare-strings.ts │ ├── contains-duplicate.ts │ ├── count-binary-substrings.ts │ ├── defanging-an-ip-address.ts │ ├── different-ways-to-add-parentheses.ts │ ├── find-the-longest-substring-containing-vowels-in-even-counts.ts │ ├── generate-a-string-with-characters-that-have-odd-counts.ts │ ├── generate-parentheses.ts │ ├── integer-to-roman.ts │ ├── largest-number.ts │ ├── length-of-last-word.ts │ ├── longest-common-prefix.ts │ ├── longest-palindromic-substring.ts │ ├── longest-substring-without-repeating-characters.ts │ ├── maximum-number-of-vowels-in-a-substring-of-given-length.ts │ ├── minimum-window-substring.ts │ ├── regular-expression-matching.ts │ ├── repeated-substring-pattern.ts │ ├── restore-ip-addresses.ts │ ├── reverse-words-in-a-string.ts │ ├── roman-to-integer.ts │ ├── string-matching-in-an-array.ts │ ├── string2int.ts │ ├── unique-characters.ts │ ├── valid-palindrome-ii.ts │ └── zuo-xuan-zhuan-zi-fu-chuan-lcof.ts └── tree │ ├── Tree.ts │ ├── bfs.ts │ ├── binary-tree-level-order-traversal-ii.ts │ ├── binary-tree-level-order-traversal.ts │ ├── binary-tree-right-side-view.ts │ ├── construct-binary-tree-from-preorder-and-inorder-traversal.ts │ ├── convert-sorted-array-to-binary-search-tree.ts │ ├── dfs.ts │ ├── lowest-common-ancestor-of-a-binary-tree.ts │ ├── my-calendar-i.ts │ ├── same-tree.ts │ ├── subtree-of-another-tree.ts │ ├── trim-a-binary-search-tree.ts │ ├── unique-binary-search-trees.ts │ └── validate-binary-search-tree.ts ├── test ├── array │ ├── 01-matrix.test.ts │ ├── 4sum-ii.test.ts │ ├── best-time-to-buy-and-sell-stock-ii.test.ts │ ├── binary-search.test.ts │ ├── bubble-sort.test.ts │ ├── can-place-flowers.test.ts │ ├── circular-array-loop.test.ts │ ├── container-with-most-water.test.ts │ ├── contains-duplicate-iii.test.ts │ ├── count-good-triplets.test.ts │ ├── count-number-of-nice-subarrays.test.ts │ ├── count-the-repetitions.test.ts │ ├── daily-temperatures.test.ts │ ├── defuse-the-bomb.test.ts │ ├── distance-between-bus-stops.test.ts │ ├── find-common-characters.test.ts │ ├── find-in-mountain-array.test.ts │ ├── find-the-duplicate-number.test.ts │ ├── first-missing-positive.test.ts │ ├── first-missing-prime-number.test.ts │ ├── first-unique-character-in-a-string.test.ts │ ├── first-unique-number-in-data-stream.test.ts │ ├── fruit-into-baskets.test.ts │ ├── gray-code.test.ts │ ├── happy-number.test.ts │ ├── highest-frequency-ip.test.ts │ ├── house-robber.test.ts │ ├── jump-game-ii.test.ts │ ├── jump-game.test.ts │ ├── kids-with-the-greatest-number-of-candies.test.ts │ ├── kth-largest-element-in-an-array.test.ts │ ├── kth-smallest-element-in-a-sorted-matrix.test.ts │ ├── lemonade-change.test.ts │ ├── letter-combinations-of-a-phone-number.test.ts │ ├── longest-uncommon-subsequence-ii.test.ts │ ├── loop-asc-array.test.ts │ ├── lru-cache.test.ts │ ├── majority-element.test.ts │ ├── maximal-square.test.ts │ ├── maximum-and-minimum.test.ts │ ├── maximum-gap.test.data.ts │ ├── maximum-gap.test.ts │ ├── maximum-length-of-pair-chain.test.ts │ ├── maximum-length-of-repeated-subarray.test.ts │ ├── maximum-product-subarray.test.ts │ ├── maximum-subarray.test.ts │ ├── merge-intervals.test.ts │ ├── minimum-cost-for-tickets.test.ts │ ├── minimum-cost-to-hire-k-workers.test.ts │ ├── number-of-boomerangs.test.ts │ ├── number-of-islands.test.ts │ ├── partition-array.test.ts │ ├── product-of-array-except-self.test.ts │ ├── random-pick-with-blacklist.test.ts │ ├── remove-duplicates-from-sorted-array.test.ts │ ├── reverse-pairs.test.ts │ ├── rotate-array.test.ts │ ├── search-in-rotated-sorted-array.test.ts │ ├── search-insert-position.test.ts │ ├── select-sort.test.ts │ ├── shortest-word-distance.test.ts │ ├── shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof.test.ts │ ├── single-number.test.ts │ ├── sort-array-by-parity.test.ts │ ├── sort-transformed-array.test.ts │ ├── special-positions-in-a-binary-matrix.test.ts │ ├── spiral-matrix.test.ts │ ├── subarray-sums-divisible-by-k.test.ts │ ├── substring-with-concatenation-of-all-words.test.ts │ ├── wiggle-sort-ii.test.ts │ ├── x-of-a-kind-in-a-deck-of-cards.test.ts │ └── zigzag-conversion.test.ts ├── graphs │ ├── course-schedule-ii.test.ts │ ├── find-the-town-judge.test.ts │ ├── minimize-the-total-price-of-the-trips.test.ts │ └── possible-bipartition.test.ts ├── heap │ └── super-ugly-number.test.ts ├── lib │ ├── Heap.test.ts │ ├── ListNode.test.ts │ ├── MaxPriorityQueue.test.ts │ ├── MinPriorityQueue.test.ts │ ├── TreeNode.test.ts │ └── splice.test.ts ├── list │ ├── ListNode.test.ts │ ├── delete-node-in-a-linked-list.test.ts │ ├── linked-list-cycle.test.ts │ ├── merge-k-sorted-lists.test.ts │ ├── merge-two-sorted-lists.test.ts │ ├── middle-of-the-linked-list.test.ts │ ├── reverse-linked-list.test.ts │ ├── reverse-nodes-in-k-group.test.ts │ ├── sort-list.test.ts │ └── swap-nodes-in-pairs.test.ts ├── map │ ├── check-if-one-string-swap-can-make-strings-equal.test.ts │ ├── largest-substring-between-two-equal-characters.test.ts │ ├── longest-substring-with-at-most-k-distinct-characters.test.ts │ └── remove-letter-to-equalize-frequency.test.ts ├── math │ ├── 3sum-closest.test.ts │ ├── 3sum.test.ts │ ├── 4sum.test.ts │ ├── add-binary.test.ts │ ├── coin-lcci.test.ts │ ├── factorial-trailing-zeroes.test.ts │ ├── max-points-on-a-line.test.ts │ ├── maximum-lcci.test.ts │ ├── median-of-two-sorted-arrays.test.ts │ ├── next-greater-element-iii.test.ts │ ├── palindrome-number.test.ts │ ├── perfect-number.test.ts │ ├── permutations.test.ts │ ├── powx-n.test.ts │ ├── subarray-sum-equals-k.test.ts │ ├── ugly-number-ii.test.ts │ └── ugly-number.test.ts ├── other │ └── minimum-number-of-refueling-stops.test.ts ├── search │ └── array-nesting.test.ts ├── sort │ ├── bubbleSort.test.ts │ ├── insertSort.test.ts │ ├── mergeSort.test.ts │ ├── minimum-absolute-difference.test.ts │ ├── quickSort.test.ts │ └── selectSort.test.ts ├── stack │ ├── build-an-array-with-stack-operations.test.ts │ ├── decode-string.test.ts │ ├── dinner-plate-stacks.test.ts │ ├── maximal-rectangle.test.ts │ ├── min-stack.test.ts │ ├── simplify-path.test.ts │ └── yong-liang-ge-zhan-shi-xian-dui-lie-lcof.test.ts ├── string │ ├── check-if-a-word-occurs-as-a-prefix-of-any-word-in-a-sentence.test.ts │ ├── check-if-binary-string-has-at-most-one-segment-of-ones.test.ts │ ├── compare-strings.test.ts │ ├── contains-duplicate.test.ts │ ├── count-binary-substrings.test.ts │ ├── defanging-an-ip-address.test.ts │ ├── different-ways-to-add-parentheses.test.ts │ ├── find-the-longest-substring-containing-vowels-in-even-counts.test.ts │ ├── generate-a-string-with-characters-that-have-odd-counts.test.ts │ ├── generate-parentheses.test.ts │ ├── integer-to-roman.test.ts │ ├── largest-number.test.ts │ ├── length-of-last-word.test.ts │ ├── longest-common-prefix.test.ts │ ├── longest-palindromic-substring.test.ts │ ├── longest-substring-without-repeating-characters.test.ts │ ├── maximum-number-of-vowels-in-a-substring-of-given-length.test.ts │ ├── minimum-window-substring.test.ts │ ├── regular-expression-matching.test.ts │ ├── repeated-substring-pattern.test.ts │ ├── restore-ip-addresses.test.ts │ ├── reverse-words-in-a-string.test.ts │ ├── roman-to-integer.test.ts │ ├── string-matching-in-an-array.test.ts │ ├── string2int.test.ts │ ├── unique-characters.test.ts │ ├── valid-palindrome-ii.test.ts │ └── zuo-xuan-zhuan-zi-fu-chuan-lcof.test.ts └── tree │ ├── bfs.test.ts │ ├── binary-tree-level-order-traversal-ii.test.ts │ ├── binary-tree-level-order-traversal.test.ts │ ├── binary-tree-right-side-view.test.ts │ ├── construct-binary-tree-from-preorder-and-inorder-traversal.test.ts │ ├── convert-sorted-array-to-binary-search-tree.test.ts │ ├── dfs.test.ts │ ├── lowest-common-ancestor-of-a-binary-tree.test.ts │ ├── my-calendar-i.test.ts │ ├── same-tree.test.ts │ ├── subtree-of-another-tree.test.ts │ ├── trim-a-binary-search-tree.test.ts │ ├── unique-binary-search-trees.test.ts │ └── validate-binary-search-tree.test.ts ├── tsconfig.json └── yarn.lock /.gitpod.yml: -------------------------------------------------------------------------------- 1 | tasks: 2 | - init: yarn install 3 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // 使用 IntelliSense 了解相关属性。 3 | // 悬停以查看现有属性的描述。 4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "pwa-node", 9 | "request": "launch", 10 | "name": "Launch Program", 11 | "skipFiles": ["/**"], 12 | "program": "${file}", 13 | "outFiles": ["${workspaceFolder}/**/*.js"] 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Yige 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /images/array/4sum-ii.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/array/4sum-ii.jpeg -------------------------------------------------------------------------------- /images/array/contains-duplicate-iii.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/array/contains-duplicate-iii.jpeg -------------------------------------------------------------------------------- /images/array/count-good-triplets.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/array/count-good-triplets.jpeg -------------------------------------------------------------------------------- /images/array/defuse-the-bomb.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/array/defuse-the-bomb.jpeg -------------------------------------------------------------------------------- /images/array/distance-between-bus-stops.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/array/distance-between-bus-stops.jpeg -------------------------------------------------------------------------------- /images/array/fruit-into-baskets.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/array/fruit-into-baskets.jpeg -------------------------------------------------------------------------------- /images/array/house-robber.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/array/house-robber.jpeg -------------------------------------------------------------------------------- /images/array/maximum-length-of-pair-chain.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/array/maximum-length-of-pair-chain.jpeg -------------------------------------------------------------------------------- /images/array/minimum-cost-to-hire-k-workers.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/array/minimum-cost-to-hire-k-workers.jpeg -------------------------------------------------------------------------------- /images/array/number-of-boomerangs.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/array/number-of-boomerangs.jpeg -------------------------------------------------------------------------------- /images/array/shortest-word-distance.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/array/shortest-word-distance.jpeg -------------------------------------------------------------------------------- /images/array/special-positions-in-a-binary-matrix.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/array/special-positions-in-a-binary-matrix.jpeg -------------------------------------------------------------------------------- /images/array/spiral-matrix.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/array/spiral-matrix.jpeg -------------------------------------------------------------------------------- /images/graphs/find-the-town-judge.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/graphs/find-the-town-judge.jpeg -------------------------------------------------------------------------------- /images/graphs/minimize-the-total-price-of-the-trips.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/graphs/minimize-the-total-price-of-the-trips.jpeg -------------------------------------------------------------------------------- /images/graphs/possible-bipartition.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/graphs/possible-bipartition.jpeg -------------------------------------------------------------------------------- /images/list/delete-node-in-a-linked-list.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/list/delete-node-in-a-linked-list.jpeg -------------------------------------------------------------------------------- /images/list/reverse-linked-list.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/list/reverse-linked-list.jpeg -------------------------------------------------------------------------------- /images/map/check-if-one-string-swap-can-make-strings-equal.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/map/check-if-one-string-swap-can-make-strings-equal.jpeg -------------------------------------------------------------------------------- /images/map/largest-substring-between-two-equal-characters.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/map/largest-substring-between-two-equal-characters.jpeg -------------------------------------------------------------------------------- /images/map/remove-letter-to-equalize-frequency.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/map/remove-letter-to-equalize-frequency.jpeg -------------------------------------------------------------------------------- /images/math/max-points-on-a-line.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/math/max-points-on-a-line.jpeg -------------------------------------------------------------------------------- /images/math/ugly-number.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/math/ugly-number.jpeg -------------------------------------------------------------------------------- /images/search/array-nesting.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/search/array-nesting.jpeg -------------------------------------------------------------------------------- /images/sort/minimum-absolute-difference.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/sort/minimum-absolute-difference.jpeg -------------------------------------------------------------------------------- /images/stack/build-an-array-with-stack-operations.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/stack/build-an-array-with-stack-operations.jpeg -------------------------------------------------------------------------------- /images/stack/dinner-plate-stacks.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/stack/dinner-plate-stacks.jpeg -------------------------------------------------------------------------------- /images/stack/simplify-path.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/stack/simplify-path.jpeg -------------------------------------------------------------------------------- /images/string/check-if-binary-string-has-at-most-one-segment-of-ones.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/string/check-if-binary-string-has-at-most-one-segment-of-ones.jpeg -------------------------------------------------------------------------------- /images/string/generate-a-string-with-characters-that-have-odd-counts.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/string/generate-a-string-with-characters-that-have-odd-counts.jpeg -------------------------------------------------------------------------------- /images/string/string-matching-in-an-array.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/string/string-matching-in-an-array.jpeg -------------------------------------------------------------------------------- /images/tree/my-calendar-i.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/tree/my-calendar-i.jpeg -------------------------------------------------------------------------------- /images/tree/same-tree.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/tree/same-tree.jpeg -------------------------------------------------------------------------------- /images/tree/trim-a-binary-search-tree.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yi-ge/typescript-practice/25a41fbbb8c8683c41876562709700d82022c59f/images/tree/trim-a-binary-search-tree.jpeg -------------------------------------------------------------------------------- /src/array/01-matrix.ts: -------------------------------------------------------------------------------- 1 | export const updateMatrix = function (matrix: number[][]): number[][] { 2 | if (matrix.length === 0) return [] 3 | 4 | const m = matrix.length 5 | const n = matrix[0].length 6 | 7 | // 左上 -> 右下 8 | for (let i = 0; i < m; i++) { 9 | for (let j = 0; j < n; j++) { 10 | if (matrix[i][j] !== 0) { 11 | matrix[i][j] = m + n 12 | if (i > 0) matrix[i][j] = Math.min(matrix[i - 1][j] + 1, matrix[i][j]) 13 | if (j > 0) matrix[i][j] = Math.min(matrix[i][j - 1] + 1, matrix[i][j]) 14 | } 15 | } 16 | } 17 | 18 | // 右下 -> 左上 19 | for (let i = m - 1; i >= 0; i--) { 20 | for (let j = n - 1; j >= 0; j--) { 21 | // distance 22 | if (matrix[i][j] !== 0) { 23 | if (j < n - 1) matrix[i][j] = Math.min(matrix[i][j], matrix[i][j + 1] + 1) 24 | if (i < matrix.length - 1) matrix[i][j] = Math.min(matrix[i][j], matrix[i + 1][j] + 1) 25 | } 26 | } 27 | } 28 | 29 | return matrix 30 | } 31 | -------------------------------------------------------------------------------- /src/array/4sum-ii.ts: -------------------------------------------------------------------------------- 1 | // 四数相加 II 2 | // https://leetcode.cn/problems/4sum-ii/ 3 | // INLINE ../../images/array/4sum-ii.jpeg 4 | 5 | export function fourSumCount (nums1: number[], nums2: number[], nums3: number[], nums4: number[]): number { 6 | const map = new Map() 7 | for (let i = 0; i < nums3.length; i++) { 8 | for (let j = 0; j < nums4.length; j++) { 9 | const sum = nums3[i] + nums4[j] 10 | if (map.has(sum)) { 11 | map.set(sum, map.get(sum) as number + 1) 12 | } else { 13 | map.set(sum, 1) 14 | } 15 | } 16 | } 17 | 18 | let res = 0 19 | for (let i = 0; i < nums1.length; i++) { 20 | for (let j = 0; j < nums2.length; j++) { 21 | const sum = 0 - nums1[i] - nums2[j] 22 | if (map.has(sum)) res += map.get(sum) as number 23 | } 24 | } 25 | 26 | return res 27 | } -------------------------------------------------------------------------------- /src/array/best-time-to-buy-and-sell-stock-ii.ts: -------------------------------------------------------------------------------- 1 | export const maxProfit = function (prices: number[]): number { 2 | let profit = 0 3 | for (let n = 1; n < prices.length; n++) { 4 | if (prices[n] > prices[n - 1]) profit += prices[n] - prices[n - 1] 5 | } 6 | 7 | return profit 8 | } 9 | 10 | -------------------------------------------------------------------------------- /src/array/binary-search.ts: -------------------------------------------------------------------------------- 1 | export const search = function (nums: number[], target: number): number { 2 | if (!nums || nums.length === 0) return -1 3 | 4 | let start = 0 5 | let end = nums.length 6 | while (start < end) { 7 | const mid = Math.floor(start + (end - start) / 2) 8 | if (target === nums[mid]) { 9 | end = mid 10 | } else if (target < nums[mid]) { 11 | end = mid - 1 12 | } else { 13 | start = mid + 1 14 | } 15 | } 16 | 17 | if (target === nums[start]) { 18 | return start 19 | } 20 | 21 | return -1 22 | } 23 | -------------------------------------------------------------------------------- /src/array/bubble-sort.ts: -------------------------------------------------------------------------------- 1 | // 冒泡排序 2 | // 平均时间复杂度 O(n * n), 最好情况 O(n),最坏情况 O(n * n) 3 | // 空间复杂度 O(1) 4 | // 稳定 5 | 6 | export default (arr: number[]): number[] => { 7 | for (let n = 0, len = arr.length - 1, down = true; n < len; n++) { 8 | for (let i = 0, iLen = len - n; i < iLen; i++) { 9 | if (arr[i + 1] < arr[i]) { 10 | const tmp = arr[i] 11 | arr[i] = arr[i + 1] 12 | arr[i + 1] = tmp 13 | down = false 14 | } 15 | } 16 | if (down) break 17 | } 18 | return arr 19 | } 20 | -------------------------------------------------------------------------------- /src/array/can-place-flowers.ts: -------------------------------------------------------------------------------- 1 | export default (flowerbed: number[], n: number): boolean => { 2 | let max = 0 3 | 4 | // 前后各加一个0,避免判断边界情况。 5 | flowerbed.unshift(0) 6 | flowerbed.push(0) 7 | 8 | for (let i = 0, len = flowerbed.length - 1; i < len; i++) { 9 | if (flowerbed[i] === 0) { 10 | if (flowerbed[i - 1] === 0 && flowerbed[i + 1] === 0) { // 判断前后两个元素是否为0 11 | max++ 12 | i++ 13 | } 14 | } 15 | } 16 | 17 | return max >= n 18 | } 19 | -------------------------------------------------------------------------------- /src/array/circular-array-loop.ts: -------------------------------------------------------------------------------- 1 | // LeetCode 457. 环形数组循环 https://leetcode-cn.com/problems/circular-array-loop/ 2 | // LintCode 1229. 循环数组中的环 https://www.lintcode.com/problem/circular-array-loop/description 3 | 4 | const getNextIndex = (nums: number[], len: number, cur: number) => { 5 | return ((cur + nums[cur]) % len + len) % len 6 | } 7 | 8 | export function circularArrayLoop (nums: number[]): boolean { 9 | for (let i = 0, len = nums.length; i < len; i++) { 10 | if (nums[i] === 0) continue 11 | let slow = i, fast = getNextIndex(nums, len, i) 12 | while (nums[slow] * nums[fast] > 0 && nums[slow] * nums[getNextIndex(nums, len, fast)] > 0) { // 方向相同 13 | if (slow === fast) { 14 | if (slow !== getNextIndex(nums, len, slow)) { 15 | return true 16 | } else { 17 | break 18 | } 19 | } 20 | slow = getNextIndex(nums, len, slow) 21 | fast = getNextIndex(nums, len, getNextIndex(nums, len, fast)) 22 | } 23 | let add = i 24 | while (nums[add] * nums[getNextIndex(nums, len, add)] > 0) { 25 | const tmp = add 26 | add = getNextIndex(nums, len, add) 27 | nums[tmp] = 0 28 | } 29 | } 30 | return false 31 | } -------------------------------------------------------------------------------- /src/array/container-with-most-water.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 双指针 3 | * @param {number[]} heights 4 | * @return {number} 5 | */ 6 | export const maxArea = function (heights:number[]):number { 7 | let max = 0 8 | 9 | let l = 0 10 | let r = heights.length - 1 11 | 12 | while (l < r) { 13 | const height = Math.min(heights[l], heights[r]) 14 | const area = height * (r - l) 15 | if (area > max) { 16 | max = area 17 | } 18 | 19 | if (heights[l] <= heights[r]) { 20 | l++ 21 | } else { 22 | r-- 23 | } 24 | } 25 | 26 | return max 27 | } 28 | 29 | // 解法一: 可能超时 30 | // /** 31 | // * @param {number[]} heights 32 | // * @return {number} 33 | // */ 34 | // export const maxArea = function (heights) { 35 | // let max = 0; 36 | 37 | // for (let n = 0, len = heights.length; n < len - 1; n++) { 38 | // for (let i = 1; i < len; i++) { 39 | // const height = Math.min(heights[n], heights[i]) 40 | // const area = height * (i - n) 41 | // if (area > max) { 42 | // max = area 43 | // } 44 | // } 45 | // } 46 | 47 | // return max 48 | // } 49 | -------------------------------------------------------------------------------- /src/array/contains-duplicate-iii.ts: -------------------------------------------------------------------------------- 1 | // 存在重复元素 III 2 | // https://leetcode.cn/problems/contains-duplicate-iii/ 3 | // INLINE ../../images/array/contains-duplicate-iii.jpeg 4 | 5 | export function containsNearbyAlmostDuplicate (nums: number[], k: number, t: number): boolean { 6 | const set = new Set() 7 | for (let i = 0, len = nums.length; i < len; i++) { 8 | let min = Number.MAX_VALUE 9 | for (const n of set.values()) { // abs(nums[i] - nums[j]) <= t 10 | if (n /*?*/ >= nums[i] - t) { 11 | min = Math.min(min, n) 12 | } 13 | } 14 | if (min !== Number.MAX_VALUE && min/*?*/ <= nums[i] + t) return true 15 | 16 | set.add(nums[i]) /*?*/ 17 | 18 | // 如果出现重复元素, set 的 size 不能反映实际长度。但是本题不受影响 19 | if (set.size > k) { // 满足 abs(i - j) <= k 20 | set.delete(nums[i - k]) /*?*/ 21 | } 22 | } 23 | 24 | return false 25 | } -------------------------------------------------------------------------------- /src/array/count-good-triplets.ts: -------------------------------------------------------------------------------- 1 | // 统计好三元组 2 | // https://leetcode.cn/problems/count-good-triplets/ 3 | // INLINE ../../images/array/count-good-triplets.jpeg 4 | 5 | export function countGoodTriplets (arr: number[], a: number, b: number, c: number): number { 6 | let ans = 0 7 | for (let i = 0; i < arr.length; i++) { 8 | for (let j = i + 1; j < arr.length; j++) { 9 | for (let k = j + 1; k < arr.length; k++) { 10 | if (Math.abs(arr[i] - arr[j]) <= a && Math.abs(arr[j] - arr[k]) <= b && Math.abs(arr[i] - arr[k]) <= c) { 11 | ans++ 12 | } 13 | } 14 | } 15 | } 16 | return ans 17 | } -------------------------------------------------------------------------------- /src/array/daily-temperatures.ts: -------------------------------------------------------------------------------- 1 | export const dailyTemperatures = function (T: number[]): number[] { 2 | const len = T.length 3 | const ans = new Array(len).fill(0) 4 | const stack = [] 5 | for (let i = 0; i < len; i++) { 6 | const temperature = T[i] 7 | while (stack.length && temperature > T[stack[stack.length - 1]]) { 8 | const prevIndex = stack.pop() as number 9 | ans[prevIndex] = i - prevIndex 10 | } 11 | stack.push(i) 12 | } 13 | return ans 14 | } 15 | -------------------------------------------------------------------------------- /src/array/defuse-the-bomb.ts: -------------------------------------------------------------------------------- 1 | // 拆炸弹 2 | // https://leetcode.cn/problems/defuse-the-bomb 3 | // INLINE ../../images/array/defuse-the-bomb.jpeg 4 | // 解题思路:拼接数组,模拟过程 5 | 6 | export function decrypt (code: number[], k: number): number[] { 7 | if (k === 0) return new Array(code.length).fill(0) 8 | const codes = [...code, ...code] 9 | const res = [] 10 | if (k > 0) { 11 | for (let i = 0; i < code.length; i++) { 12 | let sum = 0 13 | for (let j = 0; j < k; j++) { 14 | sum += codes[i + j + 1] 15 | } 16 | res.push(sum) 17 | } 18 | } else { 19 | for (let i = code.length; i < code.length * 2; i++) { 20 | let sum = 0 21 | for (let j = 0; j < Math.abs(k); j++) { 22 | sum += codes[i - j - 1] 23 | } 24 | res.push(sum) 25 | } 26 | } 27 | return res 28 | } -------------------------------------------------------------------------------- /src/array/distance-between-bus-stops.ts: -------------------------------------------------------------------------------- 1 | // 公交站间的距离 2 | // https://leetcode.cn/problems/distance-between-bus-stops 3 | // INLINE ../../images/array/distance-between-bus-stops.jpeg 4 | 5 | export function distanceBetweenBusStops (distance: number[], start: number, destination: number): number { 6 | if (start > destination) [start, destination] = [destination, start] 7 | 8 | let dis1 = 0 9 | let dis2 = 0 10 | for (let i = 0, len = distance.length; i < len; i++) { 11 | if (i >= start && i < destination) { 12 | dis1 += distance[i] 13 | } else { 14 | dis2 += distance[i] 15 | } 16 | } 17 | return Math.min(dis1, dis2) 18 | } -------------------------------------------------------------------------------- /src/array/find-common-characters.ts: -------------------------------------------------------------------------------- 1 | export const commonChars = function (A: string[]): string[] { 2 | const res = [] 3 | let chars = new Set(A[0].split('')) // 不重复的chat集合 4 | for (let n = 1; n < A.length; n++) { 5 | const b = new Set(A[n].split('')) 6 | chars = new Set([...b].filter(x => chars.has(x))) 7 | } 8 | 9 | const maps = [] 10 | 11 | for (let n = 0; n < A.length; n++) { 12 | const tmp = new Map() 13 | for (let i = 0; i < A[n].length; i++) { 14 | if (chars.has(A[n][i])) { 15 | if (tmp.has(A[n][i])) { 16 | tmp.set(A[n][i], tmp.get(A[n][i]) + 1) 17 | } else { 18 | tmp.set(A[n][i], 1) 19 | } 20 | } 21 | } 22 | maps.push(tmp) 23 | } 24 | 25 | const newChars = [...chars] 26 | 27 | for (const n in newChars) { 28 | let min = -1 29 | for (const i in maps) { 30 | if (maps[i].get(newChars[n]) < min || min === -1) { 31 | min = maps[i].get(newChars[n]) 32 | } 33 | } 34 | for (let x = 0; x < min; x++) { 35 | res.push(newChars[n]) 36 | } 37 | } 38 | 39 | return res 40 | } 41 | -------------------------------------------------------------------------------- /src/array/find-the-duplicate-number.ts: -------------------------------------------------------------------------------- 1 | export const findDuplicate = function (nums: number[]): number { 2 | const len = nums.length 3 | let l = 0; let r = len - 1; let res = -1 // 数字都在1-n 4 | while (l <= r) { 5 | const mid = (l + r) >> 1 6 | let cnt = 0 7 | for (let i = 0; i < len; i++) { 8 | cnt += nums[i] <= mid ? 1 : 0 // true = 1,满足条件才计数 9 | } 10 | 11 | if (cnt <= mid) { 12 | l = mid + 1 13 | } else { 14 | r = mid - 1 15 | res = mid 16 | } 17 | } 18 | 19 | return res 20 | } 21 | -------------------------------------------------------------------------------- /src/array/first-unique-character-in-a-string.ts: -------------------------------------------------------------------------------- 1 | export const firstUniqChar = function (s: string): string { 2 | const due = new Set() 3 | const queue = new Set() 4 | for (const n of s) { 5 | if (queue.has(n)) { 6 | queue.delete(n) 7 | due.add(n) 8 | } else if (!due.has(n)) { 9 | queue.add(n) 10 | } 11 | } 12 | 13 | return Array.from(queue)?.[0] as string || ' ' 14 | } 15 | -------------------------------------------------------------------------------- /src/array/first-unique-number-in-data-stream.ts: -------------------------------------------------------------------------------- 1 | export const firstUniqueNumber = function (nums: number[], number_: number): number { 2 | const due = new Set() 3 | const queue = new Set() 4 | for (const n of nums) { 5 | if (queue.has(n)) { 6 | queue.delete(n) 7 | due.add(n) 8 | } else if (!due.has(n)) { 9 | queue.add(n) 10 | } 11 | 12 | if (n === number_) break 13 | } 14 | 15 | if (!due.has(number_) && !queue.has(number_)) return -1 16 | 17 | return Array.from(queue)[0] as number 18 | } 19 | -------------------------------------------------------------------------------- /src/array/fruit-into-baskets.ts: -------------------------------------------------------------------------------- 1 | // 水果成篮 2 | // https://leetcode.cn/problems/fruit-into-baskets 3 | // INLINE ../../images/array/fruit-into-baskets.jpeg 4 | 5 | export function totalFruit (fruits: number[]): number { 6 | const map = new Map() 7 | 8 | let left = 0, right = 0, ans = 0 9 | while (right < fruits.length) { 10 | map.set(fruits[right], (map.get(fruits[right]) || 0) + 1) 11 | while (map.size > 2) { 12 | map.set(fruits[left], map.get(fruits[left]) - 1) 13 | if (map.get(fruits[left]) === 0) { 14 | map.delete(fruits[left]) 15 | } 16 | left++ 17 | } 18 | ans = Math.max(ans, right - left + 1) 19 | right++ 20 | } 21 | 22 | return ans 23 | } -------------------------------------------------------------------------------- /src/array/gray-code.ts: -------------------------------------------------------------------------------- 1 | // LeetCode 89. 格雷编码 https://leetcode-cn.com/problems/gray-code/ 2 | // LintCode 411. 格雷编码 https://www.lintcode.com/problem/gray-code/description 3 | 4 | export default (n: number): number[] => { 5 | if (n === 0) return [0] 6 | const make = (n: number): number[] => { 7 | if (n === 1) { 8 | return [0, 1] 9 | } else { 10 | const prev = make(n - 1) 11 | const result = [] 12 | const max = Math.pow(2, n) - 1 13 | for (let i = 0, len = prev.length; i < len; i++) { 14 | result[i] = Number(`0${prev[i]}`) 15 | result[max - i] = Number(`1${prev[i]}`) 16 | } 17 | return result 18 | } 19 | } 20 | 21 | return make(n).map(val => { 22 | return parseInt(val.toString(), 2) 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /src/array/happy-number.ts: -------------------------------------------------------------------------------- 1 | export const isHappy = function (n: number): boolean { 2 | const set = new Set() 3 | 4 | while (n !== 1 && !set.has(n)) { 5 | set.add(n) 6 | n = n.toString().split('').reduce((a, b) => a + Number(b) * Number(b), 0) 7 | } 8 | 9 | return n === 1 10 | } 11 | -------------------------------------------------------------------------------- /src/array/highest-frequency-ip.ts: -------------------------------------------------------------------------------- 1 | export const highestFrequency = function (ipLines: string[]): string { 2 | const map = new Map() 3 | let max = 0 4 | let maxN = ipLines[0] 5 | ipLines.forEach(n => { 6 | const temp = (map.get(n) || 0) + 1 7 | map.set(n, temp) 8 | if (temp > max) { 9 | maxN = n 10 | max = temp 11 | } 12 | }) 13 | 14 | return maxN 15 | } 16 | -------------------------------------------------------------------------------- /src/array/house-robber.ts: -------------------------------------------------------------------------------- 1 | // 打家劫舍 2 | // https://leetcode.cn/problems/house-robber 3 | // INLINE ../../images/array/house-robber.jpeg 4 | 5 | export const rob = function (nums?: number[]): number { 6 | if (!nums) return 0 7 | const len = nums.length 8 | if (len === 0) return 0 9 | if (len === 1) return nums[0] 10 | 11 | let first = nums[0] 12 | let second = Math.max(nums[0], nums[1]) 13 | for (let i = 2; i < len; i++) { 14 | const temp = second 15 | second = Math.max(first + nums[i], second) 16 | first = temp 17 | } 18 | return second 19 | } 20 | -------------------------------------------------------------------------------- /src/array/jump-game-ii.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number} 4 | */ 5 | export const jump = function (nums: number[]): number { 6 | let step = 0 // 跳跃步数 7 | let maxPosition = 0 // 最大位置 8 | let lastJumpStepMax = 0 // 最后一次跳跃最大能跳的步数 9 | 10 | for (let n = 0, len = nums.length; n < len - 1; n++) { 11 | maxPosition = Math.max(maxPosition, nums[n] + n) 12 | if (lastJumpStepMax === n) { // 从当前位置开始,到当前能跳的位置这个区间,谁最大,就选谁,并跳一次 13 | lastJumpStepMax = maxPosition 14 | step++ 15 | } 16 | if (lastJumpStepMax > len) return step 17 | } 18 | 19 | return step 20 | } 21 | -------------------------------------------------------------------------------- /src/array/jump-game.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {boolean} 4 | */ 5 | export const canJump = function (nums:number[]):boolean { 6 | let maxLength = nums[0] 7 | 8 | for (let n = 1, len = nums.length; n < len; n++) { 9 | if (n > maxLength) return false // 如果能调最远的距离没有超过当前起跳距离,必然失败 10 | const tmp = n + nums[n] 11 | if (tmp > maxLength) maxLength = tmp // 获取能跳最远的距离 12 | } 13 | 14 | return true 15 | } 16 | 17 | // let maxLength = 0 18 | 19 | // for (const n in nums) { 20 | // if (n > maxLength) return false // 如果能调最远的距离没有超过当前起跳距离,必然失败 21 | // maxLength = Math.max(maxLength, Number(n) + nums[n]) // 获取能跳最远的距离 22 | // } 23 | 24 | // return true 25 | -------------------------------------------------------------------------------- /src/array/kids-with-the-greatest-number-of-candies.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} candies 3 | * @param {number} extraCandies 4 | * @return {boolean[]} 5 | */ 6 | export const kidsWithCandies = (candies:number[], extraCandies:number):boolean[] => { 7 | return candies.map(n => n + extraCandies >= Math.max(...candies)) 8 | } 9 | -------------------------------------------------------------------------------- /src/array/kth-largest-element-in-an-array.ts: -------------------------------------------------------------------------------- 1 | 2 | export default (arr:number[], k:number) => { 3 | // 这个方法未必是效率最差的 4 | return arr.sort((a, b) => b - a)[k - 1] 5 | 6 | // 冒泡排序变种,只排序指定长度的内容。未必是最佳方案 7 | // const len = arr.length - 1 8 | // for (let n = 0, down = true; n < k; n++) { 9 | // for (let i = 0, iLen = len - n; i < iLen; i++) { 10 | // if (arr[i + 1] < arr[i]) { 11 | // const tmp = arr[i] 12 | // arr[i] = arr[i + 1] 13 | // arr[i + 1] = tmp 14 | // down = false 15 | // } 16 | // } 17 | // if (down) break 18 | // } 19 | // return arr[len - k + 1] 20 | } 21 | -------------------------------------------------------------------------------- /src/array/kth-smallest-element-in-a-sorted-matrix.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[][]} matrix 3 | * @param {number} k 4 | * @return {number} 5 | */ 6 | export const kthSmallest = function (matrix:number[][], k:number):number { 7 | return matrix.flat().sort((a, b) => a - b)[k - 1] 8 | } 9 | -------------------------------------------------------------------------------- /src/array/lemonade-change.ts: -------------------------------------------------------------------------------- 1 | export const lemonadeChange = function (bills: number[]): boolean { 2 | const map = new Map() 3 | 4 | while (bills.length) { 5 | const money = bills.shift() as number 6 | 7 | if (money === 5) { 8 | map.set(5, (map.get(5) || 0) + 1) 9 | } else { 10 | let change = money - 5 11 | while (change !== 0 && change - 10 > 0 && map.get(10) > 0) { 12 | map.set(10, map.get(10) - 1) 13 | change -= 10 14 | } 15 | 16 | while (change !== 0 && map.get(5) > 0) { 17 | map.set(5, map.get(5) - 1) 18 | change -= 5 19 | } 20 | 21 | if (change !== 0) return false 22 | map.set(money, (map.get(money) || 0) + 1) 23 | } 24 | } 25 | 26 | return true 27 | } 28 | -------------------------------------------------------------------------------- /src/array/letter-combinations-of-a-phone-number.ts: -------------------------------------------------------------------------------- 1 | // LeetCode 17. 电话号码的字母组合 https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/ 2 | // LintCode 425. 电话号码的字母组合 https://www.lintcode.com/problem/letter-combinations-of-a-phone-number/description 3 | 4 | export default function letterCombinations (digits: string): string[] { 5 | const map = new Map([ 6 | ['2', 'abc'], 7 | ['3', 'def'], 8 | ['4', 'ghi'], 9 | ['5', 'jkl'], 10 | ['6', 'mno'], 11 | ['7', 'pqrs'], 12 | ['8', 'tuv'], 13 | ['9', 'wxyz'] 14 | ]) 15 | 16 | const nums = digits.split('') 17 | 18 | if (nums.length === 0) return [] 19 | 20 | const code: string[] = [] 21 | 22 | nums.forEach(item => { 23 | if (map.get(item)) { 24 | code.push(map.get(item) as string) 25 | } 26 | }) 27 | 28 | const comb = (arr: any[]): string[] => { 29 | const tmp = [] 30 | for (let n = 0; n < arr[0].length; n++) { 31 | for (let i = 0; i < arr[1].length; i++) { 32 | tmp.push(`${arr[0][n]}${arr[1][i]}`) 33 | } 34 | } 35 | arr.splice(0, 2, tmp) 36 | 37 | if (arr.length > 1) { 38 | comb(arr) 39 | } else { 40 | return tmp 41 | } 42 | return arr[0] 43 | } 44 | 45 | return code.length > 1 ? comb(code) : code[0].split('') 46 | } 47 | -------------------------------------------------------------------------------- /src/array/longest-uncommon-subsequence-ii.ts: -------------------------------------------------------------------------------- 1 | // 题目翻译:给出一个字符串数组,在里面找出字符串满足`当前字符串不是字符串数组中其他字符串的子序列`,返回满足条件的字符串中`最长的字符串的长度` 2 | 3 | /** 4 | * 判断字符串是不是另一个字符串的子序列 5 | * @param str1 字符串1 6 | * @param str2 字符串2 7 | * @returns 是否是子序列 8 | */ 9 | export function isSubsequence(str1: string, str2: string): boolean { 10 | if (str1.length > str2.length) return false 11 | if (str1 === str2) return true 12 | 13 | let p = 0, q = 0 14 | 15 | while(p < str1.length && q < str2.length) { 16 | if (str1[p] === str2[q]) { 17 | p++ 18 | q++ 19 | } else { 20 | q++ 21 | } 22 | } 23 | 24 | return p === str1.length 25 | } 26 | 27 | export function findLUSlength(strs: string[]): number { 28 | let ans = -1 29 | 30 | for (let i = 0, len = strs.length; i < len; i++) { 31 | let check = true 32 | for (let j = 0; j < len; j++) { 33 | if (i === j) continue 34 | if (isSubsequence(strs[i], strs[j])) { 35 | check = false 36 | break 37 | } 38 | } 39 | if (check) { // 如果都不是子序列 40 | ans = Math.max(ans, strs[i].length) 41 | } 42 | } 43 | 44 | return ans 45 | }; -------------------------------------------------------------------------------- /src/array/lru-cache.ts: -------------------------------------------------------------------------------- 1 | export default class LRUCache { 2 | private max: number 3 | private map: Map 4 | constructor (capacity: number) { 5 | this.max = capacity 6 | this.map = new Map() 7 | } 8 | 9 | get (key: number): number { 10 | const value = this.map.get(key) 11 | if (value !== undefined) { 12 | this.map.delete(key) 13 | this.map.set(key, value) 14 | return value 15 | } 16 | return -1 17 | } 18 | 19 | put (key: number, value: number): void { 20 | this.map.delete(key) 21 | this.map.set(key, value) 22 | if (this.map.size > this.max) this.map.delete(this.map.keys().next().value) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/array/majority-element.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number} 4 | */ 5 | export const majorityElement = function (nums:number[]):number { 6 | if (nums.length === 1) return nums[0] 7 | const tmp = nums.sort((a, b) => a - b) 8 | const res = tmp[~~(nums.length / 2)] 9 | if (nums.length > 2) return res 10 | if (nums.length === 2 && nums[0] === nums[1]) { 11 | return res 12 | } 13 | return -1 14 | } 15 | -------------------------------------------------------------------------------- /src/array/maximal-square.ts: -------------------------------------------------------------------------------- 1 | export const maximalSquare = function (matrix: number[][]): number { 2 | if (!matrix || !matrix[0]) return 0 3 | 4 | const rows = matrix.length 5 | const cols = matrix[0].length 6 | let max = 0 7 | 8 | const dp = new Array(rows).fill(0).map(_ => new Array(cols).fill(0)) 9 | 10 | for (let n = 0; n < rows; n++) { 11 | for (let i = 0; i < cols; i++) { 12 | if (Number(matrix[n][i]) === 1) { 13 | if (n === 0 || i === 0) dp[n][i] = 1 14 | else dp[n][i] = Math.min(dp[n - 1][i], dp[n][i - 1], dp[n - 1][i - 1]) + 1 // 找规律 15 | max = Math.max(max, dp[n][i]) 16 | } 17 | } 18 | } 19 | 20 | return max * max 21 | } 22 | -------------------------------------------------------------------------------- /src/array/maximum-and-minimum.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param matrix: an input matrix 3 | * @return: nums[0]: the maximum,nums[1]: the minimum 4 | */ 5 | export const maxAndMin = function (matrix:number[][]) { 6 | if (matrix[0] === undefined || matrix[0][0] === undefined) return [] 7 | let max = matrix[0][0] 8 | let min = matrix[0][0] 9 | 10 | for (let n = 0, len = matrix.length; n < len; n++) { 11 | for (let i = 0; i < matrix[0].length; i++) { 12 | max = Math.max(max, matrix[n][i]) 13 | min = Math.min(min, matrix[n][i]) 14 | } 15 | } 16 | 17 | return [max, min] 18 | } 19 | -------------------------------------------------------------------------------- /src/array/maximum-length-of-pair-chain.ts: -------------------------------------------------------------------------------- 1 | // 最长数对链 2 | // https://leetcode.cn/problems/maximum-length-of-pair-chain 3 | // INLINE ../../images/array/maximum-length-of-pair-chain.jpeg 4 | 5 | export function findLongestChain (pairs: number[][]): number { 6 | let curr = -Infinity, ans = 0 7 | pairs.sort((a, b) => a[1] - b[1]) // ? 8 | for (let i = 0, len = pairs.length; i < len; i++) { 9 | if (curr < pairs[i][0]) { 10 | curr = pairs[i][1] 11 | ans++ 12 | } 13 | } 14 | return ans 15 | } -------------------------------------------------------------------------------- /src/array/maximum-length-of-repeated-subarray.ts: -------------------------------------------------------------------------------- 1 | // 输入: 2 | // A: [1, 2, 3, 2, 1] 3 | // B: [3, 2, 1, 4, 7] 4 | 5 | const maxLength = function (A:number[], B:number[], addA:number, addB:number, len:number) { 6 | addA = (addA > 0) ? addA : 0 7 | addB = (addB > 0) ? addB : 0 8 | let result = 0 9 | let k = 0 10 | for (let i = 0; i < len && (k + len - i > result); i++) { 11 | if (A[i + addA] === B[i + addB]) { 12 | k++ 13 | } else { 14 | k = 0 15 | } 16 | result = Math.max(result, k) 17 | } 18 | return result 19 | } 20 | 21 | /** 22 | * @param {number[]} A 23 | * @param {number[]} B 24 | * @return {number} 25 | */ 26 | export const findLength = function (A:number[], B:number[]):number { 27 | const ALen = A.length 28 | const BLen = B.length 29 | let result = 0 30 | for (let i = 1; i < ALen + BLen; i++) { 31 | if (result >= (ALen + BLen - i)) { 32 | return result 33 | } 34 | const len = Math.min(i, ALen, BLen, (ALen + BLen - i)) 35 | result = Math.max(maxLength(A, B, ALen - i, i - ALen, len), result) 36 | } 37 | return result 38 | } 39 | -------------------------------------------------------------------------------- /src/array/maximum-product-subarray.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number} 4 | */ 5 | export const maxProduct = function (nums:number[]):number { 6 | let res = nums[0] 7 | let prevMin = nums[0] 8 | let prevMax = nums[0] 9 | let tmp1 = 0; let tmp2 = 0 10 | for (let i = 1; i < nums.length; i++) { 11 | tmp1 = prevMin * nums[i] 12 | tmp2 = prevMax * nums[i] 13 | prevMin = Math.min(tmp1, tmp2, nums[i]) 14 | prevMax = Math.max(tmp1, tmp2, nums[i]) 15 | res = Math.max(prevMax, res) 16 | } 17 | return res 18 | } 19 | -------------------------------------------------------------------------------- /src/array/maximum-subarray.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number} 4 | */ 5 | export const maxSubArray = function (nums:number[]):number { 6 | let max = nums[0] 7 | let tmp = 0 8 | nums.forEach(n => { max = Math.max(tmp > 0 ? tmp += n : tmp = n, max) }) 9 | // 如果当前指针所指元素之前的和小于0,则丢弃当前元素之前的数列 10 | return max 11 | } 12 | -------------------------------------------------------------------------------- /src/array/merge-intervals.ts: -------------------------------------------------------------------------------- 1 | export const merge = function (intervals: number[][]): number[][] { 2 | if (intervals.length < 2) return intervals 3 | 4 | intervals = intervals.sort((a, b) => a[0] - b[0]) 5 | 6 | const res = [intervals[0]] 7 | 8 | for (let n = 1, len = intervals.length; n < len; n++) { 9 | if (intervals[n][0] <= res[res.length - 1][1]) { 10 | if (intervals[n][1] > res[res.length - 1][1]) { 11 | res[res.length - 1][1] = intervals[n][1] 12 | } 13 | } else { 14 | res.push(intervals[n]) 15 | } 16 | } 17 | 18 | return res 19 | } 20 | 21 | -------------------------------------------------------------------------------- /src/array/minimum-cost-to-hire-k-workers.ts: -------------------------------------------------------------------------------- 1 | import { MaxPriorityQueue } from './../lib/MaxPriorityQueue' 2 | // 雇佣 K 名工人的最低成本 3 | // https://leetcode.cn/problems/minimum-cost-to-hire-k-workers 4 | // INLINE ../../images/array/minimum-cost-to-hire-k-workers.jpeg 5 | // 解题思路:去菜市场买菜,第一家青菜5元/500g,第二家青菜3元/kg。比较哪家便宜,我们自然会想到统一单位,每kg青菜多少钱。 6 | // 同样的道理,我们计算出每单位工作质量的工资(记为w/q->wq),即可对比雇佣谁的性价比更高。 7 | // 由于我们要雇佣 K 名工人,而不是 1 名工人。因此我们需要一个“最大堆”来维护k个数据中总计最小的成本。 8 | 9 | export function mincostToHireWorkers (quality: number[], wage: number[], k: number): number { 10 | // 每个人每单位工作质量需要的工资,为了记录是谁的wq,这里用数组记录[i, wage[i]/quality[i]]。 11 | const wq = new Array(quality.length).fill(0).map((_, index) => [index, wage[index] / quality[index]]).sort((a, b) => a[1] - b[1]) 12 | // 最大堆 13 | const queue = new MaxPriorityQueue() 14 | 15 | let kSum = 0 // 当前窗口值总计 16 | let ans = Number.MAX_VALUE 17 | for (let i = 0; i < wage.length; i++) { 18 | const currQuality = quality[wq[i][0]] 19 | const currWq = wq[i][1] 20 | queue.enqueue(currQuality) 21 | kSum += currQuality 22 | 23 | if (queue.getSize() > k) { 24 | kSum -= queue.dequeue() 25 | } 26 | 27 | if (queue.getSize() === k) { 28 | ans = Math.min(ans, kSum * currWq) 29 | } 30 | } 31 | 32 | return ans 33 | } -------------------------------------------------------------------------------- /src/array/number-of-boomerangs.ts: -------------------------------------------------------------------------------- 1 | // 回旋镖的数量 2 | // https://leetcode.cn/problems/number-of-boomerangs/ 3 | // INLINE ../../images/array/number-of-boomerangs.jpeg 4 | 5 | export function numberOfBoomerangs (points: number[][]): number { 6 | let res = 0 7 | 8 | const dis = (a: number[], b: number[]) => { // 注意,不开方结果一致 9 | return (a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]) 10 | } 11 | 12 | for (let i = 0; i < points.length; i++) { 13 | const map = new Map() 14 | for (let j = 0; j < points.length; j++) { 15 | if (i !== j) { 16 | const d = dis(points[i], points[j]) 17 | const tmp = map.get(d) 18 | if (tmp) { 19 | map.set(d, tmp + 1) 20 | } else { 21 | map.set(d, 1) 22 | } 23 | } 24 | } 25 | 26 | map.forEach(item => { 27 | // if (item >= 2) { // 如果是1,套入公式得到同样结果,因此可以不作判断 28 | res += item * (item - 1) // 排列 3 => 3 * 2, A = n * ( n - 1 ) 29 | // } 30 | }) 31 | } 32 | 33 | return res 34 | } -------------------------------------------------------------------------------- /src/array/number-of-islands.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {character[][]} grid 3 | * @return {number} 4 | */ 5 | export const numIslands = function (grid: any[][]): number { 6 | if (!grid[0]) return 0 7 | const maxN = grid.length - 1 8 | const maxI = grid[0].length - 1 9 | 10 | const overTurn = (n: number, i: number) => { // 沉没上下左右的岛屿 11 | if (Number(grid[n][i]) === 1) { 12 | grid[n][i] = 0 13 | if (i - 1 >= 0) overTurn(n, i - 1) // 上 14 | if (i + 1 <= grid[0].length - 1) overTurn(n, i + 1) // 下 15 | if (n - 1 >= 0) overTurn(n - 1, i) // 左 16 | if (n + 1 <= grid.length - 1) overTurn(n + 1, i) // 右 17 | } 18 | } 19 | 20 | let res = 0 21 | // 1. 遍历所有的点 22 | for (let n = 0; n <= maxN; n++) { 23 | for (let i = 0; i <= maxI; i++) { 24 | if (Number(grid[n][i]) === 1) { // 2. 如果是岛屿,就将其上下左右都为1的岛屿沉没 25 | res++ 26 | overTurn(n, i) 27 | } 28 | } 29 | } 30 | 31 | return res 32 | } 33 | -------------------------------------------------------------------------------- /src/array/partition-array.ts: -------------------------------------------------------------------------------- 1 | // LintCode 31. 数组划分 https://www.lintcode.com/problem/partition-array/description 2 | 3 | export default (nums: number[], k: number) => { 4 | if (nums.length === 0) return 0 5 | 6 | let start = 0 7 | let end = nums.length - 1 8 | 9 | while (start <= end) { 10 | while (start < end && nums[start] < k) { 11 | start++ 12 | } 13 | 14 | while (start <= end && nums[end] >= k) { 15 | end-- 16 | } 17 | 18 | if (start <= end) { 19 | const tmp = nums[start] 20 | nums[start] = nums[end] 21 | nums[end] = tmp 22 | start++ 23 | end-- 24 | } 25 | } 26 | 27 | return start 28 | } -------------------------------------------------------------------------------- /src/array/product-of-array-except-self.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number[]} 4 | */ 5 | export const productExceptSelf = function (nums:number[]):number[] { 6 | const ans = [] 7 | for (let i = 0, len = nums.length; i < len; i++) { 8 | let tmpL = 1 9 | let tmpR = 1 10 | for (let j = 0; j < len; j++) { 11 | if (j < i) { 12 | tmpL *= nums[j] 13 | } else if (j > i) { 14 | tmpR *= nums[j] 15 | } 16 | } 17 | ans.push(tmpL * tmpR) 18 | } 19 | 20 | return ans 21 | } 22 | 23 | // 此算法效率不高,请勿仿照作者偷懒 24 | -------------------------------------------------------------------------------- /src/array/random-pick-with-blacklist.ts: -------------------------------------------------------------------------------- 1 | export class Solution { 2 | private map: Map 3 | private range: number 4 | constructor(n: number, blacklist: number[]) { 5 | this.map = new Map() 6 | this.range = n - blacklist.length 7 | const cantMapSet: Set = new Set() 8 | for (const i of blacklist) { 9 | if (i >= this.range) { 10 | console.log(i) 11 | cantMapSet.add(i) 12 | } 13 | } 14 | 15 | let index = this.range 16 | for (const i of blacklist) { 17 | if (i < this.range) { 18 | while (cantMapSet.has(index)) { 19 | index++ 20 | } 21 | this.map.set(i, index) 22 | index++ 23 | } 24 | } 25 | } 26 | 27 | pick(): number { 28 | const r = Math.floor(Math.random() * this.range) 29 | return this.map.has(r) ? (this.map.get(r) as number) : r 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/array/remove-duplicates-from-sorted-array.ts: -------------------------------------------------------------------------------- 1 | // LeetCode 26. 删除排序数组中的重复项 https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ 2 | // LintCode 100. 删除排序数组中的重复数字 https://www.lintcode.com/problem/remove-duplicates-from-sorted-array/description 3 | 4 | export default (nums:number[]):number => { 5 | if (!nums || (nums && nums.length === 0)) return 0 6 | let i = 0 7 | for (let n = 1, len = nums.length; n < len; n++) { 8 | if (nums[n] !== nums[i]) { 9 | nums[++i] = nums[n] 10 | if (i !== n && n === len - 1) { 11 | nums.splice(n, 1) 12 | } 13 | } 14 | } 15 | 16 | return i + 1 17 | } 18 | -------------------------------------------------------------------------------- /src/array/reverse-pairs.ts: -------------------------------------------------------------------------------- 1 | let count = 0 2 | 3 | export const resetCount = () => { 4 | count = 0 5 | } 6 | 7 | /** 8 | * 归并排序 - 合并左右 9 | */ 10 | export const merge = (left: number[], right: number[]) => { 11 | const res = [] 12 | const leftLength = left.length 13 | const rightLength = right.length 14 | for ( 15 | let index = 0, l = 0, r = 0; 16 | index < leftLength + rightLength; 17 | index++ 18 | ) { 19 | if (l >= leftLength) res[index] = right[r++] 20 | else if (r >= rightLength) res[index] = left[l++] 21 | else if (left[l] <= right[r]) res[index] = left[l++] 22 | else { 23 | res[index] = right[r++] 24 | count += leftLength - l // 唯一与归并排序有差异的地方 25 | } 26 | } 27 | return res 28 | } 29 | 30 | /** 31 | * 归并排序 32 | */ 33 | export const mergeSort = (nums: number[]): number[] => { 34 | if (nums.length < 2) return nums 35 | const mid = ~~(nums.length / 2) 36 | const left = nums.slice(0, mid) 37 | const right = nums.slice(mid) 38 | return merge(mergeSort(left), mergeSort(right)) 39 | } 40 | 41 | /** 42 | * 逆序对 43 | */ 44 | export const reversePairs = function (nums: number[]): number { 45 | resetCount() 46 | mergeSort(nums) 47 | return count 48 | } 49 | -------------------------------------------------------------------------------- /src/array/rotate-array.ts: -------------------------------------------------------------------------------- 1 | // 轮转数组 2 | // https://leetcode.cn/problems/rotate-array/ 3 | 4 | /** 5 | Do not return anything, modify nums in-place instead. 6 | */ 7 | export function rotate (nums: number[], k: number): void { 8 | const len = nums.length 9 | nums.push(...nums) 10 | while (len - k < 0) { 11 | k = k - len 12 | } 13 | nums.splice(0, len - k) 14 | nums.splice(len) 15 | } -------------------------------------------------------------------------------- /src/array/search-in-rotated-sorted-array.ts: -------------------------------------------------------------------------------- 1 | export const search = function (nums: number[], target: number): number { 2 | // 参考 src/array/binary-search.ts 3 | let l = 0 4 | let r = nums.length - 1 5 | while (l <= r) { 6 | const mid = l + ((r - l) >> 1) 7 | if (nums[mid] === target) return mid 8 | 9 | if (nums[l] <= nums[mid]) { 10 | if (nums[mid] > target && nums[l] <= target) { 11 | r = mid - 1 12 | } else { 13 | l = mid + 1 14 | } 15 | } else { 16 | if (nums[mid] < target && nums[r] >= target) { 17 | l = mid + 1 18 | } else { 19 | r = mid - 1 20 | } 21 | } 22 | } 23 | return -1 24 | } 25 | 26 | /** 27 | * @param {number[]} nums 28 | * @param {number} target 29 | * @return {number} 30 | */ 31 | // export const search = (nums, target) => { 32 | // return nums.indexOf(target) 33 | // } 34 | -------------------------------------------------------------------------------- /src/array/search-insert-position.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @param {number} target 4 | * @return {number} 5 | */ 6 | var searchInsert = function (nums:number[], target:number):number { 7 | const res = nums.findIndex(item => item === target) 8 | if (res !== -1) return res 9 | 10 | if (target < nums[0]) return 0 11 | 12 | for (const n in nums) { 13 | if (nums[n] > target) { 14 | return Number(n) 15 | } 16 | } 17 | 18 | return nums.length 19 | } 20 | 21 | export default searchInsert 22 | -------------------------------------------------------------------------------- /src/array/select-sort.ts: -------------------------------------------------------------------------------- 1 | // 选择排序 2 | // 平均时间复杂度 O(n * n), 最好情况 O(n * n),最坏情况 O(n * n) 3 | // 空间复杂度 O(1) 4 | // 稳定 5 | 6 | export default (arr:number[]) => { 7 | for (let n = 0, len = arr.length; n < len; n++) { 8 | let min = arr[n] 9 | for (let i = n + 1; i < len; i++) { 10 | if (arr[i] < min) { 11 | const tmp = min 12 | min = arr[i] 13 | arr[i] = tmp 14 | } 15 | } 16 | arr[n] = min 17 | } 18 | 19 | return arr 20 | } 21 | -------------------------------------------------------------------------------- /src/array/shortest-word-distance.ts: -------------------------------------------------------------------------------- 1 | // 最短单词距离 2 | // https://leetcode.cn/problems/shortest-word-distance/ 3 | // INLINE ../../images/array/shortest-word-distance.jpeg 4 | 5 | export function shortestDistance (wordsDict: string[], word1: string, word2: string): number { 6 | let result = wordsDict.length 7 | let lastTraverseIndex = -1 8 | let index = -1 9 | for (let i = 0; i < wordsDict.length; i++) { 10 | const word = wordsDict[i] 11 | if (word === word1) { 12 | lastTraverseIndex = i 13 | } else if (word === word2) { 14 | index = i 15 | } 16 | 17 | if (lastTraverseIndex >= 0 && index >= 0) { 18 | result = Math.min(result, Math.abs(index - lastTraverseIndex)) 19 | } 20 | } 21 | 22 | return result 23 | } -------------------------------------------------------------------------------- /src/array/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number[]} 4 | */ 5 | export const singleNumbers = function (nums:number[]):number[] { 6 | const ab = nums.reduce((a, b) => a ^ b) 7 | const diff = ab & -ab 8 | const num1 = nums.reduce((a, n) => n & diff ? a ^ n : a, 0) 9 | 10 | return [num1, ab ^ num1] 11 | } 12 | -------------------------------------------------------------------------------- /src/array/single-number.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number} 4 | */ 5 | export var singleNumber = function (nums:number[]):number { 6 | return nums.reduce((a, b) => a ^ b) 7 | } 8 | -------------------------------------------------------------------------------- /src/array/sort-array-by-parity.ts: -------------------------------------------------------------------------------- 1 | // LeetCode 922. 按奇偶排序数组 II https://leetcode-cn.com/problems/sort-array-by-parity-ii/ 2 | 3 | export default (arr: number[]) => { 4 | arr = arr.sort((a, b) => a - b) 5 | 6 | const r: number[] = [] 7 | let odd = 1 8 | let even = 0 9 | arr.forEach(item => { 10 | if (item % 2 === 1) { 11 | r[odd] = item 12 | odd += 2 13 | } else { 14 | r[even] = item 15 | even += 2 16 | } 17 | }) 18 | 19 | return r 20 | } 21 | -------------------------------------------------------------------------------- /src/array/sort-transformed-array.ts: -------------------------------------------------------------------------------- 1 | // 有序转化数组 2 | // https://leetcode.cn/problems/sort-transformed-array/ 3 | // 解题思路:借助一元二次方程性质,双指针从两头开始计算,每次保存两端值较小的一个到结果,不必事先计算中线。 4 | // a > 0 向上抛物线,两边大中间小。从后向前存储(升序,大的值在数组末尾,所以逆序保存)。 5 | // a < 0 向下抛物线,两边小中间大。从前往后存储。 6 | // a = 0 取决于b单调递增/递减。 7 | 8 | export function sortTransformedArray (nums: number[], a: number, b: number, c: number): number[] { 9 | const fx = (x: number) => a * x * x + b * x + c 10 | let left = 0 11 | let right = nums.length - 1 12 | let index = a > 0 ? right : left 13 | const res = new Array(nums.length) 14 | while (left <= right) { 15 | const leftVal = fx(nums[left]) 16 | const rightVal = fx(nums[right]) 17 | if (a > 0) { 18 | if (leftVal > rightVal) { 19 | res[index--] = leftVal 20 | left++ 21 | } else { 22 | res[index--] = rightVal 23 | right-- 24 | } 25 | } else { 26 | if (rightVal < leftVal) { 27 | res[index++] = rightVal 28 | right-- 29 | } else { 30 | res[index++] = leftVal 31 | left++ 32 | } 33 | } 34 | } 35 | 36 | return res 37 | } -------------------------------------------------------------------------------- /src/array/special-positions-in-a-binary-matrix.ts: -------------------------------------------------------------------------------- 1 | // 二进制矩阵中的特殊位置 2 | // https://leetcode.cn/problems/special-positions-in-a-binary-matrix 3 | // INLINE ../../images/array/special-positions-in-a-binary-matrix.jpeg 4 | // 解题思路:参见官方题解2及注释 5 | 6 | export function numSpecial (mat: number[][]): number { 7 | const m = mat.length 8 | const n = mat[0].length 9 | 10 | for (let i = 0; i < m; i++) { 11 | let rowCount = 0 12 | for (let j = 0; j < n; j++) { // 遍历行,统计该行出现1的次数 13 | if (mat[i][j] === 1) { 14 | rowCount++ 15 | } 16 | } 17 | 18 | if (i === 0) { // * 这里是最难理解的。本来是要用第0行作为每一列有多少个1的计数,因此计数前本应该对该行先清0,再记录该行对应列出现了几次1,由于只对有1的列做计数,直接减去1避开了清0操作 19 | rowCount-- // 即 rowCount = rowCount - 1 20 | } 21 | 22 | if (rowCount > 0) { // 如果该行出现1的次数 > 0 23 | for (let j = 0; j < n; j++) { // 遍历行,得到1所在的列,对出现大于1的列做累计计数 24 | if (mat[i][j] === 1) { 25 | mat[0][j] += rowCount 26 | } 27 | } 28 | } 29 | } 30 | 31 | return mat[0].reduce((prev, curr) => curr === 1 ? prev + 1 : prev, 0) 32 | } -------------------------------------------------------------------------------- /src/array/spiral-matrix.ts: -------------------------------------------------------------------------------- 1 | // 螺旋矩阵 2 | // https://leetcode.cn/problems/spiral-matrix/ 3 | // INLINE ../../images/array/spiral-matrix.jpeg 4 | 5 | export function spiralOrder (matrix: number[][]): number[] { 6 | if (!matrix.length || !matrix[0].length) return [] 7 | const row = matrix.length 8 | const col = matrix[0].length 9 | const result: number[] = [] 10 | 11 | let left = 0 12 | let right = col - 1 13 | let top = 0 14 | let bottom = row - 1 15 | 16 | while (left <= right && top <= bottom) { 17 | for (let i = left; i <= right; ++i) { 18 | result.push(matrix[top][i]) 19 | } 20 | 21 | for (let i = top + 1; i <= bottom; ++i) { 22 | result.push(matrix[i][right]) 23 | } 24 | 25 | if (left < right && top < bottom) { 26 | for (let i = right - 1; i > left; --i) { 27 | result.push(matrix[bottom][i]) 28 | } 29 | 30 | for (let i = bottom; i > top; --i) { 31 | result.push(matrix[i][left]) 32 | } 33 | } 34 | 35 | left++ 36 | right-- 37 | top++ 38 | bottom-- 39 | } 40 | 41 | return result 42 | } -------------------------------------------------------------------------------- /src/array/subarray-sums-divisible-by-k.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} A 3 | * @param {number} K 4 | * @return {number} 5 | */ 6 | export const subarraysDivByK = function (A:number[], K:number):number { 7 | const map = new Map([[0, 1]]); let sum = 0; let count = 0 8 | 9 | A.forEach(n => { 10 | sum = (sum + n) % K; sum = sum < 0 ? sum + K : sum 11 | const temp = map.get(sum) || 0 12 | count += temp 13 | map.set(sum, temp + 1) 14 | }) 15 | 16 | return count 17 | } 18 | -------------------------------------------------------------------------------- /src/array/wiggle-sort-ii.ts: -------------------------------------------------------------------------------- 1 | /** 2 | Do not return anything, modify nums in-place instead. 3 | */ 4 | export function wiggleSort (nums: number[]): void { 5 | const [...cp] = nums, n = nums.length 6 | cp.sort((a, b) => a - b) 7 | for (let i = Math.floor((n + 1) / 2) - 1, j = n - 1, idx = 0; idx < n; idx++, i--, j--) { 8 | nums[idx++] = cp[i] 9 | if (idx < n) nums[idx] = cp[j] 10 | } 11 | } -------------------------------------------------------------------------------- /src/array/x-of-a-kind-in-a-deck-of-cards.ts: -------------------------------------------------------------------------------- 1 | // LeetCode 914. 卡牌分组 https://leetcode-cn.com/problems/x-of-a-kind-in-a-deck-of-cards/ 2 | 3 | // 分组问题,最大公约数 4 | 5 | const gcd = (a: number, b: number): number => { 6 | if (Number(b) === 0) { 7 | return Number(a) 8 | } else { 9 | return gcd(b, a % b) 10 | } 11 | } 12 | 13 | export default function hasGroupsSizeX (deck: number[]): boolean { 14 | const str = deck.sort((a, b) => a - b).join(',') + ',' 15 | 16 | const group = str.match(/(\d+,)\1+|\d+,/g) 17 | 18 | while (group && group.length > 1) { 19 | const a = group.shift()!.split(',').length - 1 20 | const b = group.shift()!.split(',').length - 1 21 | 22 | const v = gcd(a, b) 23 | 24 | if (v === 1) { 25 | return false 26 | } else { 27 | group.unshift('0,'.repeat(v)) 28 | } 29 | } 30 | 31 | return group?.length ? group[0].split(',').length > 2 : false 32 | } 33 | -------------------------------------------------------------------------------- /src/array/zigzag-conversion.ts: -------------------------------------------------------------------------------- 1 | export function convert (s: string, numRows: number): string { 2 | if (numRows === 1) return s 3 | const res = new Array(numRows).fill('') 4 | 5 | for (let i = 0, len = s.length, isDown = true, row = 0; i < len; i++) { 6 | res[isDown ? row++ : row--] += s[i] 7 | 8 | if (row === numRows - 1) { 9 | isDown = false 10 | } else if (row === 0) { 11 | isDown = true 12 | } 13 | } 14 | 15 | return res.join('') 16 | } -------------------------------------------------------------------------------- /src/graphs/course-schedule-ii.ts: -------------------------------------------------------------------------------- 1 | export const findOrder = function (numCourses: number, prerequisites: number[][]): number[] { 2 | const courses = Array(numCourses).fill(0) // 初始化 上课 需要先完成课程 的门数 3 | const obj: any = {} // 记录受该课程 影响的其他课 4 | prerequisites.forEach(item => { 5 | const one = item[0]; const two = item[1] // one 要上的课, two 需先完成的课 6 | courses[one]++ // 门数 + 1 7 | obj[two] ? obj[two].push(one) : obj[two] = [one] // 存在就加, 不存在就新建 8 | }) 9 | const res: number[] = [] 10 | const queue: number[] = [] // 队列 11 | courses.forEach((t, i) => { // 往队列添加 无需先上 就可以 上 的课 12 | if (t === 0) queue.push(i) // 因为是从0开始的, 所以索引也能代替 课的名称 13 | }) 14 | while (queue.length) { 15 | const cur = queue.shift() as number // 出队 表示该课已经上了 16 | res.push(cur) // 把出队的放入 结果数组 17 | const list = obj[cur] // 获取受该课影响的 课 18 | list && list.forEach((item: number) => { 19 | courses[item]-- // 因为 出队表示该课已经上了, 所以 要先完成的门数 - 1 20 | if (courses[item] === 0) { // 当这个课 要先修完的 已经修完了, 入队 21 | queue.push(item) 22 | } 23 | }) 24 | } 25 | 26 | return res.length === numCourses ? res : [] 27 | } 28 | 29 | // 参考自 https://leetcode-cn.com/problems/course-schedule-ii/solution/chao-da-an-by-shetia/ 30 | -------------------------------------------------------------------------------- /src/graphs/find-the-town-judge.ts: -------------------------------------------------------------------------------- 1 | // 找到小镇的法官 2 | // https://leetcode.cn/problems/find-the-town-judge 3 | // INLINE ../../images/graphs/find-the-town-judge.jpeg 4 | 5 | export function findJudge (n: number, trust: number[][]): number { 6 | const inDegrees = new Array(n + 1).fill(0) 7 | const outDegrees = new Array(n + 1).fill(0) 8 | 9 | for (const edge of trust) { 10 | ++inDegrees[edge[1]] 11 | ++outDegrees[edge[0]] 12 | } 13 | 14 | for (let i = 1; i <= n; i++) { 15 | if (inDegrees[i] === n - 1 && outDegrees[i] === 0) { 16 | return i 17 | } 18 | } 19 | 20 | return -1 21 | } -------------------------------------------------------------------------------- /src/lib/ListNode.ts: -------------------------------------------------------------------------------- 1 | export default class ListNode { 2 | val: number 3 | next: ListNode | null 4 | constructor (val?: number, next?: ListNode | null) { 5 | this.val = (val === undefined ? 0 : val) 6 | this.next = (next === undefined ? null : next) 7 | } 8 | } 9 | 10 | export const arrToList = (arr: number[]): ListNode | null => { 11 | if (!arr[0]) return null 12 | const head = new ListNode(arr[0]) 13 | let current = head 14 | for (let n = 1, len = arr.length; n < len; n++) { 15 | current.next = new ListNode(arr[n]) 16 | current = current.next 17 | } 18 | 19 | return head 20 | } 21 | 22 | export const listToArr = (list: ListNode | null): number[] => { 23 | const arr: number[] = [] 24 | while (list !== null) { 25 | arr.push(list.val) 26 | list = list.next 27 | } 28 | 29 | return arr 30 | } 31 | -------------------------------------------------------------------------------- /src/lib/MaxPriorityQueue.ts: -------------------------------------------------------------------------------- 1 | import Heap from "./Heap" 2 | 3 | export class MaxPriorityQueue { 4 | private maxHeap: Heap 5 | 6 | public constructor () { 7 | this.maxHeap = new Heap('Max') 8 | } 9 | 10 | 11 | getSize (): number { 12 | return this.maxHeap.size 13 | } 14 | 15 | isEmpty (): boolean { 16 | return this.maxHeap.isEmpty() 17 | } 18 | 19 | enqueue (e: T): void { 20 | this.maxHeap.insert(e) 21 | } 22 | 23 | dequeue (): T { 24 | return this.maxHeap.extract() as T 25 | } 26 | 27 | 28 | peek (): T | null { 29 | return this.maxHeap.peek() as T 30 | } 31 | } -------------------------------------------------------------------------------- /src/lib/MinPriorityQueue.ts: -------------------------------------------------------------------------------- 1 | import Heap from "./Heap" 2 | 3 | export class MinPriorityQueue { 4 | private minHeap: Heap 5 | 6 | public constructor () { 7 | this.minHeap = new Heap('Min') 8 | } 9 | 10 | 11 | getSize (): number { 12 | return this.minHeap.size 13 | } 14 | 15 | isEmpty (): boolean { 16 | return this.minHeap.isEmpty() 17 | } 18 | 19 | enqueue (e: T): void { 20 | this.minHeap.insert(e) 21 | } 22 | 23 | dequeue (): T | null { 24 | return this.minHeap.extract() as T 25 | } 26 | 27 | 28 | peek (): T | null { 29 | return this.minHeap.peek() as T 30 | } 31 | } -------------------------------------------------------------------------------- /src/lib/TreeNode.ts: -------------------------------------------------------------------------------- 1 | export class TreeNode { 2 | val: number 3 | left: TreeNode | null 4 | right: TreeNode | null 5 | constructor (val?: number, left?: TreeNode | null, right?: TreeNode | null) { 6 | this.val = (val === undefined ? 0 : val) 7 | this.left = (left === undefined ? null : left) 8 | this.right = (right === undefined ? null : right) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/splice.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 移除指定位置的元素 3 | * @param arr 数组 4 | * @param index 数组下标 5 | * @returns 删除了元素后的数组 6 | */ 7 | export const removeItem = (arr: any[], index: number) => { 8 | arr.splice(index, 1) 9 | return arr 10 | } 11 | 12 | /** 13 | * 在指定位置添加元素 14 | * @param arr 数组 15 | * @param index 数组下标 16 | * @param item 需要增加的元素 17 | * @return 添加了元素后的组数 18 | */ 19 | export const putItem = (arr: any[], index: number, item: any) => { 20 | arr.splice(index, 0, item) 21 | return arr 22 | } -------------------------------------------------------------------------------- /src/list/delete-node-in-a-linked-list.ts: -------------------------------------------------------------------------------- 1 | // 删除链表中的节点 2 | // https://leetcode.cn/problems/delete-node-in-a-linked-list/ 3 | // INLINE ../../images/list/delete-node-in-a-linked-list.jpeg 4 | 5 | import ListNode from "../lib/ListNode" 6 | 7 | /** 8 | Do not return anything, modify it in-place instead. 9 | */ 10 | export function deleteNode (node: ListNode | null): void { 11 | if (node === null) { 12 | return 13 | } 14 | if (node.next === null) { 15 | node = null 16 | return 17 | } 18 | node.val = node.next.val 19 | node.next = node.next.next 20 | } -------------------------------------------------------------------------------- /src/list/linked-list-cycle.ts: -------------------------------------------------------------------------------- 1 | import ListNode from '../lib/ListNode' 2 | 3 | // export const hasCycle = function (head: ListNode | null): boolean { 4 | // const set = new Set() 5 | // let current = head 6 | // while (current && current.next !== null) { 7 | // if (set.has(current)) { 8 | // return true 9 | // } 10 | // set.add(current) 11 | // current = current.next 12 | // } 13 | // return false 14 | // } 15 | 16 | export const hasCycle = function (head: ListNode | null): boolean { 17 | let slow = head 18 | let fast = head?.next 19 | while (slow?.next && fast?.next?.next) { 20 | if (fast.next === slow || slow === fast) return true 21 | slow = slow.next 22 | fast = fast.next.next 23 | } 24 | return false 25 | } 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/list/merge-two-sorted-lists.ts: -------------------------------------------------------------------------------- 1 | import ListNode from "../lib/ListNode" 2 | 3 | export const mergeTwoLists = function (l1: ListNode | null, l2: ListNode | null): ListNode | null { 4 | // src/list/merge-k-sorted-lists.ts 中已经写过了 5 | const dummyHead = new ListNode() 6 | let current = dummyHead 7 | while (l1 !== null && l2 !== null) { 8 | if (l1.val < l2.val) { 9 | if (l1.val !== null) { 10 | current.next = l1 11 | current = current.next 12 | } 13 | 14 | l1 = l1.next 15 | } else { 16 | if (l2.val !== null) { 17 | current.next = l2 18 | current = current.next 19 | } 20 | 21 | l2 = l2.next 22 | } 23 | } 24 | 25 | if (l1 === null) { 26 | current.next = l2 27 | } else { 28 | current.next = l1 29 | } 30 | 31 | return dummyHead.next 32 | } 33 | -------------------------------------------------------------------------------- /src/list/middle-of-the-linked-list.ts: -------------------------------------------------------------------------------- 1 | import ListNode from "../lib/ListNode" 2 | 3 | /** 4 | * @param {ListNode} head 5 | * @return {ListNode} 6 | */ 7 | export const middleNode = function (head: ListNode | null): ListNode | null { 8 | if (!head?.next) return head 9 | if (head.next && !head.next.next) return head.next 10 | 11 | let slow = head 12 | let fast = head.next.next 13 | 14 | while (fast && fast.next && fast.next.next && slow.next) { 15 | slow = slow.next 16 | fast = fast.next.next 17 | } 18 | 19 | return fast!.next ? slow!.next!.next : slow!.next 20 | } 21 | -------------------------------------------------------------------------------- /src/list/reverse-linked-list.ts: -------------------------------------------------------------------------------- 1 | // 反转链表 2 | // https://leetcode.cn/problems/reverse-linked-list/ 3 | // INLINE ../../images/sort/reverse-linked-list.jpeg 4 | 5 | import ListNode from "../lib/ListNode" 6 | 7 | export function reverseList (head: ListNode | null): ListNode | null { 8 | let first = null 9 | let second = head 10 | while (second !== null) { 11 | let third = second.next 12 | second.next = first 13 | first = second 14 | second = third 15 | } 16 | return first 17 | } -------------------------------------------------------------------------------- /src/list/sort-list.ts: -------------------------------------------------------------------------------- 1 | import ListNode from '../lib/ListNode' 2 | import { mergeTwoLists } from './merge-two-sorted-lists' 3 | 4 | export const sortList = function (head: ListNode | null): ListNode | null { 5 | if (head === null || head.next === null) return head 6 | 7 | let slow: ListNode | null = head 8 | let fast: ListNode | null = head 9 | while (fast !== null) { 10 | fast = fast.next 11 | fast = fast !== null ? fast.next : null 12 | if (fast !== null) { 13 | slow = slow!.next 14 | } 15 | } 16 | const half = slow!.next 17 | slow!.next = null 18 | const left = sortList(head) 19 | const right = sortList(half) 20 | return mergeTwoLists(left, right) 21 | } 22 | -------------------------------------------------------------------------------- /src/list/swap-nodes-in-pairs.ts: -------------------------------------------------------------------------------- 1 | import ListNode from "../lib/ListNode" 2 | 3 | export function swapPairs (head: ListNode | null): ListNode | null { 4 | if (!head || !head.next) return head 5 | 6 | let prev = head.next 7 | let next = prev.next 8 | 9 | prev.next = head 10 | head.next = swapPairs(next) 11 | 12 | return prev 13 | } -------------------------------------------------------------------------------- /src/map/check-if-one-string-swap-can-make-strings-equal.ts: -------------------------------------------------------------------------------- 1 | // 仅执行一次字符串交换能否使两个字符串相等 2 | // https://leetcode.cn/problems/check-if-one-string-swap-can-make-strings-equal 3 | // INLINE ../../images/map/check-if-one-string-swap-can-make-strings-equal.jpeg 4 | 5 | export function areAlmostEqual (s1: string, s2: string): boolean { 6 | if (s1 === s2) return true 7 | const diffIndex = [] 8 | for (let i = 0; i < s1.length; i++) { 9 | if (s1[i] !== s2[i]) { 10 | if (diffIndex.length == 2) { 11 | return false 12 | } 13 | diffIndex.push(i) 14 | } 15 | } 16 | 17 | if (diffIndex.length !== 2) return false 18 | return s1[diffIndex[0]] === s2[diffIndex[1]] && s2[diffIndex[0]] === s1[diffIndex[1]] 19 | } -------------------------------------------------------------------------------- /src/map/largest-substring-between-two-equal-characters.ts: -------------------------------------------------------------------------------- 1 | // 两个相同字符之间的最长子字符串 2 | // https://leetcode.cn/problems/largest-substring-between-two-equal-characters 3 | // INLINE ../../images/map/largest-substring-between-two-equal-characters.jpeg 4 | 5 | export function maxLengthBetweenEqualCharacters (s: string): number { 6 | let res = -1 7 | const map = new Map() 8 | for (let i = 0; i < s.length; i++) { 9 | if (map.has(s.charAt(i))) { 10 | res = Math.max(res, i - (map.get(s.charAt(i)) as number) - 1) 11 | } else { 12 | map.set(s.charAt(i), i) 13 | } 14 | } 15 | return res 16 | } -------------------------------------------------------------------------------- /src/map/longest-substring-with-at-most-k-distinct-characters.ts: -------------------------------------------------------------------------------- 1 | // 至多包含 K 个不同字符的最长子串 2 | // https://leetcode.cn/problems/longest-substring-with-at-most-k-distinct-characters/ 3 | // INLINE ../../images/map/longest-substring-with-at-most-k-distinct-characters.jpeg 4 | // 解题思路:滑动窗口 5 | 6 | export function lengthOfLongestSubstringKDistinct (s: string, k: number): number { 7 | let left = 0, right = 0 // 左右边界 8 | const map = new Map() // 记录在k范围内每个字符出现的次数 9 | let ans = 0 10 | while (right <= s.length) { 11 | if (map.size <= k) { 12 | if (map.has(s[right])) { 13 | map.set(s[right], map.get(s[right]) as number + 1) 14 | } else { 15 | map.set(s[right], 1) 16 | } 17 | ans = Math.max(ans, right - left) // ? 18 | right++ 19 | } else { // map.size > k 20 | const count = map.get(s[left]) as number - 1 21 | if (count > 0) { 22 | map.set(s[left], count) 23 | } else { 24 | map.delete(s[left]) 25 | } 26 | left++ 27 | } 28 | } 29 | 30 | return ans 31 | } -------------------------------------------------------------------------------- /src/map/remove-letter-to-equalize-frequency.ts: -------------------------------------------------------------------------------- 1 | // 删除字符使频率相同 2 | // https://leetcode.cn/problems/remove-letter-to-equalize-frequency 3 | // INLINE ../../images/map/remove-letter-to-equalize-frequency.jpeg 4 | 5 | export function equalFrequency (word: string): boolean { 6 | const charCount = new Array(26).fill(0) 7 | for (const c of word) { 8 | charCount[c.charCodeAt(0) - 'a'.charCodeAt(0)]++ 9 | } 10 | const freqCount = new Map() 11 | for (const c of charCount) { 12 | if (c > 0) { 13 | freqCount.set(c, (freqCount.get(c) || 0) + 1) 14 | } 15 | } 16 | for (const c of charCount) { 17 | if (c == 0) { 18 | continue 19 | } 20 | freqCount.set(c, freqCount.get(c) - 1) 21 | if (freqCount.get(c) == 0) { 22 | freqCount.delete(c) 23 | } 24 | if (c - 1 > 0) { 25 | freqCount.set(c - 1, (freqCount.get(c - 1) || 0) + 1) 26 | } 27 | if (freqCount.size == 1) { 28 | return true 29 | } 30 | if (c - 1 > 0) { 31 | freqCount.set(c - 1, freqCount.get(c - 1) - 1) 32 | if (freqCount.get(c - 1) == 0) { 33 | freqCount.delete(c - 1) 34 | } 35 | } 36 | /* istanbul ignore next */ 37 | freqCount.set(c, (freqCount.get(c) || 0) + 1) 38 | } 39 | return false 40 | } 41 | -------------------------------------------------------------------------------- /src/math/3sum.ts: -------------------------------------------------------------------------------- 1 | // 多次遇到。复制自:https://leetcode-cn.com/problems/3sum/solution/three-sum-ti-jie-by-wonderful611/ 2 | /** 3 | * @param {number[]} nums 4 | * @return {number[][]} 5 | */ 6 | export const threeSum = function (nums: number[]) { 7 | const res = [] 8 | const length = nums.length 9 | nums.sort((a, b) => a - b) // 先排个队,最左边是最弱(小)的,最右边是最强(大)的 10 | if (nums[0] <= 0 && nums[length - 1] >= 0) { // 优化1: 整个数组同符号,则无解 11 | for (let i = 0; i < length - 2;) { 12 | if (nums[i] > 0) break // 优化2: 最左值为正数则一定无解 13 | let first = i + 1 14 | let last = length - 1 15 | do { 16 | if (first >= last || nums[i] * nums[last] > 0) break // 两人选相遇,或者三人同符号,则退出 17 | const result = nums[i] + nums[first] + nums[last] 18 | if (result === 0) { // 如果可以组队 19 | res.push([nums[i], nums[first], nums[last]]) 20 | } 21 | if (result <= 0) { // 实力太弱,把菜鸟那边右移一位 22 | while (first < last && nums[first] === nums[++first]) { } // 如果相等就跳过 23 | } else { // 实力太强,把大神那边右移一位 24 | while (first < last && nums[last] === nums[--last]) { } 25 | } 26 | } while (first < last) 27 | while (nums[i] === nums[++i]) { } 28 | } 29 | } 30 | return res 31 | } 32 | -------------------------------------------------------------------------------- /src/math/add-binary.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} a 3 | * @param {string} b 4 | * @return {string} 5 | */ 6 | export const addBinary = function (a: string, b: string) { 7 | // eslint-disable-next-line no-undef 8 | return (BigInt('0b' + a) + BigInt('0b' + b)).toString(2) 9 | } 10 | -------------------------------------------------------------------------------- /src/math/coin-lcci.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 参考:https://leetcode-cn.com/problems/coin-lcci/solution/jian-dan-de-shu-xue-jia-fa-by-zindler/ 3 | * @param {number} n 4 | * @return {number} 5 | */ 6 | export const waysToChange = function (n: number) { 7 | const mod = 1e9 + 7 8 | let res = 0 9 | for (let i = 0; i <= ~~(n / 25); i++) { 10 | const a = ~~((n - i * 25) / 10) 11 | const t = (a + 1) * (~~(n / 5) - 5 * i - a + 1) 12 | res = (res + t) % mod 13 | } 14 | return res 15 | } 16 | -------------------------------------------------------------------------------- /src/math/factorial-trailing-zeroes.ts: -------------------------------------------------------------------------------- 1 | // LeetCode 172. 阶乘后的零 https://leetcode-cn.com/problems/factorial-trailing-zeroes/submissions/ 2 | // LintCode 2. 尾部的零 https://www.lintcode.com/problem/trailing-zeros/description 3 | 4 | export default (n: number) => { 5 | let sum = 0 6 | while (n !== 0) { 7 | sum += Math.floor(n /= 5) 8 | } 9 | return sum 10 | } 11 | -------------------------------------------------------------------------------- /src/math/maximum-lcci.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} a 3 | * @param {number} b 4 | * @return {number} 5 | */ 6 | export const maximum = function (a: number, b: number) { 7 | // return Math.max(a, b) 8 | // 不得使用if-else或其他比较运算符,那么我们也尽可能回避abs、max这些函数 9 | // return (a + b) / 2 + Math.abs(a - b) / 2 10 | // return (a + b) / 2 + Math.abs(a - (a + b) / 2) 11 | // return ((a + b) + Math.abs(a - b)) / 2 12 | 13 | // 1.两个符号相同不会溢出,符号不同可能溢出 14 | // 2.所以的分别对a,b两值的符号位求异或 15 | // 3.符号相同直接取k,符号不同,判断a的符号位 16 | const ak = a >>> 63 17 | const bk = b >>> 63 // 符号位 18 | const diff = ak ^ bk// 求异或,相同为0,不同为1 19 | let k = (a - b) >>> 63 20 | // 如果符号相同就取k,符号不同就判断ak符号得出k,是0还是1 21 | k = k & (diff ^ 1) | (ak & diff) 22 | return b * k + a * (k ^ 1) 23 | 24 | // const k = ((a - b) >> 63) & 1 25 | // return b * k + a * (k ^ 1) 26 | 27 | // const k = (a - b) >>> 63 28 | // return b * k + a * (k ^ 1) 29 | 30 | // k就是把符号位取出来,1是负数,0是正数。负数说明b大,所以b*1+a*0不就是b吗。反之,如果是正数,说明a大,那么就是b*0+a*1就等于 a了。 31 | } 32 | -------------------------------------------------------------------------------- /src/math/next-greater-element-iii.ts: -------------------------------------------------------------------------------- 1 | // 下一个更大元素 III 2 | // https://leetcode.cn/problems/next-greater-element-iii 3 | // 解题思路:参考 31. 下一个排列 4 | 5 | const reverse = (nums: string[], begin: number) => { 6 | let i = begin, j = nums.length - 1 7 | while (i < j) { 8 | [nums[i], nums[j]] = [nums[j], nums[i]] 9 | i++ 10 | j-- 11 | } 12 | } 13 | 14 | export function nextGreaterElement (n: number): number { 15 | const numStrArr = [...n.toString()] 16 | let i = numStrArr.length - 2 17 | while (i >= 0 && numStrArr[i + 1] <= numStrArr[i]) { 18 | i-- 19 | } 20 | 21 | if (i < 0) return -1 22 | 23 | let j = numStrArr.length - 1 24 | while (j >= 0 && numStrArr[i] >= numStrArr[j]) { j-- } 25 | ;[numStrArr[i], numStrArr[j]] = [numStrArr[j], numStrArr[i]] 26 | reverse(numStrArr, i + 1) 27 | const res = Number(numStrArr.join('')) 28 | return res > 2 ** 31 - 1 ? -1 : res 29 | } -------------------------------------------------------------------------------- /src/math/palindrome-number.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} x 3 | * @return {boolean} 4 | */ 5 | export const isPalindrome = function (x: number) { 6 | if (x < 0 || (x % 10 === 0 && x !== 0)) return false // 如果末尾数为0且不是0 7 | 8 | let reverse = 0 9 | 10 | while (reverse < x) { 11 | reverse = reverse * 10 + x % 10 12 | x = x / 10 | 0 13 | } 14 | 15 | return reverse === x || (reverse / 10 | 0) === x 16 | } 17 | -------------------------------------------------------------------------------- /src/math/perfect-number.ts: -------------------------------------------------------------------------------- 1 | const pn = (p: number) => { // 欧几里得-欧拉定理 2 | return (1 << (p - 1)) * ((1 << p) - 1) 3 | } 4 | 5 | /** 6 | * @param {number} num 7 | * @return {boolean} 8 | */ 9 | export const checkPerfectNumber = function (num: number) { 10 | const primes = [2, 3, 5, 7, 13, 17, 19, 31] 11 | for (const prime of primes) { 12 | if (pn(prime) === num) return true 13 | } 14 | 15 | return false 16 | } 17 | -------------------------------------------------------------------------------- /src/math/permutations.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number[][]} 4 | */ 5 | export const permute = function (nums: number[]): number[][] { 6 | const res: number[][] = [] 7 | const backtrack = (path: number[] = []) => { 8 | if (path.length === nums.length) res.push(path) 9 | for (const n of nums) { 10 | !path.includes(n) && backtrack(path.concat(n)) 11 | } 12 | } 13 | backtrack() 14 | return res 15 | } 16 | -------------------------------------------------------------------------------- /src/math/powx-n.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} x 3 | * @param {number} n 4 | * @return {number} 5 | */ 6 | export const myPow = function (x:number, n:number) { // 参考:快速幂 + 迭代 https://leetcode-cn.com/problems/powx-n/solution/powx-n-by-leetcode-solution/ 7 | let ans = 1.0 // 答案 8 | 9 | if (n < 0) { // 如果 n 为负 10 | n = -n // 将 n 变为正 11 | x = 1.0 / x // 2^-2 = 1/(2^2) = 1/4 = 0.25 12 | } 13 | 14 | while (n > 0) { 15 | if (n & 1) ans *= x // 如果n的二进制最后一位为1,则计入贡献 16 | x *= x // 将贡献不断平方 17 | n >>>= 1 // 无符号右移一位,相当于 n = n / 2 | 0 ,去掉二进制的最后一位,相当于下一次判断倒数第二位 18 | } 19 | 20 | return ans.toFixed(5) 21 | } 22 | -------------------------------------------------------------------------------- /src/math/subarray-sum-equals-k.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @param {number} k 4 | * @return {number} 5 | */ 6 | export const subarraySum = function (nums: number[], k: number) { 7 | const map = new Map() 8 | let sum = 0 9 | let res = 0 10 | 11 | nums.forEach((n, index) => { 12 | sum += n 13 | if (sum === k) res++ 14 | const subSum = sum - k 15 | let value = [] 16 | if (map.has(subSum)) res += map.get(subSum).length 17 | if (map.has(sum)) { 18 | value = map.get(sum) 19 | } 20 | value.push(index) 21 | map.set(sum, value) 22 | }) 23 | 24 | return res 25 | } 26 | -------------------------------------------------------------------------------- /src/math/ugly-number-ii.ts: -------------------------------------------------------------------------------- 1 | export const nthUglyNumber = function (n: number) { 2 | const res = [1] 3 | let inx2 = 0 4 | let inx3 = 0 5 | let inx5 = 0 6 | 7 | for (let i = 1; i < n; i++) { 8 | const temp2 = res[inx2] * 2 9 | const temp3 = res[inx3] * 3 10 | const temp5 = res[inx5] * 5 11 | const min = Math.min(temp2, temp3, temp5) 12 | if (min === temp2) inx2++ 13 | if (min === temp3) inx3++ 14 | if (min === temp5) inx5++ 15 | 16 | res.push(min) 17 | } 18 | 19 | return res[n - 1] || 0 20 | } 21 | 22 | // 思路: 23 | // 一开始,丑数只有{1},1可以同2,3,5相乘,取最小的1×2=2添加到丑数序列中。 24 | 25 | // 现在丑数中有{1,2},在上一步中,1已经同2相乘过了,所以今后没必要再比较1×2了,我们说1失去了同2相乘的资格。 26 | 27 | // 现在1有与3,5相乘的资格,2有与2,3,5相乘的资格,但是2×3和2×5是没必要比较的,因为有比它更小的1可以同3,5相乘,所以我们只需要比较1×3,1×5,2×2。 28 | 29 | // 依此类推,每次我们都分别比较有资格同2,3,5相乘的最小丑数,选择最小的那个作为下一个丑数,假设选择到的这个丑数是同i(i=2,3,5)相乘得到的,所以它失去了同i相乘的资格,把对应的pi++,让pi指向下一个丑数即可。 30 | 31 | // 作者:zzxn 32 | // 链接:https://leetcode-cn.com/problems/ugly-number-ii/solution/san-zhi-zhen-fang-fa-de-li-jie-fang-shi-by-zzxn/ 33 | // 来源:力扣(LeetCode) 34 | // 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 35 | -------------------------------------------------------------------------------- /src/math/ugly-number.ts: -------------------------------------------------------------------------------- 1 | // 丑数 2 | // https://leetcode.cn/problems/ugly-number/ 3 | // INLINE ../../images/math/ugly-number.jpeg 4 | 5 | export function isUgly (n: number): boolean { 6 | if (n <= 0) return false 7 | for (const i of [2, 3, 5]) { 8 | while (n % i === 0) { 9 | n = n / i 10 | } 11 | } 12 | return n === 1 13 | } -------------------------------------------------------------------------------- /src/other/minimum-number-of-refueling-stops.ts: -------------------------------------------------------------------------------- 1 | // 最低加油次数 2 | // https://leetcode.cn/problems/minimum-number-of-refueling-stops 3 | // 解题思路:https://leetcode.cn/problems/minimum-number-of-refueling-stops/solution/javascript-tan-xin-by-younglina-coz4/ 4 | 5 | import { MaxPriorityQueue } from "../lib/MaxPriorityQueue" 6 | 7 | export function minRefuelStops (target: number, startFuel: number, stations: number[][]): number { 8 | // 贪心算法 9 | // 所有油都带上,油用完时,取最大的油加上 10 | let maxPriorityQueue = new MaxPriorityQueue() // 最大优先队列 11 | let res = 0, total = 0, idx = 0, len = stations.length 12 | while (total < target) { 13 | if (startFuel === 0) { 14 | if (maxPriorityQueue.getSize()) { 15 | // 油用完,并且队列还有油,就取出最大的加一次油 16 | startFuel += maxPriorityQueue.dequeue() || 0 17 | res++ 18 | } else return -1 19 | } 20 | // 每行驶1英里就会用掉1升汽油,当前油量即为能走的最远距离 21 | total += startFuel 22 | // 每次清空油量,即走到的最远距离 23 | startFuel = 0 24 | // 将小于当前走过距离的加油站的油加入队列 25 | while (idx < len && stations[idx][0] <= total) maxPriorityQueue.enqueue(stations[idx++][1]) 26 | } 27 | return res 28 | } -------------------------------------------------------------------------------- /src/search/array-nesting.ts: -------------------------------------------------------------------------------- 1 | // 数组嵌套 2 | // https://leetcode.cn/problems/array-nesting 3 | // INLINE ../../images/search/array-nesting.jpeg 4 | 5 | export function arrayNesting (nums: number[]): number { 6 | let maxNesting = 0 7 | const set = new Set() 8 | for (let i = 0, len = nums.length; i < len; i++) { 9 | let nesting = 0 10 | let nextIndex = nums[i] 11 | while (nextIndex >= 0 && nextIndex <= len - 1) { 12 | if (set.has(nextIndex)) { 13 | break 14 | } else { 15 | set.add(nextIndex) 16 | nesting++ 17 | nextIndex = nums[nextIndex] 18 | } 19 | } 20 | maxNesting = Math.max(maxNesting, nesting) 21 | } 22 | return maxNesting 23 | } -------------------------------------------------------------------------------- /src/sort/bubbleSort.ts: -------------------------------------------------------------------------------- 1 | // O(n^2) 2 | // 选择排序: 选择最小的元素和当前位置元素交换位置。 3 | // 插入排序: 对比已排序的元素插入到合适位置。 4 | // 冒泡排序: 把最大的元素排到最末尾。 5 | 6 | /** 7 | * 冒泡排序 8 | * @param nums 待排序数组 9 | * @returns 已排序好的数组 10 | */ 11 | export const bubbleSort = (nums: number[]): number[] => { 12 | for (let i = 0; i < nums.length - 1; i++) { 13 | let done = true 14 | for (let j = 0; j < nums.length - 1 - i; j++) { 15 | if (nums[j] > nums[j + 1]) { 16 | [nums[j], nums[j + 1]] = [nums[j + 1], nums[j]] 17 | done = false 18 | } 19 | } 20 | if (done) break 21 | } 22 | return nums 23 | } 24 | -------------------------------------------------------------------------------- /src/sort/insertSort.ts: -------------------------------------------------------------------------------- 1 | import { putItem, removeItem } from "../lib/splice" 2 | 3 | export const insertSort = (arr: number[]) => { 4 | for (let i = 1; i < arr.length; i++) { 5 | for (let j = i; j > 0 && arr[j - 1] > arr[j]; j--) { 6 | [arr[j - 1], arr[j]] = [arr[j], arr[j - 1]] 7 | } 8 | } 9 | return arr 10 | } 11 | 12 | export const insertSort2 = (arr: number[]) => { 13 | for (let i = 1; i < arr.length; i++) { 14 | if (arr[i - 1] > arr[i]) { // 6 > 1 15 | for (let j = i; j > 0; j--) { 16 | if (arr[j - 1] < arr[i]) { 17 | const tmp = arr[i] 18 | arr = removeItem(arr, i) // 删除i位置的元素 19 | arr = putItem(arr, j, tmp) // 在j位置插入该元素 20 | break 21 | } 22 | } 23 | if (arr[i] < arr[0]) { 24 | const tmp = arr[i] 25 | removeItem(arr, i) 26 | arr.unshift(tmp) 27 | } 28 | } 29 | } 30 | return arr 31 | } 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/sort/mergeSort.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 合并两个已经排好序的数组 为一个新的排好序的数组 3 | * @param a 数组A 4 | * @param b 数组B 5 | * @returns 合并后的数组 6 | */ 7 | const merge = (a: any[], b: any[]) => { 8 | const arr = [] 9 | while (a.length && b.length) { 10 | if (a[0] < b[0]) { 11 | arr.push(a.shift()) 12 | } else { 13 | arr.push(b.shift()) 14 | } 15 | } 16 | return [...arr, ...a, ...b] 17 | } 18 | 19 | /** 20 | * 归并排序 21 | * @param arr 待排序数组 22 | * @returns 排好序的数组 23 | */ 24 | export const mergeSort = (arr: any[]): any[] => { 25 | // 终止条件: 当数组只有一个元素或者是空数组的时候,终止递归 26 | if (arr.length <= 1) return arr 27 | const halfIndex = Math.floor(arr.length / 2) // arr.length >> 1 28 | 29 | const left = arr.splice(0, halfIndex) 30 | // const right = arr 31 | 32 | return merge(mergeSort(left), mergeSort(arr)) 33 | } 34 | -------------------------------------------------------------------------------- /src/sort/minimum-absolute-difference.ts: -------------------------------------------------------------------------------- 1 | // 最小绝对差 2 | // https://leetcode.cn/problems/minimum-absolute-difference 3 | // INLINE ../../images/sort/minimum-absolute-difference.jpeg 4 | 5 | export function minimumAbsDifference (arr: number[]): number[][] { 6 | arr.sort((a, b) => a - b) 7 | let minAbsDifference = Number.MAX_VALUE 8 | let minAbsDifferenceArr: number[][] = [] 9 | for (let i = 0, len = arr.length - 1; i < len; i++) { 10 | let j = i + 1 11 | const tmp = Math.abs(arr[i]/*?*/ - arr[j]/*?*/) 12 | if (tmp < minAbsDifference) { 13 | minAbsDifference = tmp // ? 14 | // minAbsDifferenceArr = arr[i] > arr[j] ? [[arr[j], arr[i]]] : [[arr[i], arr[j]]] // ? 15 | minAbsDifferenceArr = [[arr[i], arr[j]]] // ? 16 | } else if (tmp === minAbsDifference) { 17 | minAbsDifferenceArr.push([arr[i], arr[j]]) 18 | } 19 | } 20 | return minAbsDifferenceArr // ? 21 | } -------------------------------------------------------------------------------- /src/sort/quickSort.ts: -------------------------------------------------------------------------------- 1 | export const partition = (arr: number[], l: number, r: number) => { 2 | const v = arr[l] 3 | 4 | let j = l 5 | for (let i = l + 1; i <= r; i++) { 6 | if (arr[i] < v) { 7 | [arr[j + 1], arr[i]] = [arr[i], arr[j + 1]] 8 | j++ 9 | } 10 | } 11 | 12 | [arr[l], arr[j]] = [arr[j], arr[l]] 13 | return j 14 | } 15 | 16 | /** 17 | * 快速排序 18 | * @param arr 待排序数组 19 | * @param l 左下标 20 | * @param r 右下标 21 | */ 22 | export const quickSort = (arr: number[], l = 0, r = arr.length - 1) => { 23 | if (l >= r) return 24 | const p = partition(arr, l, r) 25 | quickSort(arr, l, p - 1) 26 | quickSort(arr, p + 1, r) 27 | } 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/sort/selectSort.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 选择排序 3 | * @param arr 待排序数组 4 | * @returns 已排序数组 5 | */ 6 | export const selectSort = (arr: number[]) => { 7 | for (let i = 0; i < arr.length; i++) { 8 | let minIndex = i // 从i起,找到剩余元素中最小值的位置 9 | for (let j = i + 1; j < arr.length; j++) { // 找出最小的元素 10 | if (arr[j] < arr[minIndex]) { 11 | minIndex = j 12 | } 13 | } 14 | // 最小的元素和i交换位置 15 | [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]] 16 | } 17 | return arr 18 | } 19 | -------------------------------------------------------------------------------- /src/stack/build-an-array-with-stack-operations.ts: -------------------------------------------------------------------------------- 1 | // 用栈操作构建数组 2 | // https://leetcode.cn/problems/build-an-array-with-stack-operations 3 | // INLINE ../../images/stack/build-an-array-with-stack-operations.jpeg 4 | 5 | export function buildArray (target: number[], n: number): string[] { 6 | const set = new Set(target) 7 | const res = [] 8 | for (let i = 1; i <= n; i++) { 9 | if (!set.has(i)) { 10 | res.push("Push", "Pop") 11 | } else { 12 | res.push('Push') 13 | if (target[target.length - 1] === i) break 14 | } 15 | } 16 | return res 17 | } -------------------------------------------------------------------------------- /src/stack/decode-string.ts: -------------------------------------------------------------------------------- 1 | export const decodeString = function (s: string): string { 2 | const stack = [] 3 | let multiple = '' 4 | for (let i = 0, len = s.length; i < len; i++) { 5 | if (!isNaN(Number(s[i]))) { // 判断是数字 6 | if (i === 0 || !isNaN(Number(s[i - 1]))) { // 如果上一位也是数字,则 7 | multiple += s[i] 8 | } else { 9 | multiple = s[i] 10 | } 11 | } else if (multiple && s[i] === '[') { 12 | stack.push(Number(multiple)) 13 | multiple = '' 14 | } else if (s[i] === ']') { 15 | let current = stack.pop() 16 | let tmpStr = '' 17 | while (typeof current !== 'number') { 18 | tmpStr = current + tmpStr 19 | current = stack.pop() 20 | } 21 | tmpStr = tmpStr.repeat(current) 22 | stack.push(tmpStr) 23 | } else { 24 | stack.push(s[i]) 25 | } 26 | } 27 | 28 | return stack.join('') 29 | } 30 | -------------------------------------------------------------------------------- /src/stack/min-stack.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * initialize your data structure here. 3 | */ 4 | export class MinStack { 5 | stack: any[] 6 | minStack: any[] 7 | constructor () { 8 | this.stack = [] 9 | this.minStack = [Infinity] 10 | } 11 | 12 | push (x: number): void { 13 | this.stack.push(x) 14 | this.minStack.push(Math.min(this.minStack[this.minStack.length - 1], x)) 15 | } 16 | 17 | pop (): void { 18 | this.stack.pop() 19 | this.minStack.pop() 20 | } 21 | 22 | top (): number { 23 | return this.stack[this.stack.length - 1] 24 | } 25 | 26 | getMin (): number { 27 | return this.minStack[this.minStack.length - 1] 28 | } 29 | } 30 | 31 | /** 32 | * Your MinStack object will be instantiated and called as such: 33 | * var obj = new MinStack() 34 | * obj.push(x) 35 | * obj.pop() 36 | * var param_3 = obj.top() 37 | * var param_4 = obj.getMin() 38 | */ 39 | -------------------------------------------------------------------------------- /src/stack/simplify-path.ts: -------------------------------------------------------------------------------- 1 | // 简化路径 2 | // https://leetcode.cn/problems/simplify-path/ 3 | // INLINE ../../images/stack/simplify-path.jpeg 4 | 5 | export function simplifyPath (path: string): string { 6 | const dirs = path.split('/') 7 | const stack: string[] = [] // 数组模拟stack 8 | 9 | for (const dir of dirs) { 10 | if (dir === '..') { 11 | stack.length && stack.pop() 12 | } else if (dir !== '.') { 13 | dir && stack.push(dir) 14 | } 15 | } 16 | 17 | return '/' + stack.join('/') 18 | } -------------------------------------------------------------------------------- /src/stack/yong-liang-ge-zhan-shi-xian-dui-lie-lcof.ts: -------------------------------------------------------------------------------- 1 | export class CQueue { 2 | stackA: any[] 3 | stackB: any[] 4 | 5 | constructor () { 6 | this.stackA = [] 7 | this.stackB = [] 8 | } 9 | 10 | appendTail (value: number): void { 11 | this.stackA.push(value) 12 | } 13 | 14 | deleteHead (): number { 15 | const stackBNum = this.stackB.length 16 | 17 | while (this.stackA.length) { 18 | this.stackB.push(this.stackA.pop()) 19 | } 20 | 21 | if (stackBNum !== 0) { 22 | this.stackB.push(...this.stackB.splice(0, stackBNum)) 23 | } 24 | 25 | const tmp = this.stackB.pop() 26 | return tmp === undefined ? -1 : tmp 27 | } 28 | } 29 | 30 | /** 31 | * Your CQueue object will be instantiated and called as such: 32 | * var obj = new CQueue() 33 | * obj.appendTail(value) 34 | * var param_2 = obj.deleteHead() 35 | */ 36 | -------------------------------------------------------------------------------- /src/string/check-if-a-word-occurs-as-a-prefix-of-any-word-in-a-sentence.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} sentence 3 | * @param {string} searchWord 4 | * @return {number} 5 | */ 6 | export const isPrefixOfWord = function (sentence: string, searchWord: string) { 7 | const items = sentence.split(' ') 8 | 9 | for (const n in items) { 10 | if (items[n].indexOf(searchWord) === 0) return Number(n) + 1 11 | } 12 | 13 | return -1 14 | } 15 | -------------------------------------------------------------------------------- /src/string/check-if-binary-string-has-at-most-one-segment-of-ones.ts: -------------------------------------------------------------------------------- 1 | // 检查二进制字符串字段 2 | // https://leetcode.cn/problems/check-if-binary-string-has-at-most-one-segment-of-ones/ 3 | // INLINE ../../images/string/check-if-binary-string-has-at-most-one-segment-of-ones.jpeg 4 | 5 | export function checkOnesSegment (s: string): boolean { 6 | return !s.includes('01') 7 | } -------------------------------------------------------------------------------- /src/string/compare-strings.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param A: A string 3 | * @param B: A string 4 | * @return: if string A contains all of the characters in B return true else return false 5 | */ 6 | export const compareStrings = function (A: string, B: string) { 7 | const a = A.split('') 8 | const b = B.split('') 9 | 10 | for (const n in b) { 11 | const tmp = a.indexOf(b[n]) 12 | if (tmp === -1) { 13 | return false 14 | } else { 15 | a.splice(tmp, 1) 16 | } 17 | } 18 | 19 | return true 20 | } 21 | -------------------------------------------------------------------------------- /src/string/contains-duplicate.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {boolean} 4 | */ 5 | export const containsDuplicate = function (nums: number[]) { 6 | return new Set(nums).size !== nums.length 7 | } 8 | -------------------------------------------------------------------------------- /src/string/defanging-an-ip-address.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} address 3 | * @return {string} 4 | */ 5 | export const defangIPaddr = function (address: string) { 6 | return address.replace(/\./g, '[.]') 7 | } 8 | -------------------------------------------------------------------------------- /src/string/different-ways-to-add-parentheses.ts: -------------------------------------------------------------------------------- 1 | // 为运算表达式设计优先级 2 | // https://leetcode.cn/problems/different-ways-to-add-parentheses 3 | 4 | export function diffWaysToCompute (expression: string): number[] { 5 | if (/^\d+$/.test(expression)) return [Number(expression)] 6 | 7 | const res = [] 8 | for (let i = 0, len = expression.length; i < len; i++) { 9 | if (['+', '-', '*'].includes(expression[i])) { 10 | const left = diffWaysToCompute(expression.slice(0, i)) 11 | const right = diffWaysToCompute(expression.slice(i + 1, expression.length)) 12 | 13 | for (const l of left) { 14 | for (const r of right) { 15 | if (expression[i] === '+') res.push(l + r) 16 | else if (expression[i] === '-') res.push(l - r) 17 | else res.push(l * r) 18 | } 19 | } 20 | } 21 | } 22 | 23 | return res 24 | } -------------------------------------------------------------------------------- /src/string/find-the-longest-substring-containing-vowels-in-even-counts.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} s 3 | * @return {number} 4 | */ 5 | export const findTheLongestSubstring = function (s: string) { 6 | const n = s.length 7 | const pos = new Array(1 << 5).fill(-1) 8 | let ans = 0; let status = 0 9 | pos[0] = 0 10 | for (let i = 0; i < n; ++i) { 11 | const ch = s.charAt(i) 12 | if (ch === 'a') { 13 | status ^= 1 << 0 14 | } else if (ch === 'e') { 15 | status ^= 1 << 1 16 | } else if (ch === 'i') { 17 | status ^= 1 << 2 18 | } else if (ch === 'o') { 19 | status ^= 1 << 3 20 | } else if (ch === 'u') { 21 | status ^= 1 << 4 22 | } 23 | if (~pos[status]) { 24 | ans = Math.max(ans, i + 1 - pos[status]) 25 | } else { 26 | pos[status] = i + 1 27 | } 28 | } 29 | return ans 30 | } 31 | -------------------------------------------------------------------------------- /src/string/generate-a-string-with-characters-that-have-odd-counts.ts: -------------------------------------------------------------------------------- 1 | // 生成每种字符都是奇数个的字符串 2 | // https://leetcode.cn/problems/generate-a-string-with-characters-that-have-odd-counts 3 | // INLINE ../../images/string/generate-a-string-with-characters-that-have-odd-counts.jpeg 4 | 5 | export function generateTheString (n: number): string { 6 | return n % 2 === 0 ? 'a'.repeat(n - 1) + 'b' : 'a'.repeat(n) 7 | } -------------------------------------------------------------------------------- /src/string/generate-parentheses.ts: -------------------------------------------------------------------------------- 1 | function backtracking (n: number, res: string[], path: string, leftCount: number, rightCount: number) { 2 | if (path.length === 2 * n) return res.push(path) 3 | 4 | if (leftCount < n) { 5 | backtracking(n, res, path + '(', leftCount + 1, rightCount) 6 | } 7 | 8 | if (rightCount < leftCount) { 9 | backtracking(n, res, path + ')', leftCount, rightCount + 1) 10 | } 11 | } 12 | 13 | export function generateParenthesis (n: number): string[] { 14 | const res: string[] = [] 15 | backtracking(n, res, "", 0, 0) 16 | return res 17 | } -------------------------------------------------------------------------------- /src/string/integer-to-roman.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} num 3 | * @return {string} 4 | */ 5 | export const intToRoman = function (num: number) { 6 | const nums = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1] 7 | const chars = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I'] 8 | let result = '' 9 | while (num) { 10 | if (num >= nums[0]) { // 3 > 1 => 2 > 1 => 1 == 1 11 | result += chars[0] // I => II => III 12 | num -= nums[0] // 3 -> 2 => 2 -> 1 => 1 => 0 13 | } else { 14 | nums.shift() 15 | chars.shift() 16 | } 17 | } 18 | return result 19 | } 20 | -------------------------------------------------------------------------------- /src/string/largest-number.ts: -------------------------------------------------------------------------------- 1 | export const largestNumber = function (nums: number[]): string { 2 | return nums.sort((a, b) => Number(`${b}${a}`) - Number(`${a}${b}`)).join('').replace(/^0+/, '') || '0' 3 | } 4 | -------------------------------------------------------------------------------- /src/string/length-of-last-word.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} s 3 | * @return {number} 4 | */ 5 | export const lengthOfLastWord = function (s: string) { 6 | s = s.trim() 7 | const tmp = s.lastIndexOf(' ') 8 | const lastWord = s.substring(tmp === -1 ? 0 : tmp + 1, s.length) 9 | return lastWord.length 10 | } 11 | -------------------------------------------------------------------------------- /src/string/longest-common-prefix.ts: -------------------------------------------------------------------------------- 1 | const comp = (left: string, right: string, res?: string) => { 2 | if (left.length > right.length) { 3 | [left, right] = [right, left] 4 | } 5 | 6 | res = res || left 7 | while (right.indexOf(res) !== 0 && res.length > 0) { 8 | res = res.slice(0, res.length - 1) 9 | } 10 | 11 | return res 12 | } 13 | 14 | export const longestCommonPrefix = function (strs: string[]): string { 15 | if (strs.length < 2) return strs[0] || '' 16 | 17 | let res = strs[0] 18 | for (let i = 1; i < strs.length; i++) { 19 | res = comp(res, strs[i]) 20 | } 21 | 22 | return res 23 | } 24 | -------------------------------------------------------------------------------- /src/string/longest-substring-without-repeating-characters.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} s 3 | * @return {number} 4 | */ 5 | export const lengthOfLongestSubstring = function (s: string) { 6 | let max = 0 7 | 8 | for (let n = 0, len = s.length, inx = 0, set = new Set(); n < len; n++) { 9 | if (n !== 0) set.delete(s[n - 1]) 10 | while (inx < len && !set.has(s[inx])) set.add(s[inx++]) 11 | max = Math.max(max, inx - n) 12 | } 13 | 14 | return max 15 | } 16 | -------------------------------------------------------------------------------- /src/string/maximum-number-of-vowels-in-a-substring-of-given-length.ts: -------------------------------------------------------------------------------- 1 | const v = ['a', 'e', 'i', 'o', 'u'] 2 | const check = (str: string) => { 3 | const map = new Map() 4 | 5 | for (let i = 0; i < str.length; i++) { 6 | if (v.includes(str[i])) { 7 | map.set(str[i], (map.get(str[i]) || 0) + 1) 8 | } 9 | } 10 | 11 | let res = 0 12 | map.forEach(n => { 13 | res += n 14 | }) 15 | return res 16 | } 17 | 18 | export const maxVowels = function (s: string, k: number): number { 19 | let i = 0 20 | let res = 0 21 | 22 | const temp = s.slice(i, i + k) 23 | let tmp = check(temp) 24 | res = Math.max(res, tmp) 25 | 26 | while (i + k <= s.length) { 27 | i++ 28 | if (v.includes(s[i + k - 1])) { 29 | tmp++ 30 | } 31 | 32 | if (v.includes(s[i - 1])) { 33 | tmp-- 34 | } 35 | 36 | res = Math.max(res, tmp) 37 | } 38 | 39 | return res 40 | } 41 | -------------------------------------------------------------------------------- /src/string/minimum-window-substring.ts: -------------------------------------------------------------------------------- 1 | export const minWindow = function (s: string, t: string): string { 2 | const sLen = s.length; const tLen = t.length 3 | const tMap = new Map(); const map = new Map() 4 | let l = 0; let r = 0; let res = '' 5 | 6 | for (let i = 0; i < tLen; i++) { 7 | tMap.set(t[i], (tMap.get(t[i]) || 0) + 1) 8 | } 9 | 10 | const check = (cMap: Map) => { 11 | const check = new Map( 12 | [...cMap].filter(([k, v]) => tMap.has(k) && v >= tMap.get(k)) 13 | ) 14 | 15 | return check.size === tMap.size 16 | } 17 | 18 | while (r <= sLen) { 19 | if (t.includes(s[r])) { 20 | map.set(s[r], (map.get(s[r]) || 0) + 1) 21 | } 22 | 23 | while (check(map) && l <= r) { 24 | const tmp = s.slice(l, r + 1) 25 | if (res.length === 0 || tmp.length <= res.length) res = tmp 26 | if (t.includes(s[l]) && map.has(s[l])) { 27 | map.set(s[l], map.get(s[l]) - 1) 28 | } 29 | l++ 30 | } 31 | r++ 32 | } 33 | 34 | return res 35 | } 36 | -------------------------------------------------------------------------------- /src/string/repeated-substring-pattern.ts: -------------------------------------------------------------------------------- 1 | // LeetCode 459. 重复的子字符串 https://leetcode-cn.com/problems/repeated-substring-pattern/ 2 | // LintCode 1227. 重复的子串模式 https://www.lintcode.com/problem/repeated-substring-pattern/description 3 | 4 | export default (str: string): boolean => { 5 | return /^(\w+)\1+$/.test(str) 6 | } 7 | -------------------------------------------------------------------------------- /src/string/reverse-words-in-a-string.ts: -------------------------------------------------------------------------------- 1 | // LeetCode 557. 反转字符串中的单词 III https://leetcode-cn.com/problems/reverse-words-in-a-string-iii/ 2 | // LintCode 1173. 反转字符串 III https://www.lintcode.com/problem/reverse-words-in-a-string-iii/description 3 | 4 | export default (s: string) => { 5 | return s.split(' ').map(item => { 6 | let tmp = '' 7 | for (let n = item.length; n >= 0; n--) { 8 | tmp += item.charAt(n) 9 | } 10 | return tmp 11 | }).join(' ') 12 | } 13 | -------------------------------------------------------------------------------- /src/string/roman-to-integer.ts: -------------------------------------------------------------------------------- 1 | export const romanToInt = function (s: string): number { 2 | const map = new Map([ 3 | ['I', 1], 4 | ['IV', 4], 5 | ['V', 5], 6 | ['IX', 9], 7 | ['X', 10], 8 | ['XL', 40], 9 | ['L', 50], 10 | ['XC', 90], 11 | ['C', 100], 12 | ['CD', 400], 13 | ['D', 500], 14 | ['CM', 900], 15 | ['M', 1000] 16 | ]) 17 | 18 | let ans = 0 19 | let i = 0 20 | while (i < s.length) { 21 | if (i + 1 < s.length && map.has(s.substring(i, i + 2))) { 22 | ans += map.get(s.substring(i, i + 2)) as number 23 | i += 2 24 | } else { 25 | ans += map.get(s.substring(i, i + 1)) || 0 26 | i++ 27 | } 28 | } 29 | return ans 30 | } 31 | -------------------------------------------------------------------------------- /src/string/string-matching-in-an-array.ts: -------------------------------------------------------------------------------- 1 | // 数组中的字符串匹配 2 | // https://leetcode.cn/problems/string-matching-in-an-array 3 | // INLINE ../../images/string/string-matching-in-an-array.jpeg 4 | // 思路:字符串出现次数>1就说明有其他包含该字符串的字符串 5 | 6 | export function stringMatching (words: string[]): string[] { 7 | // return words.filter((word) => words.find(item => item.includes(word) && item.length > word.length)) 8 | const allStr = words.join('|') 9 | return words.filter((word) => allStr.indexOf(word) !== allStr.lastIndexOf(word)) 10 | } -------------------------------------------------------------------------------- /src/string/string2int.ts: -------------------------------------------------------------------------------- 1 | // 注意,仅为提供面试思路,实现不严谨 2 | export const string2int = (s: string): number => { 3 | // 如果是机器检查。这道题很简单,*1就完了, 或者Math.floor,或者 +'123'。都可以绕开系统的检查。 4 | // 但是如果是面试,就必须要用到map和reduce,上述方法显然不是面试官想听到的。 5 | // 而这俩都是数组的方法,因此首先用split('')将'123'变为['1','2','3']。 6 | // reduce常规用法就是 total * 10 + currentValue。至于map,需要思考如何用map将字符串数组变为数字数组。 7 | // 某人问过我这道题,由于网上写的基本都是错的,面试可能通不过,特记录于此。 8 | 9 | return s.split('').map(i => i.charCodeAt(0) - 48).reduce((total, currentValue) => total * 10 + currentValue) 10 | 11 | // 温馨提示:面试不一定需要说出你知道的或者你的各种想法,而是要尽可能准确的回答面试官想知道的答案。 12 | // 特别对于职业发展来说,如果你的真实想法不一定是面试官希望听到的,就不要说。 13 | } 14 | -------------------------------------------------------------------------------- /src/string/unique-characters.ts: -------------------------------------------------------------------------------- 1 | export const isUnique = (str: string) => { 2 | return new Set(str.split('')).size === str.length 3 | } 4 | -------------------------------------------------------------------------------- /src/string/valid-palindrome-ii.ts: -------------------------------------------------------------------------------- 1 | export const validPalindrome = function (s: string, flag = true): boolean { 2 | let l = 0; let r = s.length - 1 3 | while (l < r && s[l] === s[r]) { 4 | l++; r-- 5 | } 6 | if (l >= r) return true // 说明是回文 7 | if (flag) return validPalindrome(s.slice(l, r), false) || validPalindrome(s.slice(l + 1, r + 1), false) // 如果不是回文,切左边或者右边,再判断一次 8 | return false 9 | } 10 | 11 | // 暴力解法,会超时 12 | // /** 13 | // * @param {string} s 14 | // * @return {boolean} 15 | // */ 16 | // export const validPalindrome = function (s) { 17 | // const len = s.length 18 | // const tmpLen = len - 1 19 | // let mid = len >> 1 20 | // if (s.substring(0, mid) === s.substring(len % 2 ? mid + 1 : mid, len).split('').reverse().join('')) { 21 | // return true 22 | // } 23 | 24 | // mid = tmpLen >> 1 25 | // for (let n = 0; n < len; n++) { 26 | // const tmp = s.substring(0, n) + s.substring(n + 1, len) 27 | // if (tmp.substring(0, mid) === tmp.substring(tmpLen % 2 ? mid + 1 : mid, tmpLen).split('').reverse().join('')) { 28 | // return true 29 | // } 30 | // } 31 | 32 | // return false 33 | // } 34 | -------------------------------------------------------------------------------- /src/string/zuo-xuan-zhuan-zi-fu-chuan-lcof.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} s 3 | * @param {number} n 4 | * @return {string} 5 | */ 6 | export const reverseLeftWords = function (s: string, n: number) { 7 | return (s + s).substr(n, s.length) 8 | } 9 | -------------------------------------------------------------------------------- /src/tree/Tree.ts: -------------------------------------------------------------------------------- 1 | import { TreeNode } from "../lib/TreeNode" 2 | 3 | export default class Tree { 4 | private root: TreeNode | null 5 | private queue: TreeNode[] 6 | private insertNum: number 7 | 8 | constructor () { 9 | this.root = null 10 | this.queue = [] 11 | this.insertNum = 0 12 | } 13 | 14 | insert (val: number | null) { 15 | this.insertNum++ // 插入次数加1 16 | const node = (!val && typeof val === 'object') ? null : new TreeNode(val) // 判断是否为空节点 17 | 18 | if (!this.root) { // 判断根节点是否存在 19 | this.root = node // 插入根节点 20 | this.root && this.queue.push(this.root) // 非空节点入列 21 | } else { // 插入非根节点 22 | const parent = this.queue[0] // 被插入的父节点 23 | if (!(this.insertNum % 2)) { // 通过插入次数判断左右 24 | parent.left = node // 插入左边 25 | parent.left && this.queue.push(parent.left) // 非空节点入列 26 | } else { 27 | parent.right = node // 插入右边 28 | parent.right && this.queue.push(parent.right) // 非空节点入列 29 | this.queue.shift() // 当前父节点parent 已经不可能再插入子节点,故出列 30 | } 31 | } 32 | return this 33 | } 34 | 35 | static arrToTree (arr: (number | null)[]): TreeNode | null { 36 | const tree = new Tree() 37 | 38 | for (const n in arr) { 39 | tree.insert(arr[n]) 40 | } 41 | 42 | return tree.root 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/tree/bfs.ts: -------------------------------------------------------------------------------- 1 | import { TreeNode } from "../lib/TreeNode" 2 | 3 | export const bfs = (node: TreeNode): number[] => { 4 | const res = [] 5 | const queue = [] // 队列 6 | queue.push(node) 7 | while (queue.length > 0) { 8 | node = queue.shift() as TreeNode // 逻辑上此处一定存在值 9 | res.push(node.val) 10 | 11 | if (node.left) { 12 | queue.push(node.left) 13 | } 14 | 15 | if (node.right) { 16 | queue.push(node.right) 17 | } 18 | } 19 | return res 20 | } -------------------------------------------------------------------------------- /src/tree/binary-tree-level-order-traversal-ii.ts: -------------------------------------------------------------------------------- 1 | import { TreeNode } from '../lib/TreeNode' 2 | 3 | export const levelOrder = function (root: TreeNode | null) { 4 | const res = [] 5 | const queue = [root] 6 | while (queue.length) { // BFS 7 | const tmp = [] 8 | const leave = queue.length // 记录这一层有几个 9 | for (let i = 0; i < leave; i++) { // 一次性把固定个数的队列执行完 10 | const node = queue.shift() 11 | if (node && node.left) queue.push(node.left) 12 | if (node && node.right) queue.push(node.right) 13 | if (node) tmp.push(node.val) 14 | } 15 | if (tmp.length) res.unshift(tmp) 16 | } 17 | 18 | return res 19 | } 20 | -------------------------------------------------------------------------------- /src/tree/binary-tree-level-order-traversal.ts: -------------------------------------------------------------------------------- 1 | import { TreeNode } from "../lib/TreeNode" 2 | 3 | export const levelOrder = function (root: TreeNode | null): number[][] { 4 | const res = [] 5 | const queue = [root] 6 | while (queue.length) { // BFS 7 | const tmp = [] 8 | const leave = queue.length // 记录这一层有几个 9 | for (let i = 0; i < leave; i++) { // 一次性把固定个数的队列执行完 10 | const node = queue.shift() 11 | if (node && node.left) queue.push(node.left) 12 | if (node && node.right) queue.push(node.right) 13 | if (node) tmp.push(node.val) 14 | } 15 | if (tmp.length) res.push(tmp) 16 | } 17 | 18 | return res 19 | } 20 | -------------------------------------------------------------------------------- /src/tree/binary-tree-right-side-view.ts: -------------------------------------------------------------------------------- 1 | import { TreeNode } from "../lib/TreeNode" 2 | 3 | export const rightSideView = function (root: TreeNode | null): number[] { 4 | if (!root) return [] 5 | const queue = [root] // 队列 把树顶加入队列 6 | const arr: number[] = [] // 用来存储每层最后个元素值 7 | while (queue.length > 0) { 8 | let len = queue.length 9 | while (len) { 10 | const node = queue.shift() // 取出队列第一个元素 11 | if (len === 1 && node?.val) arr.push(node.val) // 当是 当前一层的最后一个元素时,把值加入arr 12 | if (node?.left) queue.push(node.left) // 继续往队列添加元素 13 | if (node?.right) queue.push(node.right) 14 | len-- 15 | } 16 | } 17 | 18 | return arr 19 | } 20 | -------------------------------------------------------------------------------- /src/tree/construct-binary-tree-from-preorder-and-inorder-traversal.ts: -------------------------------------------------------------------------------- 1 | // 前序遍历:根左右 2 | // 中序遍历:左根右 3 | 4 | import { TreeNode } from "../lib/TreeNode" 5 | 6 | // 前序遍历知道根、中序遍历知道左边长度。 7 | 8 | export const buildTree = function (preorder: number[], inorder: number[]): TreeNode | null { 9 | if (inorder.length === 0) return null 10 | const root = new TreeNode(preorder[0]) 11 | const index = inorder.indexOf(preorder[0]) 12 | root.left = buildTree(preorder.slice(1, index + 1), inorder.slice(0, index)) 13 | root.right = buildTree(preorder.slice(index + 1), inorder.slice(index + 1)) 14 | return root 15 | } 16 | -------------------------------------------------------------------------------- /src/tree/convert-sorted-array-to-binary-search-tree.ts: -------------------------------------------------------------------------------- 1 | import { TreeNode } from "../lib/TreeNode" 2 | 3 | export const sortedArrayToBST = function (nums: number[]): TreeNode | null { 4 | if (!nums.length) return null 5 | 6 | const createTree = (left: number, right: number): TreeNode | null => { 7 | if (left > right) return null 8 | const mid = Math.floor((left + right) / 2) 9 | const root = new TreeNode(nums[mid]) 10 | root.left = createTree(left, mid - 1) 11 | root.right = createTree(mid + 1, right) 12 | return root 13 | } 14 | 15 | return createTree(0, nums.length - 1) 16 | } 17 | -------------------------------------------------------------------------------- /src/tree/lowest-common-ancestor-of-a-binary-tree.ts: -------------------------------------------------------------------------------- 1 | import { TreeNode } from "../lib/TreeNode" 2 | 3 | export const lowestCommonAncestor = function (root: TreeNode | null, p: TreeNode | null, q: TreeNode | null): TreeNode | null { 4 | if (!root || root === p || root === q) return root 5 | const left = lowestCommonAncestor(root.left, p, q) 6 | const right = lowestCommonAncestor(root.right, p, q) 7 | if ((left === p && right === q) || (left === q && right === p)) return root 8 | return left || right 9 | } 10 | -------------------------------------------------------------------------------- /src/tree/same-tree.ts: -------------------------------------------------------------------------------- 1 | // 相同的树 2 | // https://leetcode.cn/problems/same-tree/ 3 | // INLINE ../../images/tree/same-tree.jpeg 4 | 5 | import { TreeNode } from "../lib/TreeNode" 6 | 7 | export function isSameTree (p: TreeNode | null, q: TreeNode | null): boolean { 8 | if ((p === null || q === null) && p !== q) { 9 | return false 10 | } 11 | 12 | if (p?.val !== q?.val) { 13 | return false 14 | } 15 | 16 | if ((p?.left || q?.right) && !isSameTree(p?.left || null, q?.left || null)) return false 17 | if ((p?.right || q?.right) && !isSameTree(p?.right || null, q?.right || null)) return false 18 | 19 | return true 20 | } -------------------------------------------------------------------------------- /src/tree/subtree-of-another-tree.ts: -------------------------------------------------------------------------------- 1 | import { TreeNode } from "../lib/TreeNode" 2 | 3 | export const isSubtree = function (s: TreeNode | null, t: TreeNode | null): boolean { 4 | if (!s && t) { 5 | return false 6 | } 7 | 8 | const linkNode = function (node: TreeNode | null, target: TreeNode | null): boolean { 9 | if ((!node && target) || (node && !target)) return false 10 | if (!node && !target) return true 11 | 12 | return node?.val === target?.val ? linkNode(node!.left, target!.left) && linkNode(node!.right, target!.right) : false 13 | } 14 | 15 | return linkNode(s, t) || isSubtree(s!.left, t) || isSubtree(s!.right, t) 16 | } 17 | -------------------------------------------------------------------------------- /src/tree/trim-a-binary-search-tree.ts: -------------------------------------------------------------------------------- 1 | // 修剪二叉搜索树 2 | // https://leetcode.cn/problems/trim-a-binary-search-tree 3 | // INLINE ../../images/tree/trim-a-binary-search-tree.jpeg 4 | // 解题思路:递归 5 | 6 | import { TreeNode } from "../lib/TreeNode" 7 | 8 | export function trimBST (root: TreeNode | null, low: number, high: number): TreeNode | null { 9 | if (root === null) { 10 | return null 11 | } 12 | 13 | if (root.val < low) { 14 | return trimBST(root.right, low, high) 15 | } else if (root.val > high) { 16 | return trimBST(root.left, low, high) 17 | } else { 18 | root.left = trimBST(root.left, low, high) 19 | root.right = trimBST(root.right, low, high) 20 | return root 21 | } 22 | } -------------------------------------------------------------------------------- /src/tree/unique-binary-search-trees.ts: -------------------------------------------------------------------------------- 1 | // 卡塔兰数 2 | export const numTrees = function (n: number): number { 3 | let C = 1 4 | for (let i = 0; i < n; ++i) { 5 | C = C * 2 * (2 * i + 1) / (i + 2) 6 | } 7 | return C 8 | } 9 | -------------------------------------------------------------------------------- /src/tree/validate-binary-search-tree.ts: -------------------------------------------------------------------------------- 1 | import { TreeNode } from "../lib/TreeNode" 2 | 3 | export const isValidBST = function (root: TreeNode | null, lower = -Infinity, upper = Infinity): boolean { 4 | if (root === null) return true 5 | if (root.val <= lower || root.val >= upper) return false 6 | return isValidBST(root.left, lower, root.val) && isValidBST(root.right, root.val, upper) 7 | } 8 | -------------------------------------------------------------------------------- /test/array/01-matrix.test.ts: -------------------------------------------------------------------------------- 1 | import { updateMatrix } from '../../src/array/01-matrix' 2 | 3 | test('01 矩阵', () => { 4 | expect(updateMatrix([])).toEqual([]) 5 | 6 | expect(updateMatrix([ 7 | [0, 0, 0], 8 | [0, 1, 0], 9 | [0, 0, 0] 10 | ])).toEqual([ 11 | [0, 0, 0], 12 | [0, 1, 0], 13 | [0, 0, 0] 14 | ]) 15 | 16 | expect(updateMatrix([ 17 | [0, 0, 0], 18 | [0, 1, 0], 19 | [1, 1, 1] 20 | ])).toEqual([ 21 | [0, 0, 0], 22 | [0, 1, 0], 23 | [1, 2, 1] 24 | ]) 25 | 26 | expect(updateMatrix([ 27 | [0, 0, 0], 28 | [0, 0, 0], 29 | [0, 0, 0], 30 | [0, 0, 0], 31 | [0, 0, 0] 32 | ])).toEqual([ 33 | [0, 0, 0], 34 | [0, 0, 0], 35 | [0, 0, 0], 36 | [0, 0, 0], 37 | [0, 0, 0] 38 | ]) 39 | 40 | expect(updateMatrix([ 41 | [0, 1, 0, 1, 1], 42 | [1, 1, 0, 0, 1], 43 | [0, 0, 0, 1, 0], 44 | [1, 0, 1, 1, 1], 45 | [1, 0, 0, 0, 1] 46 | ])).toEqual([ 47 | [0, 1, 0, 1, 2], 48 | [1, 1, 0, 0, 1], 49 | [0, 0, 0, 1, 0], 50 | [1, 0, 1, 1, 1], 51 | [1, 0, 0, 0, 1] 52 | ]) 53 | }) 54 | -------------------------------------------------------------------------------- /test/array/4sum-ii.test.ts: -------------------------------------------------------------------------------- 1 | import { fourSumCount } from '../../src/array/4sum-ii' 2 | 3 | test('四数相加 II', () => { 4 | // 示例 1: 5 | // 输入:nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2] 6 | // 输出:2 7 | // 解释: 8 | // 两个元组如下: 9 | // 1. (0, 0, 0, 1) -> nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0 10 | // 2. (1, 1, 0, 0) -> nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0 11 | 12 | // 示例 2: 13 | // 输入:nums1 = [0], nums2 = [0], nums3 = [0], nums4 = [0] 14 | // 输出:1 15 | 16 | expect(fourSumCount([1, 2], [-2, -1], [-1, 2], [0, 2])).toBe(2) 17 | expect(fourSumCount([0], [0], [0], [0])).toBe(1) 18 | expect(fourSumCount([-1, -1], [-1, 1], [-1, 1], [1, -1])).toBe(6) 19 | expect(fourSumCount([-1, 1, 1, 1, -1] 20 | , [0, -1, -1, 0, 1] 21 | , [-1, -1, 1, -1, -1] 22 | , [0, 1, 0, -1, -1])).toBe(132) 23 | }) -------------------------------------------------------------------------------- /test/array/best-time-to-buy-and-sell-stock-ii.test.ts: -------------------------------------------------------------------------------- 1 | import { maxProfit } from '../../src/array/best-time-to-buy-and-sell-stock-ii' 2 | 3 | test('maxProfit', () => { 4 | expect(maxProfit([7, 1, 5, 3, 6, 4])).toBe(7) 5 | expect(maxProfit([1, 2, 3, 4, 5])).toBe(4) 6 | expect(maxProfit([7, 6, 4, 3, 1])).toBe(0) 7 | expect(maxProfit([])).toBe(0) 8 | expect(maxProfit([2, 1, 2, 0, 1])).toBe(2) 9 | }) 10 | -------------------------------------------------------------------------------- /test/array/binary-search.test.ts: -------------------------------------------------------------------------------- 1 | import { search } from '../../src/array/binary-search' 2 | 3 | test('BinarySearch', () => { 4 | expect(search([], 9)).toEqual(-1) 5 | expect(search([-1, 0, 3, 5, 9, 12], 9)).toEqual(4) 6 | expect(search([-1, 0, 3, 5, 9, 12], 2)).toEqual(-1) 7 | expect(search([1, 4, 4, 5, 7, 7, 8, 9, 9, 10], 1)).toEqual(0) 8 | expect(search([1, 2, 3, 3, 4, 5, 10], 3)).toEqual(2) 9 | expect(search([1, 2, 3, 3, 4, 5, 10], 6)).toEqual(-1) 10 | }) 11 | -------------------------------------------------------------------------------- /test/array/bubble-sort.test.ts: -------------------------------------------------------------------------------- 1 | import bubbleSort from '../../src/array/bubble-sort' 2 | 3 | test('bubbleSort', () => { 4 | expect(bubbleSort([1, 2, 3])).toEqual([1, 2, 3]) 5 | expect(bubbleSort([3, 2, 1])).toEqual([1, 2, 3]) 6 | expect(bubbleSort([])).toEqual([]) 7 | expect(bubbleSort([3, 6, 4, 5, 6, 8])).toEqual([3, 4, 5, 6, 6, 8]) 8 | expect(bubbleSort([1, 1, 1])).toEqual([1, 1, 1]) 9 | expect(bubbleSort([-1, -10, 3])).toEqual([-10, -1, 3]) 10 | expect(bubbleSort([7, 2, 8, 3, 6, 3])).toEqual([2, 3, 3, 6, 7, 8]) 11 | }) 12 | -------------------------------------------------------------------------------- /test/array/can-place-flowers.test.ts: -------------------------------------------------------------------------------- 1 | import canPlaceFlowers from '../../src/array/can-place-flowers' 2 | 3 | test('canPlaceFlowers', () => { 4 | expect(canPlaceFlowers([1, 0, 0, 0, 1], 1)).toBeTruthy() 5 | expect(canPlaceFlowers([1, 0, 0, 0, 1], 2)).toBeFalsy() 6 | expect(canPlaceFlowers([1, 0, 0, 0, 1, 0, 0], 2)).toBeTruthy() 7 | }) 8 | -------------------------------------------------------------------------------- /test/array/circular-array-loop.test.ts: -------------------------------------------------------------------------------- 1 | import { circularArrayLoop } from '../../src/array/circular-array-loop' 2 | 3 | test('circularArrayLoop', () => { 4 | expect(circularArrayLoop([0])).toEqual(false) 5 | expect(circularArrayLoop([2, -1, 1, 2, 2])).toEqual(true) 6 | expect(circularArrayLoop([-1, 2])).toEqual(false) 7 | expect(circularArrayLoop([-2, 1, -1, -2, -2])).toEqual(false) 8 | }) 9 | -------------------------------------------------------------------------------- /test/array/container-with-most-water.test.ts: -------------------------------------------------------------------------------- 1 | import { maxArea } from '../../src/array/container-with-most-water' 2 | 3 | test('盛最多水的容器', () => { 4 | expect(maxArea([1, 8, 6, 2, 5, 4, 8, 3, 7])).toBe(49) 5 | expect(maxArea([1, 3, 2])).toBe(2) 6 | expect(maxArea([1, 3, 2, 2])).toBe(4) 7 | }) 8 | -------------------------------------------------------------------------------- /test/array/contains-duplicate-iii.test.ts: -------------------------------------------------------------------------------- 1 | import { containsNearbyAlmostDuplicate } from '../../src/array/contains-duplicate-iii' 2 | 3 | test('存在重复元素 III', () => { 4 | // 示例 1: 5 | // 输入:nums = [1,2,3,1], k = 3, t = 0 6 | // 输出:true 7 | // 示例 2: 8 | // 输入:nums = [1,0,1,1], k = 1, t = 2 9 | // 输出:true 10 | // 示例 3: 11 | // 输入:nums = [1,5,9,1,5,9], k = 2, t = 3 12 | // 输出:false 13 | expect(containsNearbyAlmostDuplicate([1, 2, 3, 1], 3, 0)).toBeTruthy() 14 | expect(containsNearbyAlmostDuplicate([1, 0, 1, 1], 1, 2)).toBeTruthy() 15 | expect(containsNearbyAlmostDuplicate([1, 5, 9, 1, 5, 9], 2, 3)).toBeFalsy() 16 | }) -------------------------------------------------------------------------------- /test/array/count-good-triplets.test.ts: -------------------------------------------------------------------------------- 1 | import { countGoodTriplets } from '../../src/array/count-good-triplets' 2 | 3 | test('统计好三元组', () => { 4 | // 示例 1: 5 | // 输入:arr = [3,0,1,1,9,7], a = 7, b = 2, c = 3 6 | // 输出:4 7 | // 解释:一共有 4 个好三元组:[(3,0,1), (3,0,1), (3,1,1), (0,1,1)] 。 8 | expect(countGoodTriplets([3, 0, 1, 1, 9, 7], 7, 2, 3)).toBe(4) 9 | 10 | // 示例 2: 11 | // 输入:arr = [1,1,2,2,3], a = 0, b = 0, c = 1 12 | // 输出:0 13 | // 解释:不存在满足所有条件的三元组。 14 | expect(countGoodTriplets([1, 1, 2, 3], 0, 0, 1)).toBe(0) 15 | }) -------------------------------------------------------------------------------- /test/array/count-number-of-nice-subarrays.test.ts: -------------------------------------------------------------------------------- 1 | import { numberOfSubarrays } from '../../src/array/count-number-of-nice-subarrays' 2 | 3 | test('统计「优美子数组」', () => { 4 | expect(numberOfSubarrays([1, 1, 2, 1, 1], 3)).toBe(2) 5 | expect(numberOfSubarrays([2, 4, 6], 1)).toBe(0) 6 | expect(numberOfSubarrays([2, 2, 2, 1, 2, 2, 1, 2, 2, 2], 2)).toBe(16) 7 | }) 8 | -------------------------------------------------------------------------------- /test/array/count-the-repetitions.test.ts: -------------------------------------------------------------------------------- 1 | import { includesInStr, getStrCopyByNum, getMaxRepetitions } from '../../src/array/count-the-repetitions' 2 | 3 | test('判断从 s2 中删除某些字符是否可以变为 s1', () => { 4 | expect(includesInStr('abc', 'ab')).toBe(1) 5 | expect(includesInStr('acb', 'ab')).toBe(1) 6 | expect(includesInStr('ab', 'ab')).toBe(1) 7 | expect(includesInStr('ac', 'ab')).toBe(0) 8 | expect(includesInStr('aa', 'a')).toBe(2) 9 | expect(includesInStr('aaa', 'a')).toBe(3) 10 | expect(includesInStr('abcabc', 'abb')).toBe(1) 11 | }) 12 | 13 | test('获取重复字符串', () => { 14 | expect(getStrCopyByNum('abc', 2)).toBe('abcabc') 15 | expect(getStrCopyByNum('abc', 3)).toBe('abcabcabc') 16 | }) 17 | 18 | test('统计重复个数', () => { 19 | expect(getMaxRepetitions('abc', 4, 'ab', 2)).toBe(2) 20 | expect(getMaxRepetitions('acb', 4, 'ab', 2)).toBe(2) 21 | expect(getMaxRepetitions('abc', 4, 'abb', 2)).toBe(1) 22 | expect(getMaxRepetitions('aaa', 3, 'aa', 1)).toBe(4) 23 | expect(getMaxRepetitions('abccab', 4, 'abc', 2)).toBe(2) 24 | }) 25 | -------------------------------------------------------------------------------- /test/array/daily-temperatures.test.ts: -------------------------------------------------------------------------------- 1 | import { dailyTemperatures } from '../../src/array/daily-temperatures' 2 | 3 | test('每日温度', () => { 4 | expect(dailyTemperatures([73, 74, 75, 71, 69, 72, 76, 73])).toEqual([1, 1, 4, 2, 1, 1, 0, 0]) 5 | }) 6 | -------------------------------------------------------------------------------- /test/array/defuse-the-bomb.test.ts: -------------------------------------------------------------------------------- 1 | import { decrypt } from '../../src/array/defuse-the-bomb' 2 | 3 | test('拆炸弹', () => { 4 | // 示例 1: 5 | // 输入:code = [5,7,1,4], k = 3 6 | // 输出:[12,10,16,13] 7 | // 解释:每个数字都被接下来 3 个数字之和替换。解密后的密码为 [7+1+4, 1+4+5, 4+5+7, 5+7+1]。注意到数组是循环连接的。 8 | expect(decrypt([5, 7, 1, 4], 3)).toEqual([12, 10, 16, 13]) 9 | 10 | // 示例 2: 11 | // 输入:code = [1,2,3,4], k = 0 12 | // 输出:[0,0,0,0] 13 | // 解释:当 k 为 0 时,所有数字都被 0 替换。 14 | expect(decrypt([1, 2, 3, 4], 0)).toEqual([0, 0, 0, 0]) 15 | 16 | // 示例 3: 17 | // 输入:code = [2,4,9,3], k = -2 18 | // 输出:[12,5,6,13] 19 | // 解释:解密后的密码为 [3+9, 2+3, 4+2, 9+4] 。注意到数组是循环连接的。如果 k 是负数,那么和为 之前 的数字。 20 | expect(decrypt([2, 4, 9, 3], -2)).toEqual([12, 5, 6, 13]) 21 | }) -------------------------------------------------------------------------------- /test/array/distance-between-bus-stops.test.ts: -------------------------------------------------------------------------------- 1 | import { distanceBetweenBusStops } from '../../src/array/distance-between-bus-stops' 2 | 3 | test('公交站间的距离', () => { 4 | // 示例 1: 5 | expect(distanceBetweenBusStops([1, 2, 3, 4], 0, 1)).toBe(1) 6 | 7 | // 示例 2: 8 | expect(distanceBetweenBusStops([1, 2, 3, 4], 0, 2)).toBe(3) 9 | 10 | // 示例 3: 11 | expect(distanceBetweenBusStops([1, 2, 3, 4], 0, 3)).toBe(4) 12 | 13 | expect(distanceBetweenBusStops([1, 2, 3, 4], 3, 0)).toBe(4) 14 | }) -------------------------------------------------------------------------------- /test/array/find-common-characters.test.ts: -------------------------------------------------------------------------------- 1 | import { commonChars } from '../../src/array/find-common-characters' 2 | 3 | describe('查找常用字符', () => { 4 | test('查找常用字符', () => { 5 | expect(commonChars(['bella', 'label', 'roller']).sort()).toEqual(['e', 'l', 'l'].sort()) 6 | expect(commonChars(['cool', 'lock', 'cook']).sort()).toEqual(['c', 'o'].sort()) 7 | expect(commonChars(['acabcddd', 'bcbdbcbd', 'baddbadb', 'cbdddcac', 'aacbcccd', 'ccccddda', 'cababaab', 'addcaccd']).sort()).toEqual([].sort()) 8 | }) 9 | }) 10 | -------------------------------------------------------------------------------- /test/array/find-the-duplicate-number.test.ts: -------------------------------------------------------------------------------- 1 | import { findDuplicate } from '../../src/array/find-the-duplicate-number' 2 | 3 | test('寻找重复数', () => { 4 | expect(findDuplicate([1, 3, 4, 2, 2])).toBe(2) 5 | expect(findDuplicate([3, 1, 3, 4, 2])).toBe(3) 6 | }) 7 | -------------------------------------------------------------------------------- /test/array/first-missing-positive.test.ts: -------------------------------------------------------------------------------- 1 | import firstMissingPositive from '../../src/array/first-missing-positive' 2 | 3 | test('缺失的第一个正数', () => { 4 | expect(firstMissingPositive([-1])).toBe(1) 5 | expect(firstMissingPositive([0])).toBe(1) 6 | expect(firstMissingPositive([])).toBe(1) 7 | expect(firstMissingPositive([3, 2, -1])).toBe(1) 8 | expect(firstMissingPositive([3, 4, -1, 1])).toBe(2) 9 | expect(firstMissingPositive([1, 2, 0])).toBe(3) 10 | expect(firstMissingPositive([7, 8, 9, 11, 12])).toBe(1) 11 | }) 12 | -------------------------------------------------------------------------------- /test/array/first-missing-prime-number.test.ts: -------------------------------------------------------------------------------- 1 | import firstMissingPrime, { isPrinme } from '../../src/array/first-missing-prime-number' 2 | 3 | test('是否是素数', () => { 4 | expect(isPrinme(0)).toBe(false) 5 | expect(isPrinme(1)).toBe(false) 6 | expect(isPrinme(2)).toBe(true) 7 | expect(isPrinme(3)).toBe(true) 8 | expect(isPrinme(5)).toBe(true) 9 | expect(isPrinme(7)).toBe(true) 10 | expect(isPrinme(6)).toBe(false) 11 | }) 12 | 13 | test('缺失的第一个素数', () => { 14 | expect(firstMissingPrime([])).toBe(2) 15 | expect(firstMissingPrime([1])).toBe(2) 16 | expect(firstMissingPrime([2])).toBe(3) 17 | expect(firstMissingPrime([3, 5, 7])).toBe(2) 18 | expect(firstMissingPrime([3, 8, 7, 2, 0])).toBe(5) 19 | expect(firstMissingPrime([2, 3, 5, 7, 11, 13, 17, 23, 29])).toBe(19) 20 | }) 21 | -------------------------------------------------------------------------------- /test/array/first-unique-character-in-a-string.test.ts: -------------------------------------------------------------------------------- 1 | import { firstUniqChar } from '../../src/array/first-unique-character-in-a-string' 2 | 3 | test('第一个只出现一次的字符', () => { 4 | expect(firstUniqChar('')).toBe(' ') 5 | expect(firstUniqChar('bbc')).toBe('c') 6 | expect(firstUniqChar('leetcode')).toBe('l') 7 | }) 8 | -------------------------------------------------------------------------------- /test/array/first-unique-number-in-data-stream.test.ts: -------------------------------------------------------------------------------- 1 | import { firstUniqueNumber } from '../../src/array/first-unique-number-in-data-stream' 2 | 3 | test('数据流中第一个唯一的数字', () => { 4 | expect(firstUniqueNumber([], -1)).toBe(-1) 5 | expect(firstUniqueNumber([1, 2, 2, 1, 3, 4, 4, 5, 6], 5)).toBe(3) 6 | expect(firstUniqueNumber([1, 2, 2, 1, 3, 4, 4, 5, 6], 7)).toBe(-1) 7 | expect(firstUniqueNumber([1, 2, 2, 1, 3, 4], 3)).toBe(3) 8 | }) 9 | -------------------------------------------------------------------------------- /test/array/fruit-into-baskets.test.ts: -------------------------------------------------------------------------------- 1 | import { totalFruit } from '../../src/array/fruit-into-baskets' 2 | 3 | test('水果成篮', () => { 4 | // 示例 1: 5 | // 输入:fruits = [1,2,1] 6 | // 输出:3 7 | // 解释:可以采摘全部 3 棵树。 8 | expect(totalFruit([1, 2, 1])).toBe(3) 9 | 10 | // 示例 2: 11 | // 输入:fruits = [0,1,2,2] 12 | // 输出:3 13 | // 解释:可以采摘 [1,2,2] 这三棵树。 14 | // 如果从第一棵树开始采摘,则只能采摘 [0,1] 这两棵树。 15 | expect(totalFruit([0, 1, 2, 2])).toBe(3) 16 | 17 | // 示例 3: 18 | // 输入:fruits = [1,2,3,2,2] 19 | // 输出:4 20 | // 解释:可以采摘 [2,3,2,2] 这四棵树。 21 | // 如果从第一棵树开始采摘,则只能采摘 [1,2] 这两棵树。 22 | expect(totalFruit([1, 2, 3, 2, 2])).toBe(4) 23 | 24 | // 示例 4: 25 | // 输入:fruits = [3,3,3,1,2,1,1,2,3,3,4] 26 | // 输出:5 27 | // 解释:可以采摘 [1,2,1,1,2] 这五棵树。 28 | expect(totalFruit([3, 3, 3, 1, 2, 1, 1, 2, 3, 3, 4])).toBe(5) 29 | }) -------------------------------------------------------------------------------- /test/array/gray-code.test.ts: -------------------------------------------------------------------------------- 1 | import grayCode from '../../src/array/gray-code' 2 | 3 | test('grayCode', () => { 4 | expect(grayCode(1)).toEqual([0, 1]) 5 | expect(grayCode(2)).toEqual([0, 1, 3, 2]) 6 | expect(grayCode(0)).toEqual([0]) 7 | }) 8 | -------------------------------------------------------------------------------- /test/array/happy-number.test.ts: -------------------------------------------------------------------------------- 1 | import { isHappy } from '../../src/array/happy-number' 2 | 3 | test('快乐数', () => { 4 | expect(isHappy(19)).toBe(true) 5 | expect(isHappy(5)).toBe(false) 6 | }) 7 | -------------------------------------------------------------------------------- /test/array/highest-frequency-ip.test.ts: -------------------------------------------------------------------------------- 1 | import { highestFrequency } from '../../src/array/highest-frequency-ip' 2 | 3 | test('最高频率的IP', () => { 4 | expect(highestFrequency(['192.168.1.1', '192.118.2.1', '192.168.1.1'])).toEqual('192.168.1.1') 5 | expect(highestFrequency(['192.168.1.1', '192.118.2.1', '192.168.1.1', '192.118.2.1', '192.118.2.1'])).toEqual('192.118.2.1') 6 | }) 7 | -------------------------------------------------------------------------------- /test/array/house-robber.test.ts: -------------------------------------------------------------------------------- 1 | import { rob } from '../../src/array/house-robber' 2 | 3 | test('打家劫舍', () => { 4 | expect(rob()).toBe(0) 5 | expect(rob([1])).toBe(1) 6 | expect(rob([])).toBe(0) 7 | expect(rob([1, 2, 3, 1])).toBe(4) 8 | expect(rob([2, 7, 9, 3, 1])).toBe(12) 9 | expect( 10 | rob([ 11 | 828, 125, 740, 724, 983, 321, 773, 678, 841, 842, 875, 377, 674, 144, 340, 12 | 467, 625, 916, 463, 922, 255, 662, 692, 123, 778, 766, 254, 559, 480, 483, 13 | 904, 60, 305, 966, 872, 935, 626, 691, 832, 998, 508, 657, 215, 162, 858, 14 | 179, 869, 674, 452, 158, 520, 138, 847, 452, 764, 995, 600, 568, 92, 496, 15 | 533, 404, 186, 345, 304, 420, 181, 73, 547, 281, 374, 376, 454, 438, 553, 16 | 929, 140, 298, 451, 674, 91, 531, 685, 862, 446, 262, 477, 573, 627, 624, 17 | 814, 103, 294, 388, 18 | ]) 19 | ).toBe(29123) 20 | }) 21 | -------------------------------------------------------------------------------- /test/array/jump-game-ii.test.ts: -------------------------------------------------------------------------------- 1 | import { jump } from '../../src/array/jump-game-ii' 2 | 3 | test('跳跃游戏II', () => { 4 | expect(jump([2, 3, 1, 1, 4])).toBe(2) 5 | expect(jump([4, 3])).toBe(1) 6 | }) 7 | -------------------------------------------------------------------------------- /test/array/jump-game.test.ts: -------------------------------------------------------------------------------- 1 | import { canJump } from '../../src/array/jump-game' 2 | 3 | test('跳跃游戏', () => { 4 | expect(canJump([2, 3, 1, 1, 4])).toBe(true) 5 | expect(canJump([3, 2, 1, 0, 4])).toBe(false) 6 | }) 7 | -------------------------------------------------------------------------------- /test/array/kids-with-the-greatest-number-of-candies.test.ts: -------------------------------------------------------------------------------- 1 | import { kidsWithCandies } from '../../src/array/kids-with-the-greatest-number-of-candies' 2 | 3 | test('拥有最多糖果的孩子', () => { 4 | expect(kidsWithCandies([2, 3, 5, 1, 3], 3)).toEqual([true, true, true, false, true]) 5 | expect(kidsWithCandies([4, 2, 1, 1, 2], 1)).toEqual([true, false, false, false, false]) 6 | expect(kidsWithCandies([12, 1, 12], 10)).toEqual([true, false, true]) 7 | }) 8 | -------------------------------------------------------------------------------- /test/array/kth-largest-element-in-an-array.test.ts: -------------------------------------------------------------------------------- 1 | import findKthLargest from '../../src/array/kth-largest-element-in-an-array' 2 | 3 | test('findKthLargest', () => { 4 | expect(findKthLargest([3, 2, 1, 5, 6, 4], 2)).toEqual(5) 5 | expect(findKthLargest([3, 2, 3, 1, 2, 4, 5, 5, 6], 4)).toEqual(4) 6 | }) 7 | -------------------------------------------------------------------------------- /test/array/kth-smallest-element-in-a-sorted-matrix.test.ts: -------------------------------------------------------------------------------- 1 | import { kthSmallest } from '../../src/array/kth-smallest-element-in-a-sorted-matrix' 2 | 3 | test('有序矩阵中第K小的元素', () => { 4 | expect(kthSmallest([ 5 | [1, 5, 9], 6 | [10, 11, 13], 7 | [12, 13, 15] 8 | ], 8)).toBe(13) 9 | 10 | expect(kthSmallest([ 11 | [1, 5, 7], 12 | [3, 7, 8], 13 | [4, 8, 9] 14 | ], 4)).toBe(5) 15 | 16 | expect(kthSmallest([ 17 | [1, 2], 18 | [3, 4] 19 | ], 3)).toBe(3) 20 | }) 21 | -------------------------------------------------------------------------------- /test/array/lemonade-change.test.ts: -------------------------------------------------------------------------------- 1 | import { lemonadeChange } from '../../src/array/lemonade-change' 2 | 3 | test('柠檬水找零', () => { 4 | expect(lemonadeChange([5, 5, 5, 5, 10, 5, 10, 10, 10, 20])).toBe(true) 5 | expect(lemonadeChange([5, 5, 5, 10, 20])).toBe(true) 6 | expect(lemonadeChange([5, 5, 10])).toBe(true) 7 | expect(lemonadeChange([10, 10])).toBe(false) 8 | expect(lemonadeChange([5, 5, 10, 10, 20])).toBe(false) 9 | }) 10 | -------------------------------------------------------------------------------- /test/array/letter-combinations-of-a-phone-number.test.ts: -------------------------------------------------------------------------------- 1 | import letterCombinations from '../../src/array/letter-combinations-of-a-phone-number' 2 | 3 | test('letterCombinations', () => { 4 | expect(letterCombinations('')).toEqual([]) 5 | expect(letterCombinations('4')).toEqual(['g', 'h', 'i']) 6 | expect(letterCombinations('8619')).toEqual(['tmw', 7 | 'tmx', 8 | 'tmy', 9 | 'tmz', 10 | 'tnw', 11 | 'tnx', 12 | 'tny', 13 | 'tnz', 14 | 'tow', 15 | 'tox', 16 | 'toy', 17 | 'toz', 18 | 'umw', 19 | 'umx', 20 | 'umy', 21 | 'umz', 22 | 'unw', 23 | 'unx', 24 | 'uny', 25 | 'unz', 26 | 'uow', 27 | 'uox', 28 | 'uoy', 29 | 'uoz', 30 | 'vmw', 31 | 'vmx', 32 | 'vmy', 33 | 'vmz', 34 | 'vnw', 35 | 'vnx', 36 | 'vny', 37 | 'vnz', 38 | 'vow', 39 | 'vox', 40 | 'voy', 41 | 'voz']) 42 | expect(letterCombinations('23')).toEqual(['ad', 'ae', 'af', 'bd', 'be', 'bf', 'cd', 'ce', 'cf']) 43 | }) 44 | -------------------------------------------------------------------------------- /test/array/longest-uncommon-subsequence-ii.test.ts: -------------------------------------------------------------------------------- 1 | import { isSubsequence, findLUSlength } from '../../src/array/longest-uncommon-subsequence-ii' 2 | 3 | describe('最长特殊序列 II', () => { 4 | test('判断字符串是不是另一个字符串的子序列', () => { 5 | expect(isSubsequence('abc', 'abcd')).toBeTruthy() 6 | expect(isSubsequence('abc', 'def')).toBeFalsy() 7 | expect(isSubsequence('abcd', 'efg')).toBeFalsy() 8 | }) 9 | 10 | test('最长特殊序列 II', () => { 11 | expect(findLUSlength(["aba","cdc","eae"])).toBe(3) 12 | expect(findLUSlength(["aaa","aaa","aa"])).toBe(-1) 13 | }) 14 | }) 15 | -------------------------------------------------------------------------------- /test/array/loop-asc-array.test.ts: -------------------------------------------------------------------------------- 1 | import loopAscArray from '../../src/array/loop-asc-array' 2 | 3 | test('loopAscArray', () => { 4 | expect(loopAscArray([], 6)).toBe(false) 5 | expect(loopAscArray([6, 7, 0, 2, 3, 4, 5], 6)).toBe(true) 6 | expect(loopAscArray([6, 7, 0, 2, 3, 4, 5], 4)).toBe(true) 7 | expect(loopAscArray([7, 0, 2, 3], 7)).toBe(true) 8 | expect(loopAscArray([0, 3, 4, 6, 7], 0)).toBe(true) 9 | expect(loopAscArray([6, 7, 0, 3, 4], 0)).toBe(true) 10 | expect(loopAscArray([6, 7, 0, 3, 4], 5)).toBe(false) 11 | expect(loopAscArray([1, 2, 3, 4, 5], 6)).toBe(false) 12 | expect(loopAscArray([1, 2, 3, 4, 5], 1)).toBe(true) 13 | expect(loopAscArray([3, 4, 5, 1, 1, 2], 1)).toBe(true) 14 | expect(loopAscArray([3, 4, 5, 1, 1, 2], 6)).toBe(false) 15 | expect(loopAscArray([3, 4, 5, 1, 1, 2], 0)).toBe(false) 16 | expect(loopAscArray([1, 0, 1, 1, 1], 0)).toBe(true) 17 | expect(loopAscArray([1, 0, 1, 1, 1], 2)).toBe(false) 18 | expect(loopAscArray([3], 2)).toBe(false) 19 | expect(loopAscArray([2], 2)).toBe(true) 20 | expect(loopAscArray([1, 1, 1], 2)).toBe(false) 21 | expect(loopAscArray([1, 1, 1], 1)).toBe(true) 22 | expect(loopAscArray([1, 1, 1, 0], 1)).toBe(true) 23 | expect(loopAscArray([1, 1, 1, 0], 2)).toBe(false) 24 | }) 25 | -------------------------------------------------------------------------------- /test/array/lru-cache.test.ts: -------------------------------------------------------------------------------- 1 | import LRUCache from '../../src/array/lru-cache' 2 | 3 | test('LRU缓存机制', () => { 4 | const cache = new LRUCache(2 /* 缓存容量 */) 5 | 6 | cache.put(1, 1) 7 | cache.put(2, 2) 8 | expect(cache.get(1)).toBe(1) // 返回 1 9 | cache.put(3, 3) // 该操作会使得密钥 2 作废 10 | expect(cache.get(2)).toBe(-1) // 返回 -1 (未找到) 11 | cache.put(4, 4) // 该操作会使得密钥 1 作废 12 | expect(cache.get(1)).toBe(-1) // 返回 -1 (未找到) 13 | expect(cache.get(3)).toBe(3) // 返回 3 14 | expect(cache.get(4)).toBe(4) // 返回 4 15 | }) 16 | -------------------------------------------------------------------------------- /test/array/majority-element.test.ts: -------------------------------------------------------------------------------- 1 | import { majorityElement } from '../../src/array/majority-element' 2 | 3 | test('主元素', () => { 4 | expect(majorityElement([1, 2, 5, 9, 5, 9, 5, 5, 5])).toBe(5) 5 | expect(majorityElement([1, 1, 1, 1, 2, 2, 2])).toBe(1) 6 | expect(majorityElement([1, 1, 1, 2, 2, 2, 2])).toBe(2) 7 | expect(majorityElement([3, 2])).toBe(-1) 8 | expect(majorityElement([2, 2, 1, 1, 1, 2, 2])).toBe(2) 9 | expect(majorityElement([1])).toBe(1) 10 | expect(majorityElement([2, 2])).toBe(2) 11 | }) 12 | -------------------------------------------------------------------------------- /test/array/maximal-square.test.ts: -------------------------------------------------------------------------------- 1 | import { maximalSquare } from '../../src/array/maximal-square' 2 | 3 | test('最大正方形', () => { 4 | expect(maximalSquare([])).toBe(0) 5 | 6 | expect(maximalSquare([ 7 | [1, 0, 1, 0, 0], 8 | [1, 0, 1, 1, 1], 9 | [1, 1, 1, 1, 1], 10 | [1, 0, 0, 1, 0] 11 | ])).toBe(4) 12 | 13 | expect(maximalSquare([ 14 | [0, 0, 0], 15 | [1, 1, 1] 16 | ])).toBe(1) 17 | }) 18 | -------------------------------------------------------------------------------- /test/array/maximum-and-minimum.test.ts: -------------------------------------------------------------------------------- 1 | import { maxAndMin } from '../../src/array/maximum-and-minimum' 2 | 3 | test('最大数和最小数', () => { 4 | expect(maxAndMin([ 5 | [1, 2, 3], 6 | [4, 3, 2], 7 | [6, 4, 4] 8 | ])).toEqual([6, 1]) 9 | 10 | expect(maxAndMin([])).toEqual([]) 11 | }) 12 | -------------------------------------------------------------------------------- /test/array/maximum-gap.test.ts: -------------------------------------------------------------------------------- 1 | import maximumGap from '../../src/array/maximum-gap' 2 | import inData from './maximum-gap.test.data' 3 | 4 | test('最大间距', () => { 5 | expect(maximumGap([0, 0])).toBe(0) 6 | expect(maximumGap([1, 1])).toBe(0) 7 | expect(maximumGap([1, 1, 1, 1])).toBe(0) 8 | expect(maximumGap([2, 2, 0])).toBe(2) 9 | expect(maximumGap([3, 6, 9, 1])).toBe(3) 10 | expect(maximumGap([10])).toBe(0) 11 | expect(maximumGap([13, 16, 19, 1])).toBe(12) 12 | expect(maximumGap([1, 3, 100])).toBe(97) 13 | expect(maximumGap(inData)).toBe(2147428092) 14 | }) 15 | -------------------------------------------------------------------------------- /test/array/maximum-length-of-pair-chain.test.ts: -------------------------------------------------------------------------------- 1 | import { findLongestChain } from '../../src/array/maximum-length-of-pair-chain' 2 | 3 | test('最长数对链', () => { 4 | // 示例: 5 | // 输入:[[1,2], [2,3], [3,4]] 6 | // 输出:2 7 | // 解释:最长的数对链是 [1,2] -> [3,4] 8 | expect(findLongestChain([[1, 2], [2, 3], [3, 4]])).toBe(2) 9 | }) -------------------------------------------------------------------------------- /test/array/maximum-length-of-repeated-subarray.test.ts: -------------------------------------------------------------------------------- 1 | import { findLength } from '../../src/array/maximum-length-of-repeated-subarray' 2 | 3 | test('最长重复子数组', () => { 4 | expect(findLength([], [])).toBe(0) 5 | expect(findLength([1, 2, 3, 2, 1], [3, 2, 1, 4, 7])).toBe(3) 6 | }) 7 | -------------------------------------------------------------------------------- /test/array/maximum-product-subarray.test.ts: -------------------------------------------------------------------------------- 1 | import { maxProduct } from '../../src/array/maximum-product-subarray' 2 | 3 | test('', () => { 4 | expect(maxProduct([2, 3, -2, 4])).toBe(6) 5 | expect(maxProduct([-2, 0, -1])).toBe(0) 6 | }) 7 | -------------------------------------------------------------------------------- /test/array/maximum-subarray.test.ts: -------------------------------------------------------------------------------- 1 | import { maxSubArray } from '../../src/array/maximum-subarray' 2 | 3 | test('最大子序和', () => { 4 | expect(maxSubArray([-2, 1, -3, 4, -1, 2, 1, -5, 4])).toBe(6) 5 | }) 6 | -------------------------------------------------------------------------------- /test/array/merge-intervals.test.ts: -------------------------------------------------------------------------------- 1 | import { merge } from '../../src/array/merge-intervals' 2 | 3 | test('合并区间', () => { 4 | expect(merge([[1, 3], [2, 6], [8, 10], [15, 18]])).toEqual([[1, 6], [8, 10], [15, 18]]) 5 | expect(merge([[1, 4], [4, 5]])).toEqual([[1, 5]]) 6 | expect(merge([[1, 3]])).toEqual([[1, 3]]) 7 | expect(merge([[1, 4], [5, 6]])).toEqual([[1, 4], [5, 6]]) 8 | expect(merge([[1, 4], [1, 4]])).toEqual([[1, 4]]) 9 | expect(merge([[1, 4], [2, 3]])).toEqual([[1, 4]]) 10 | expect(merge([[1, 4], [0, 2], [3, 5]])).toEqual([[0, 5]]) 11 | expect(merge([[1, 3], [4, 6], [4, 7]])).toEqual([[1, 3], [4, 7]]) 12 | expect(merge([[2, 3], [2, 2], [3, 3], [1, 3], [5, 7], [2, 2], [4, 6]])).toEqual([[1, 3], [4, 7]]) 13 | }) 14 | -------------------------------------------------------------------------------- /test/array/minimum-cost-for-tickets.test.ts: -------------------------------------------------------------------------------- 1 | import { mincostTickets } from '../../src/array/minimum-cost-for-tickets' 2 | 3 | test('最低票价', () => { 4 | expect(mincostTickets([1, 4, 6, 7, 8, 20], [2, 7, 15])).toBe(11) 5 | expect(mincostTickets([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 30, 31], [2, 7, 15])).toBe(17) 6 | }) 7 | -------------------------------------------------------------------------------- /test/array/minimum-cost-to-hire-k-workers.test.ts: -------------------------------------------------------------------------------- 1 | import { mincostToHireWorkers } from '../../src/array/minimum-cost-to-hire-k-workers' 2 | 3 | test('雇佣 K 名工人的最低成本', () => { 4 | // 示例 1: 5 | // 输入: quality = [10,20,5], wage = [70,50,30], k = 2 6 | // 输出: 105.00000 7 | // 解释: 我们向 0 号工人支付 70,向 2 号工人支付 35。 8 | expect(mincostToHireWorkers([10, 20, 5], [70, 50, 30], 2).toFixed(5)).toBe('105.00000') 9 | 10 | // 示例 2: 11 | // 输入: quality = [3,1,10,10,1], wage = [4,8,2,2,7], k = 3 12 | // 输出: 30.66667 13 | // 解释: 我们向 0 号工人支付 4,向 2 号和 3 号分别支付 13.33333。 14 | expect(mincostToHireWorkers([3, 1, 10, 10, 1], [4, 8, 2, 2, 7], 3).toFixed(5)).toBe('30.66667') 15 | }) -------------------------------------------------------------------------------- /test/array/number-of-boomerangs.test.ts: -------------------------------------------------------------------------------- 1 | import { numberOfBoomerangs } from '../../src/array/number-of-boomerangs' 2 | 3 | test('回旋镖的数量', () => { 4 | // 示例 1: 5 | // 输入:points = [[0,0],[1,0],[2,0]] 6 | // 输出:2 7 | // 解释:两个回旋镖为 [[1,0],[0,0],[2,0]] 和 [[1,0],[2,0],[0,0]] 8 | 9 | // 示例 2: 10 | // 输入:points = [[1,1],[2,2],[3,3]] 11 | // 输出:2 12 | 13 | // 示例 3: 14 | // 输入:points = [[1,1]] 15 | // 输出:0 16 | 17 | expect(numberOfBoomerangs([[0, 0], [1, 0], [2, 0]])).toBe(2) 18 | expect(numberOfBoomerangs([[1, 1], [2, 2], [3, 3]])).toBe(2) 19 | expect(numberOfBoomerangs([[1, 1]])).toBe(0) 20 | }) -------------------------------------------------------------------------------- /test/array/number-of-islands.test.ts: -------------------------------------------------------------------------------- 1 | import { numIslands } from '../../src/array/number-of-islands' 2 | 3 | test('岛屿的个数', () => { 4 | expect(numIslands([ 5 | [1, 1, 0, 0, 0], 6 | [0, 1, 0, 0, 1], 7 | [0, 0, 0, 1, 1], 8 | [0, 0, 0, 0, 0], 9 | [0, 0, 0, 0, 1] 10 | ])).toBe(3) 11 | 12 | expect(numIslands([ 13 | [1, 1] 14 | ])).toBe(1) 15 | 16 | expect(numIslands([])).toBe(0) 17 | }) 18 | -------------------------------------------------------------------------------- /test/array/partition-array.test.ts: -------------------------------------------------------------------------------- 1 | import partitionArray from '../../src/array/partition-array' 2 | 3 | test('loopAscArray', () => { 4 | expect(partitionArray([], 9)).toEqual(0) 5 | expect(partitionArray([7, 7, 9, 8, 6, 6, 8, 7, 9, 8, 6, 6], 10)).toEqual(12) 6 | expect(partitionArray([3, 2, 2, 1], 2)).toEqual(1) 7 | }) 8 | -------------------------------------------------------------------------------- /test/array/product-of-array-except-self.test.ts: -------------------------------------------------------------------------------- 1 | import { productExceptSelf } from '../../src/array/product-of-array-except-self' 2 | 3 | test('除自身以外数组的乘积', () => { 4 | expect(productExceptSelf([1, 2, 3, 4])).toEqual([24, 12, 8, 6]) 5 | }) 6 | -------------------------------------------------------------------------------- /test/array/remove-duplicates-from-sorted-array.test.ts: -------------------------------------------------------------------------------- 1 | import removeDuplicates from '../../src/array/remove-duplicates-from-sorted-array' 2 | 3 | test('removeDuplicates', () => { 4 | expect(removeDuplicates([])).toBe(0) 5 | 6 | const nums = [1, 1, 2] 7 | expect(removeDuplicates(nums)).toBe(2) 8 | 9 | expect(nums).toEqual([1, 2]) 10 | }) 11 | 12 | test('removeDuplicates2', () => { 13 | const nums = [1, 2] 14 | expect(removeDuplicates(nums)).toBe(2) 15 | 16 | expect(nums).toEqual([1, 2]) 17 | }) 18 | -------------------------------------------------------------------------------- /test/array/reverse-pairs.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | reversePairs, 3 | merge, 4 | mergeSort, 5 | resetCount 6 | } from '../../src/array/reverse-pairs' 7 | 8 | describe('逆序对', () => { 9 | beforeEach(() => { 10 | resetCount() 11 | }) 12 | 13 | test('归并排序 - 合并左右', () => { 14 | expect(merge([7], [5])).toEqual([5, 7]) 15 | expect(merge([2], [3])).toEqual([2, 3]) 16 | expect(merge([2, 3], [4, 5])).toEqual([2, 3, 4, 5]) 17 | }) 18 | 19 | test('归并排序', () => { 20 | expect(mergeSort([2, 4, 3, 5])).toEqual([2, 3, 4, 5]) 21 | expect(mergeSort([2, 4, 3, 0])).toEqual([0, 2, 3, 4]) 22 | }) 23 | 24 | test('逆序对', () => { 25 | expect(reversePairs([7, 5, 6, 4])).toBe(5) 26 | expect(reversePairs([2, 4, 1, 3, 5])).toBe(3) 27 | expect(reversePairs([1, 2, 3, 4])).toBe(0) 28 | }) 29 | }) 30 | -------------------------------------------------------------------------------- /test/array/rotate-array.test.ts: -------------------------------------------------------------------------------- 1 | import { rotate } from '../../src/array/rotate-array' 2 | 3 | test('轮转数组', () => { 4 | const arr = [1, 2, 3, 4, 5, 6, 7] 5 | rotate(arr, 3) 6 | expect(arr).toEqual([5, 6, 7, 1, 2, 3, 4]) 7 | 8 | const arr2 = [1, 2] 9 | rotate(arr2, 3) 10 | expect(arr2).toEqual([2, 1]) 11 | 12 | const arr3 = [1, 2, 3] 13 | rotate(arr3, 4) 14 | expect(arr3).toEqual([3, 1, 2]) 15 | 16 | const arr4 = [1, 2] 17 | rotate(arr4, 5) 18 | expect(arr4).toEqual([2, 1]) 19 | }) -------------------------------------------------------------------------------- /test/array/search-in-rotated-sorted-array.test.ts: -------------------------------------------------------------------------------- 1 | import { search } from '../../src/array/search-in-rotated-sorted-array' 2 | 3 | test('搜索旋转排序数组', () => { 4 | expect(search([4, 5, 6, 7, 0, 1, 2], 0)).toBe(4) 5 | expect(search([4, 5, 6, 7, 0, 1, 2], 3)).toBe(-1) 6 | expect(search([6, 7, 0, 1, 2, 4, 5], 7)).toBe(1) 7 | expect(search([6, 7, 0, 1, 2, 4], 4)).toBe(5) 8 | }) 9 | -------------------------------------------------------------------------------- /test/array/search-insert-position.test.ts: -------------------------------------------------------------------------------- 1 | import searchInsert from '../../src/array/search-insert-position' 2 | 3 | test('searchInsert', () => { 4 | expect(searchInsert([1, 3, 5, 6], 5)).toEqual(2) 5 | expect(searchInsert([1, 3, 5, 6], 2)).toEqual(1) 6 | expect(searchInsert([1, 3, 5, 6], 7)).toEqual(4) 7 | expect(searchInsert([1, 3, 5, 6], 0)).toEqual(0) 8 | }) 9 | -------------------------------------------------------------------------------- /test/array/select-sort.test.ts: -------------------------------------------------------------------------------- 1 | import selectSort from '../../src/array/select-sort' 2 | 3 | test('selectSort', () => { 4 | expect(selectSort([1, 2, 3])).toEqual([1, 2, 3]) 5 | expect(selectSort([3, 2, 1])).toEqual([1, 2, 3]) 6 | expect(selectSort([])).toEqual([]) 7 | expect(selectSort([3, 6, 4, 5, 6, 8])).toEqual([3, 4, 5, 6, 6, 8]) 8 | expect(selectSort([1, 1, 1])).toEqual([1, 1, 1]) 9 | expect(selectSort([-1, -10, 3])).toEqual([-10, -1, 3]) 10 | expect(selectSort([7, 2, 8, 3, 6, 3])).toEqual([2, 3, 3, 6, 7, 8]) 11 | }) 12 | -------------------------------------------------------------------------------- /test/array/shortest-word-distance.test.ts: -------------------------------------------------------------------------------- 1 | import { shortestDistance } from '../../src/array/shortest-word-distance' 2 | 3 | test('最短单词距离', () => { 4 | // 示例 1: 5 | // 输入: wordsDict = ["practice", "makes", "perfect", "coding", "makes"], word1 = "coding", word2 = "practice" 6 | // 输出: 3 7 | const wordsDict = ["practice", "makes", "perfect", "coding", "makes"] 8 | const word1 = "coding" 9 | const word2 = "practice" 10 | expect(shortestDistance(wordsDict, word1, word2)).toBe(3) 11 | 12 | // 示例 2: 13 | // 输入: wordsDict = ["practice", "makes", "perfect", "coding", "makes"], word1 = "makes", word2 = "coding" 14 | // 输出: 1 15 | const wordsDict2 = ["practice", "makes", "perfect", "coding", "makes"] 16 | const word21 = "makes" 17 | const word22 = "coding" 18 | expect(shortestDistance(wordsDict2, word21, word22)).toBe(1) 19 | }) -------------------------------------------------------------------------------- /test/array/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof.test.ts: -------------------------------------------------------------------------------- 1 | import { singleNumbers } from '../../src/array/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof' 2 | 3 | test('面试题56 - I. 数组中数字出现的次数', () => { 4 | expect(singleNumbers([4, 1, 4, 6]).some(i => [1, 6].includes(i))).toBe(true) 5 | expect(singleNumbers([1, 2, 10, 4, 1, 4, 3, 3]).some(i => [2, 10].includes(i))).toBe(true) 6 | }) 7 | -------------------------------------------------------------------------------- /test/array/single-number.test.ts: -------------------------------------------------------------------------------- 1 | import { singleNumber } from '../../src/array/single-number' 2 | 3 | test('只出现一次的数字', () => { 4 | expect(singleNumber([2, 2, 1])).toBe(1) 5 | expect(singleNumber([4, 1, 2, 1, 2])).toBe(4) 6 | }) 7 | -------------------------------------------------------------------------------- /test/array/sort-array-by-parity.test.ts: -------------------------------------------------------------------------------- 1 | import sortArrayByParity from '../../src/array/sort-array-by-parity' 2 | 3 | test('sortArrayByParity', () => { 4 | expect(sortArrayByParity([4, 2, 5, 7])).toEqual([2, 5, 4, 7]) 5 | }) 6 | -------------------------------------------------------------------------------- /test/array/sort-transformed-array.test.ts: -------------------------------------------------------------------------------- 1 | import { sortTransformedArray } from '../../src/array/sort-transformed-array' 2 | 3 | test('有序转化数组', () => { 4 | // 示例 1: 5 | // 输入: nums = [-4,-2,2,4], a = 1, b = 3, c = 5 6 | // 输出: [3,9,15,33] 7 | 8 | // 示例 2: 9 | // 输入: nums = [-4,-2,2,4], a = -1, b = 3, c = 5 10 | // 输出: [-23,-5,1,7] 11 | 12 | expect(sortTransformedArray([-4, -2, 2, 4], 1, 3, 5)).toEqual([3, 9, 15, 33]) 13 | expect(sortTransformedArray([-4, -2, 2, 4], -1, 3, 5)).toEqual([-23, -5, 1, 7]) 14 | }) -------------------------------------------------------------------------------- /test/array/spiral-matrix.test.ts: -------------------------------------------------------------------------------- 1 | import { spiralOrder } from '../../src/array/spiral-matrix' 2 | 3 | test('螺旋矩阵', () => { 4 | // 示例 1: 5 | // 输入:matrix = [[1,2,3],[4,5,6],[7,8,9]] 6 | // 输出:[1,2,3,6,9,8,7,4,5] 7 | expect(spiralOrder([[1, 2, 3], [4, 5, 6], [7, 8, 9]])).toEqual([1, 2, 3, 6, 9, 8, 7, 4, 5]) 8 | 9 | // 示例 2: 10 | // 输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]] 11 | // 输出:[1,2,3,4,8,12,11,10,9,5,6,7] 12 | expect(spiralOrder([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])).toEqual([1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7]) 13 | 14 | expect(spiralOrder([[]])).toEqual([]) 15 | expect(spiralOrder([])).toEqual([]) 16 | expect(spiralOrder([[3], [2]])).toEqual([3, 2]) 17 | }) -------------------------------------------------------------------------------- /test/array/subarray-sums-divisible-by-k.test.ts: -------------------------------------------------------------------------------- 1 | import { subarraysDivByK } from '../../src/array/subarray-sums-divisible-by-k' 2 | 3 | test('和可被K整除的子数组', () => { 4 | expect(subarraysDivByK([4, 5, 0, -2, -3, 1], 5)).toBe(7) 5 | }) 6 | -------------------------------------------------------------------------------- /test/array/wiggle-sort-ii.test.ts: -------------------------------------------------------------------------------- 1 | import { wiggleSort } from '../../src/array/wiggle-sort-ii' 2 | 3 | test('摆动排序', () => { 4 | const arr = [1, 5, 1, 1, 6, 4] 5 | wiggleSort(arr) 6 | console.log(arr) 7 | let isRight = true 8 | for (let i = 0; i < arr.length - 1; i = i + 2) { 9 | if (arr[i + 1] > arr[i] && (i - 1 <= 0 || arr[i] < arr[i - 1])) { 10 | continue 11 | } else { 12 | isRight = false 13 | } 14 | } 15 | 16 | expect(isRight).toBeTruthy() 17 | }) -------------------------------------------------------------------------------- /test/array/x-of-a-kind-in-a-deck-of-cards.test.ts: -------------------------------------------------------------------------------- 1 | import hasGroupsSizeX from '../../src/array/x-of-a-kind-in-a-deck-of-cards' 2 | 3 | test('hasGroupsSizeX', () => { 4 | expect(hasGroupsSizeX([1, 2, 3, 4, 4, 3, 2, 1])).toEqual(true) 5 | expect(hasGroupsSizeX([1, 1, 1, 2, 2, 2, 3, 3])).toEqual(false) 6 | expect(hasGroupsSizeX([1, 1, 2, 2, 2, 2])).toEqual(true) 7 | expect(hasGroupsSizeX([1])).toEqual(false) 8 | expect(hasGroupsSizeX([])).toEqual(false) 9 | expect(hasGroupsSizeX([1, 1])).toEqual(true) 10 | expect(hasGroupsSizeX([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 10, 10, 10])).toEqual(true) 11 | }) 12 | -------------------------------------------------------------------------------- /test/array/zigzag-conversion.test.ts: -------------------------------------------------------------------------------- 1 | import { convert } from '../../src/array/zigzag-conversion' 2 | 3 | test('Z 字形变换', () => { 4 | expect(convert('PAYPALISHIRING', 3)).toBe('PAHNAPLSIIGYIR') 5 | expect(convert('PAYPALISHIRING', 4)).toBe('PINALSIGYAHRPI') 6 | expect(convert('A', 1)).toBe('A') 7 | expect(convert('AB', 1)).toBe('AB') 8 | }) -------------------------------------------------------------------------------- /test/graphs/course-schedule-ii.test.ts: -------------------------------------------------------------------------------- 1 | import { findOrder } from '../../src/graphs/course-schedule-ii' 2 | 3 | test('课程表 II', () => { 4 | expect(findOrder(2, [[1, 0]])).toEqual([0, 1]) 5 | expect(findOrder(3, [[1]])).toEqual([]) 6 | expect(findOrder(4, [[1, 0], [2, 0], [3, 1], [3, 2]])).toEqual([0, 1, 2, 3]) 7 | }) 8 | -------------------------------------------------------------------------------- /test/graphs/find-the-town-judge.test.ts: -------------------------------------------------------------------------------- 1 | import { findJudge } from '../../src/graphs/find-the-town-judge' 2 | 3 | test('找到小镇的法官', () => { 4 | // 示例 1: 5 | // 输入:n = 2, trust = [[1,2]] 6 | // 输出:2 7 | expect(findJudge(2, [[1, 2]])).toBe(2) 8 | 9 | // 示例 2: 10 | // 输入:n = 3, trust = [[1,3],[2,3]] 11 | // 输出:3 12 | expect(findJudge(3, [[1, 3], [2, 3]])).toBe(3) 13 | 14 | // 示例 3: 15 | // 输入:n = 3, trust = [[1,3],[2,3],[3,1]] 16 | // 输出:-1 17 | expect(findJudge(3, [[1, 3], [2, 3], [3, 1]])).toBe(-1) 18 | }) -------------------------------------------------------------------------------- /test/graphs/possible-bipartition.test.ts: -------------------------------------------------------------------------------- 1 | import { possibleBipartition } from '../../src/graphs/possible-bipartition' 2 | 3 | test('可能的二分法', () => { 4 | // 示例 1: 5 | // 输入:n = 4, dislikes = [[1,2],[1,3],[2,4]] 6 | // 输出:true 7 | // 解释:group1 [1,4], group2 [2,3] 8 | expect(possibleBipartition(4, [[1, 2], [1, 3], [2, 4]])).toBeTruthy() 9 | 10 | // 示例 2: 11 | // 输入:n = 3, dislikes = [[1,2],[1,3],[2,3]] 12 | // 输出:false 13 | expect(possibleBipartition(3, [[1, 2], [1, 3], [2, 3]])).toBeFalsy() 14 | 15 | // 示例 3: 16 | // 输入:n = 5, dislikes = [[1,2],[2,3],[3,4],[4,5],[1,5]] 17 | // 输出:false 18 | expect(possibleBipartition(5, [[1, 2], [2, 3], [3, 4], [4, 5], [1, 5]])).toBeFalsy() 19 | 20 | expect(possibleBipartition(1, [])).toBeTruthy() 21 | }) -------------------------------------------------------------------------------- /test/heap/super-ugly-number.test.ts: -------------------------------------------------------------------------------- 1 | import { getPrimes, nthSuperUglyNumber } from '../../src/heap/super-ugly-number' 2 | 3 | test('计算质因数', () => { 4 | expect(getPrimes(6)).toEqual([2, 3]) 5 | expect(getPrimes(4)).toEqual([2]) 6 | expect(getPrimes(180)).toEqual([2, 3, 5]) 7 | }) 8 | 9 | test('超级丑数', () => { 10 | expect(nthSuperUglyNumber(12, [2, 7, 13, 19])).toBe(32) 11 | expect(nthSuperUglyNumber(800, [37, 43, 59, 61, 67, 71, 79, 83, 89, 97, 101, 103, 113, 127, 131, 157, 163, 167, 173, 179, 191, 193, 197, 199, 211, 229, 233, 239, 251, 257])).toBe(411811) 12 | }) 13 | -------------------------------------------------------------------------------- /test/lib/ListNode.test.ts: -------------------------------------------------------------------------------- 1 | import ListNode from "../../src/lib/ListNode" 2 | 3 | test("ListNode", () => { 4 | expect(ListNode).toBeDefined() 5 | expect(new ListNode(1, new ListNode(2))).toBeDefined() 6 | }) -------------------------------------------------------------------------------- /test/lib/MaxPriorityQueue.test.ts: -------------------------------------------------------------------------------- 1 | import { MaxPriorityQueue } from "../../src/lib/MaxPriorityQueue" 2 | 3 | test("MaxPriorityQueue", () => { 4 | const maxPriorityQueue = new MaxPriorityQueue() // 最大优先队列 5 | expect(maxPriorityQueue.isEmpty()).toBeTruthy() 6 | maxPriorityQueue.enqueue(1) 7 | expect(maxPriorityQueue.getSize()).toBe(1) 8 | expect(maxPriorityQueue.peek()).toBe(1) 9 | expect(maxPriorityQueue.isEmpty()).toBeFalsy() 10 | }) -------------------------------------------------------------------------------- /test/lib/MinPriorityQueue.test.ts: -------------------------------------------------------------------------------- 1 | import { MinPriorityQueue } from "../../src/lib/MinPriorityQueue" 2 | 3 | test("MinPriorityQueue", () => { 4 | const minPriorityQueue = new MinPriorityQueue() // 最小优先队列 5 | expect(minPriorityQueue.isEmpty()).toBeTruthy() 6 | expect(minPriorityQueue.peek()).toBeNull() 7 | minPriorityQueue.enqueue(1) 8 | expect(minPriorityQueue.getSize()).toBe(1) 9 | expect(minPriorityQueue.peek()).toBe(1) 10 | expect(minPriorityQueue.isEmpty()).toBeFalsy() 11 | minPriorityQueue.dequeue() 12 | expect(minPriorityQueue.isEmpty()).toBeTruthy() 13 | expect(minPriorityQueue.dequeue()).toBeNull() 14 | minPriorityQueue.enqueue(1) 15 | minPriorityQueue.enqueue(2) 16 | minPriorityQueue.enqueue(-1) 17 | minPriorityQueue.enqueue(3) 18 | minPriorityQueue.dequeue() 19 | minPriorityQueue.dequeue() 20 | minPriorityQueue.dequeue() 21 | minPriorityQueue.dequeue() 22 | expect(minPriorityQueue.isEmpty()).toBeTruthy() 23 | }) -------------------------------------------------------------------------------- /test/lib/TreeNode.test.ts: -------------------------------------------------------------------------------- 1 | import { TreeNode } from "../../src/lib/TreeNode" 2 | 3 | test("TreeNode", () => { 4 | expect(TreeNode).toBeDefined() 5 | expect(new TreeNode(undefined, new TreeNode(2), new TreeNode(3))).toBeDefined() 6 | }) -------------------------------------------------------------------------------- /test/lib/splice.test.ts: -------------------------------------------------------------------------------- 1 | import { removeItem, putItem } from './../../src/lib/splice' 2 | 3 | test('移除指定位置的元素', () => { 4 | const arr = [1, 2, 3, 4] 5 | const tmp = removeItem(arr, 1) 6 | const expectValue = [1, 3, 4] 7 | expect(tmp).toEqual(expectValue) 8 | }) 9 | 10 | test('在指定位置添加元素', () => { 11 | const arr = [1, 3, 4] 12 | const tmp = putItem(arr, 1, 2) 13 | const expectValue = [1, 2, 3, 4] 14 | expect(tmp).toEqual(expectValue) 15 | }) -------------------------------------------------------------------------------- /test/list/ListNode.test.ts: -------------------------------------------------------------------------------- 1 | import { arrToList, listToArr } from '../../src/lib/ListNode' 2 | 3 | test('数组转链表', () => { 4 | expect(arrToList([1, 2, 3])).toEqual({ next: { next: { next: null, val: 3 }, val: 2 }, val: 1 }) 5 | expect(arrToList([])).toBe(null) 6 | }) 7 | 8 | test('链表转数组', () => { 9 | const list = { next: { next: { next: null, val: 3 }, val: 2 }, val: 1 } 10 | expect(listToArr(list)).toEqual([1, 2, 3]) 11 | expect(listToArr(null)).toEqual([]) 12 | }) -------------------------------------------------------------------------------- /test/list/delete-node-in-a-linked-list.test.ts: -------------------------------------------------------------------------------- 1 | import { deleteNode } from '../../src/list/delete-node-in-a-linked-list' 2 | import { arrToList } from '../../src/lib/ListNode' 3 | 4 | test('删除链表中的节点', () => { 5 | // 示例 1: 6 | // 输入:head = [4,5,1,9], node = 5 7 | // 输出:[4,1,9] 8 | // 解释:指定链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9 9 | const source1 = arrToList([4, 5, 1, 9]) 10 | const source2 = arrToList([4, 1, 9]) 11 | deleteNode(source1!.next) 12 | expect(source1).toEqual(source2) 13 | 14 | // 示例 2: 15 | // 输入:head = [4,5,1,9], node = 1 16 | // 输出:[4,5,9] 17 | // 解释:指定链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9 18 | const source3 = arrToList([4, 5, 1, 9]) 19 | const source4 = arrToList([4, 5, 9]) 20 | deleteNode(source3!.next!.next) 21 | expect(source3).toEqual(source4) 22 | 23 | expect(deleteNode(null)).toBeUndefined() 24 | expect(deleteNode(arrToList([1]))).toBeUndefined() 25 | }) -------------------------------------------------------------------------------- /test/list/linked-list-cycle.test.ts: -------------------------------------------------------------------------------- 1 | import { hasCycle } from '../../src/list/linked-list-cycle' 2 | import { arrToList } from '../../src/lib/ListNode' 3 | 4 | test('环形链表', () => { 5 | const list = arrToList([1, 2, 3]) 6 | list!.next!.next!.next = list 7 | expect(hasCycle(list)).toBe(true) 8 | expect(hasCycle(arrToList([1, 2, 3]))).toBe(false) 9 | }) 10 | -------------------------------------------------------------------------------- /test/list/merge-k-sorted-lists.test.ts: -------------------------------------------------------------------------------- 1 | import { merge, mergeKLists } from '../../src/list/merge-k-sorted-lists' 2 | import { arrToList } from '../../src/lib/ListNode' 3 | 4 | 5 | 6 | test('合并俩链表', () => { 7 | const source1 = arrToList([1, 4, 5]) 8 | const source2 = arrToList([1, 3, 4]) 9 | 10 | expect(merge(source1, source2)).toEqual(arrToList([1, 1, 3, 4, 4, 5])) 11 | expect(merge(null, source2)).toEqual(source2) 12 | expect(merge(source1, null)).toEqual(source1) 13 | }) 14 | 15 | test('合并K个排序链表 - 1', () => { 16 | const source = [ 17 | arrToList([1, 4, 5]), 18 | arrToList([1, 3, 4]), 19 | arrToList([2, 6]) 20 | ] 21 | const out = [1, 1, 2, 3, 4, 4, 5, 6] 22 | expect(mergeKLists(source)).toEqual(arrToList(out)) 23 | }) 24 | 25 | test('合并K个排序链表 - 2', () => { 26 | const source = [ 27 | arrToList([2, 4]), 28 | arrToList([]), 29 | arrToList([-1]) 30 | ] 31 | const out = [-1, 2, 4] 32 | expect(mergeKLists(source)).toEqual(arrToList(out)) 33 | }) 34 | 35 | test('合并K个排序链表 - 3', () => { 36 | const source = [ 37 | arrToList([2, 6]), 38 | arrToList([5]), 39 | arrToList([7]) 40 | ] 41 | const out = [2, 5, 6, 7] 42 | expect(mergeKLists(source)).toEqual(arrToList(out)) 43 | expect(mergeKLists([])).toBeNull() 44 | }) 45 | -------------------------------------------------------------------------------- /test/list/merge-two-sorted-lists.test.ts: -------------------------------------------------------------------------------- 1 | import { mergeTwoLists } from '../../src/list/merge-two-sorted-lists' 2 | import { arrToList } from '../../src/lib/ListNode' 3 | 4 | test('合并两个有序链表', () => { 5 | expect(mergeTwoLists(arrToList([1, 2, 4]), arrToList([1, 3, 4]))).toEqual(arrToList([1, 1, 2, 3, 4, 4])) 6 | expect(mergeTwoLists(arrToList([]), arrToList([0, 3, 3]))).toEqual(arrToList([0, 3, 3])) 7 | expect(mergeTwoLists(arrToList([1, 3, 8, 11, 15]), arrToList([2]))).toEqual(arrToList([1, 2, 3, 8, 11, 15])) 8 | }) 9 | -------------------------------------------------------------------------------- /test/list/middle-of-the-linked-list.test.ts: -------------------------------------------------------------------------------- 1 | import { middleNode } from '../../src/list/middle-of-the-linked-list' 2 | import { arrToList } from '../../src/lib/ListNode' 3 | 4 | test('链表的中间节点', () => { 5 | expect(middleNode(arrToList([1]))).toEqual(arrToList([1])) 6 | expect(middleNode(arrToList([1, 2]))).toEqual(arrToList([2])) 7 | expect(middleNode(arrToList([1, 2, 3, 4, 5]))).toEqual(arrToList([3, 4, 5])) 8 | expect(middleNode(arrToList([1, 2, 3, 4, 5, 6]))).toEqual(arrToList([4, 5, 6])) 9 | }) 10 | -------------------------------------------------------------------------------- /test/list/reverse-linked-list.test.ts: -------------------------------------------------------------------------------- 1 | import { reverseList } from '../../src/list/reverse-linked-list' 2 | import { arrToList } from '../../src/lib/ListNode' 3 | 4 | test('反转链表', () => { 5 | const source1 = arrToList([1, 4, 5]) 6 | const source2 = arrToList([5, 4, 1]) 7 | expect(reverseList(source1)).toEqual(source2) 8 | }) -------------------------------------------------------------------------------- /test/list/reverse-nodes-in-k-group.test.ts: -------------------------------------------------------------------------------- 1 | import { reverseKGroup } from '../../src/list/reverse-nodes-in-k-group' 2 | import { arrToList, listToArr } from '../../src/lib/ListNode' 3 | 4 | test('K个一组翻转链表', () => { 5 | const res = reverseKGroup(arrToList([1, 2, 3, 4, 5]), 3) 6 | expect(listToArr(res)).toEqual([3, 2, 1, 4, 5]) 7 | expect(res).toEqual(arrToList([3, 2, 1, 4, 5])) 8 | expect(reverseKGroup(arrToList([1, 2, 3, 4, 5]), 2)).toEqual(arrToList([2, 1, 4, 3, 5])) 9 | expect(reverseKGroup(arrToList([1, 2, 3, 4, 5, 6]), 2)).toEqual(arrToList([2, 1, 4, 3, 6, 5])) 10 | expect(reverseKGroup(arrToList([1, 2, 3, 4, 5, 6, 7, 8]), 2)).toEqual(arrToList([2, 1, 4, 3, 6, 5, 8, 7])) 11 | }) 12 | -------------------------------------------------------------------------------- /test/list/sort-list.test.ts: -------------------------------------------------------------------------------- 1 | import { sortList } from '../../src/list/sort-list' 2 | import { arrToList } from '../../src/lib/ListNode' 3 | 4 | test('链表排序', () => { 5 | const source = [4, 2, 1, 3] 6 | expect(sortList(arrToList(source))).toEqual(arrToList(source.sort((a, b) => a - b))) 7 | 8 | const source2 = [-1, 5, 3, 4, 0] 9 | expect(sortList(arrToList(source2))).toEqual(arrToList(source2.sort((a, b) => a - b))) 10 | 11 | const source3 = [1, 3, 2] 12 | expect(sortList(arrToList(source3))).toEqual(arrToList([1, 2, 3])) 13 | 14 | const source4 = [1, 7, 2, 6] 15 | expect(sortList(arrToList(source4))).toEqual(arrToList([1, 2, 6, 7])) 16 | }) 17 | -------------------------------------------------------------------------------- /test/list/swap-nodes-in-pairs.test.ts: -------------------------------------------------------------------------------- 1 | import { swapPairs } from '../../src/list/swap-nodes-in-pairs' 2 | import { arrToList } from '../../src/lib/ListNode' 3 | 4 | test('两两交换链表中的节点', () => { 5 | expect(swapPairs(arrToList([1, 2, 3, 4]))).toEqual(arrToList([2, 1, 4, 3])) 6 | expect(swapPairs(arrToList([1]))).toEqual(arrToList([1])) 7 | expect(swapPairs(arrToList([]))).toEqual(arrToList([])) 8 | }) -------------------------------------------------------------------------------- /test/map/check-if-one-string-swap-can-make-strings-equal.test.ts: -------------------------------------------------------------------------------- 1 | import { areAlmostEqual } from '../../src/map/check-if-one-string-swap-can-make-strings-equal' 2 | 3 | test('仅执行一次字符串交换能否使两个字符串相等', () => { 4 | // 示例 1: 5 | // 输入:s1 = "bank", s2 = "kanb" 6 | // 输出:true 7 | // 解释:例如,交换 s2 中的第一个和最后一个字符可以得到 "bank" 8 | expect(areAlmostEqual("bank", "kanb")).toBeTruthy() 9 | 10 | // 示例 2: 11 | // 输入:s1 = "attack", s2 = "defend" 12 | // 输出:false 13 | // 解释:一次字符串交换无法使两个字符串相等 14 | expect(areAlmostEqual("attack", "defend")).toBeFalsy() 15 | 16 | // 示例 3: 17 | // 输入:s1 = "kelb", s2 = "kelb" 18 | // 输出:true 19 | // 解释:两个字符串已经相等,所以不需要进行字符串交换 20 | expect(areAlmostEqual("kelb", "kelb")).toBeTruthy() 21 | 22 | // 示例 4: 23 | // 输入:s1 = "abcd", s2 = "dcba" 24 | // 输出:false 25 | expect(areAlmostEqual("abcd", "dcba")).toBeFalsy() 26 | 27 | expect(areAlmostEqual("abcd", "abce")).toBeFalsy() 28 | }) -------------------------------------------------------------------------------- /test/map/largest-substring-between-two-equal-characters.test.ts: -------------------------------------------------------------------------------- 1 | import { maxLengthBetweenEqualCharacters } from '../../src/map/largest-substring-between-two-equal-characters' 2 | 3 | test('两个相同字符之间的最长子字符串', () => { 4 | // 示例 1: 5 | // 输入:s = "aa" 6 | // 输出:0 7 | // 解释:最优的子字符串是两个 'a' 之间的空子字符串。 8 | expect(maxLengthBetweenEqualCharacters('aa')).toBe(0) 9 | 10 | // 示例 2: 11 | // 输入:s = "abca" 12 | // 输出:2 13 | // 解释:最优的子字符串是 "bc" 。 14 | expect(maxLengthBetweenEqualCharacters('abca')).toBe(2) 15 | 16 | // 示例 3: 17 | // 输入:s = "cbzxy" 18 | // 输出:-1 19 | // 解释:s 中不存在出现出现两次的字符,所以返回 -1 。 20 | expect(maxLengthBetweenEqualCharacters('cbzxy')).toBe(-1) 21 | 22 | // 示例 4: 23 | // 输入:s = "cabbac" 24 | // 输出:4 25 | // 解释:最优的子字符串是 "abba" ,其他的非最优解包括 "bb" 和 "" 。 26 | expect(maxLengthBetweenEqualCharacters('cabbac')).toBe(4) 27 | }) -------------------------------------------------------------------------------- /test/map/longest-substring-with-at-most-k-distinct-characters.test.ts: -------------------------------------------------------------------------------- 1 | import { lengthOfLongestSubstringKDistinct } from '../../src/map/longest-substring-with-at-most-k-distinct-characters' 2 | 3 | test('至多包含 K 个不同字符的最长子串', () => { 4 | // 示例 1: 5 | // 输入:s = "eceba", k = 2 6 | // 输出:3 7 | // 解释:满足题目要求的子串是 "ece" ,长度为 3 。 8 | expect(lengthOfLongestSubstringKDistinct('eceba', 2)).toBe(3) 9 | 10 | // 示例 2: 11 | // 输入:s = "aa", k = 1 12 | // 输出:2 13 | // 解释:满足题目要求的子串是 "aa" ,长度为 2 。 14 | expect(lengthOfLongestSubstringKDistinct('aa', 1)).toBe(2) 15 | }) -------------------------------------------------------------------------------- /test/map/remove-letter-to-equalize-frequency.test.ts: -------------------------------------------------------------------------------- 1 | import { equalFrequency } from '../../src/map/remove-letter-to-equalize-frequency' 2 | 3 | test('删除字符使频率相同', () => { 4 | // 示例 1: 5 | // 输入:word = "abcc" 6 | // 输出:true 7 | // 解释:选择下标 3 并删除该字母,word 变成 "abc" 且每个字母出现频率都为 1 。 8 | const word = 'abcc' 9 | expect(equalFrequency(word)).toBeTruthy() 10 | 11 | // 示例 2: 12 | // 输入:word = "aazz" 13 | // 输出:false 14 | // 解释:我们必须删除一个字母,所以要么 "a" 的频率变为 1 且 "z" 的频率为 2 ,要么两个字母频率反过来。所以不可能让剩余所有字母出现频率相同。 15 | const word2 = 'aazz' 16 | expect(equalFrequency(word2)).toBeFalsy() 17 | }) -------------------------------------------------------------------------------- /test/math/3sum-closest.test.ts: -------------------------------------------------------------------------------- 1 | import { threeSumClosest } from '../../src/math/3sum-closest' 2 | 3 | test('最接近的三数之和', () => { 4 | expect(threeSumClosest([-1, 2, 1, -4], 1)).toBe(2) 5 | expect(threeSumClosest([0, 0, 0], 1)).toBe(0) 6 | expect(threeSumClosest([1, 8, 5, 7, 2, 1], 1)).toBe(4) 7 | expect(threeSumClosest([1, 1, -1, -1, 3], 3)).toBe(3) 8 | expect(threeSumClosest([-1, 0, 1, 1, 55], 3)).toBe(2) 9 | expect(threeSumClosest([-23, -67, 32, 21, -65, 46, 73, 42, 93, 9, -61, -79, -51, 61, -15, 49, 92, -34, 50, 1, 26, -12, 68, -97, -17, 51, -55, 75, -56, -95, -70, -42, 91, -18, -64, 20, 33, -20, 19, 61, -89, 81, -73, 82, -23, -65, 51, -88, 15, -48, 24, 34, 0, -24, 37, 22, 28, -67, -25, -61, -57, -74, 65, 50, -66, 24, 99, 80, 44, 85, 20, -4, -9, -81, 87, -82, -100, 51, -83, 9, -31, 37, 23, -61, 53, -14, -51, 88, 56, 27, 42, -52, -97, 37, 36, -59, -45, 95, 46, -1, -100, -38, 66, 44, 27, -97, 12, -43, 84, -53, 93, 18, -40, -38, 34, 85, 53, -50, -14, -6, 98, -77, -17, 50, -65, 52, -46, -94, 49, 72, -2, -82, 45, -39, -58, 67, 82, 63, 95, -32, 47, 15, -20, 46, 5, 17, -40, -95, 97, -9, 11, 8, -51, -24, -50, -37, -72, -57, 26, 26, 19, 71, -42], -87)).toBe(-87) 10 | }) -------------------------------------------------------------------------------- /test/math/3sum.test.ts: -------------------------------------------------------------------------------- 1 | import { threeSum } from '../../src/math/3sum' 2 | 3 | test('三数之和', () => { 4 | expect(threeSum([-1, 0, 1, 2, -1, -4])).toEqual([ 5 | [-1, -1, 2], 6 | [-1, 0, 1] 7 | ]) 8 | 9 | expect(threeSum([1, 0, 1, 2])).toEqual([]) 10 | expect(threeSum([0, 1, 1])).toEqual([]) 11 | expect(threeSum([0, 0, 0])).toEqual([[0, 0, 0]]) 12 | expect(threeSum([6, -5, -6, -1, -2, 8, -1, 4, -10, -8, -10, -2, -4, -1, -8, -2, 8, 9, -5, -2, -8, -9, -3, -5])).toEqual([[-10, 4, 6], [-8, -1, 9], [-6, -3, 9], [-6, -2, 8], [-5, -4, 9], [-5, -3, 8], [-5, -1, 6], [-4, -2, 6], [-3, -1, 4], [-2, -2, 4]]) 13 | }) 14 | -------------------------------------------------------------------------------- /test/math/4sum.test.ts: -------------------------------------------------------------------------------- 1 | import { fourSum, fourSum2 } from '../../src/math/4sum' 2 | 3 | describe('四数之和', () => { 4 | test('方法1', () => { 5 | expect(fourSum([1, 0, -1, 0, -2, 2], 0)).toEqual([[-2, -1, 1, 2], [-2, 0, 0, 2], [-1, 0, 0, 1]]) 6 | expect(fourSum([2, 2, 2, 2, 2], 8)).toEqual([[2, 2, 2, 2]]) 7 | expect(fourSum([1, 2, 3, 4], 10)).toEqual([[1, 2, 3, 4]]) 8 | expect(fourSum([-2, -1, -1, 1, 1, 2, 2], 0)).toEqual([[-2, -1, 1, 2], [-1, -1, 1, 1]]) 9 | }) 10 | 11 | test('方法2', () => { 12 | expect(fourSum2([1, 0, -1, 0, -2, 2], 0)).toEqual([[-2, -1, 1, 2], [-2, 0, 0, 2], [-1, 0, 0, 1]]) 13 | expect(fourSum2([2, 2, 2, 2, 2], 8)).toEqual([[2, 2, 2, 2]]) 14 | expect(fourSum2([1, 2, 3, 4], 10)).toEqual([[1, 2, 3, 4]]) 15 | expect(fourSum2([-2, -1, -1, 1, 1, 2, 2], 0)).toEqual([[-2, -1, 1, 2], [-1, -1, 1, 1]]) 16 | }) 17 | }) -------------------------------------------------------------------------------- /test/math/add-binary.test.ts: -------------------------------------------------------------------------------- 1 | import { addBinary } from '../../src/math/add-binary' 2 | 3 | test('二进制求和', () => { 4 | expect(addBinary('11', '1')).toEqual('100') 5 | expect(addBinary('1010', '1011')).toEqual('10101') 6 | }) 7 | -------------------------------------------------------------------------------- /test/math/coin-lcci.test.ts: -------------------------------------------------------------------------------- 1 | import { waysToChange } from '../../src/math/coin-lcci' 2 | 3 | test('硬币', () => { 4 | expect(waysToChange(5)).toBe(2) 5 | expect(waysToChange(10)).toBe(4) 6 | }) 7 | -------------------------------------------------------------------------------- /test/math/factorial-trailing-zeroes.test.ts: -------------------------------------------------------------------------------- 1 | import trailingZeroes from '../../src/math/factorial-trailing-zeroes' 2 | 3 | test('trailingZeroes', () => { 4 | expect(trailingZeroes(3)).toBe(0) 5 | expect(trailingZeroes(5)).toBe(1) 6 | }) 7 | -------------------------------------------------------------------------------- /test/math/max-points-on-a-line.test.ts: -------------------------------------------------------------------------------- 1 | import { maxPoints } from '../../src/math/max-points-on-a-line' 2 | 3 | test('直线上最多的点数', () => { 4 | expect(maxPoints([[1, 1], [2, 2], [3, 3]])).toBe(3) 5 | expect(maxPoints([[1, 1], [3, 2], [5, 3], [4, 1], [2, 3], [1, 4]])).toBe(4) 6 | expect(maxPoints([[0, 0]])).toBe(1) 7 | }) -------------------------------------------------------------------------------- /test/math/maximum-lcci.test.ts: -------------------------------------------------------------------------------- 1 | import { maximum } from '../../src/math/maximum-lcci' 2 | 3 | test('最大数值', () => { 4 | expect(maximum(1, 2)).toBe(2) 5 | expect(maximum(108, 133)).toBe(133) 6 | expect(maximum(199, 133)).toBe(199) 7 | expect(maximum(2147483647, -2147483648)).toBe(2147483647) 8 | }) 9 | -------------------------------------------------------------------------------- /test/math/median-of-two-sorted-arrays.test.ts: -------------------------------------------------------------------------------- 1 | import { findMedianSortedArrays } from '../../src/math/median-of-two-sorted-arrays' 2 | 3 | test('寻找两个正序数组的中位数', () => { 4 | expect(findMedianSortedArrays([], [1])).toBe(1.0) 5 | expect(findMedianSortedArrays([1, 3], [2])).toBe(2.0) 6 | expect(findMedianSortedArrays([1, 2], [3, 4])).toBe(2.5) 7 | expect(findMedianSortedArrays([1, 4], [3, 4])).toBe(3.5) 8 | }) 9 | -------------------------------------------------------------------------------- /test/math/next-greater-element-iii.test.ts: -------------------------------------------------------------------------------- 1 | import { nextGreaterElement } from '../../src/math/next-greater-element-iii' 2 | 3 | test('下一个更大元素 III', () => { 4 | // 示例 1: 5 | // 输入:n = 12 6 | // 输出:21 7 | 8 | // 示例 2: 9 | // 输入:n = 21 10 | // 输出:-1 11 | 12 | expect(nextGreaterElement(12)).toBe(21) 13 | expect(nextGreaterElement(21)).toBe(-1) 14 | expect(nextGreaterElement(230241)).toBe(230412) 15 | expect(nextGreaterElement(2 ** 31 - 1 + 1)).toBe(-1) 16 | }) -------------------------------------------------------------------------------- /test/math/palindrome-number.test.ts: -------------------------------------------------------------------------------- 1 | import { isPalindrome } from '../../src/math/palindrome-number' 2 | 3 | test('回文数', () => { 4 | expect(isPalindrome(121)).toBe(true) 5 | expect(isPalindrome(0)).toBe(true) 6 | expect(isPalindrome(11)).toBe(true) 7 | expect(isPalindrome(10)).toBe(false) 8 | expect(isPalindrome(-121)).toBe(false) 9 | }) 10 | -------------------------------------------------------------------------------- /test/math/perfect-number.test.ts: -------------------------------------------------------------------------------- 1 | import { checkPerfectNumber } from '../../src/math/perfect-number' 2 | 3 | test('完美数', () => { 4 | expect(checkPerfectNumber(28)).toBe(true) 5 | expect(checkPerfectNumber(2)).toBe(false) 6 | }) 7 | -------------------------------------------------------------------------------- /test/math/permutations.test.ts: -------------------------------------------------------------------------------- 1 | import { permute } from '../../src/math/permutations' 2 | 3 | test('全排列', () => { 4 | expect(permute([1, 2, 3])).toEqual([ 5 | [1, 2, 3], 6 | [1, 3, 2], 7 | [2, 1, 3], 8 | [2, 3, 1], 9 | [3, 1, 2], 10 | [3, 2, 1] 11 | ]) 12 | }) 13 | -------------------------------------------------------------------------------- /test/math/powx-n.test.ts: -------------------------------------------------------------------------------- 1 | import { myPow } from '../../src/math/powx-n' 2 | 3 | test('Pow(x, n)', () => { 4 | expect(myPow(2.00000, 10)).toBe('1024.00000') 5 | expect(myPow(2.10000, 3)).toBe('9.26100') 6 | expect(myPow(2.00000, -2)).toBe('0.25000') 7 | }) 8 | -------------------------------------------------------------------------------- /test/math/subarray-sum-equals-k.test.ts: -------------------------------------------------------------------------------- 1 | import { subarraySum } from '../../src/math/subarray-sum-equals-k' 2 | 3 | test('和为K的子数组', () => { 4 | expect(subarraySum([1, 1, 1], 2)).toBe(2) 5 | expect(subarraySum([0, 0], 2)).toBe(0) 6 | }) 7 | -------------------------------------------------------------------------------- /test/math/ugly-number-ii.test.ts: -------------------------------------------------------------------------------- 1 | import { nthUglyNumber } from '../../src/math/ugly-number-ii' 2 | 3 | test('丑数 II', () => { 4 | expect(nthUglyNumber(9)).toBe(10) 5 | expect(nthUglyNumber(1)).toBe(1) 6 | expect(nthUglyNumber(10)).toBe(12) 7 | expect(nthUglyNumber(0)).toBe(0) 8 | }) 9 | -------------------------------------------------------------------------------- /test/math/ugly-number.test.ts: -------------------------------------------------------------------------------- 1 | import { isUgly } from '../../src/math/ugly-number' 2 | 3 | test('丑数', () => { 4 | // 示例 1: 5 | // 输入:n = 6 6 | // 输出:true 7 | // 解释:6 = 2 × 3 8 | expect(isUgly(6)).toBeTruthy() 9 | 10 | // 示例 2: 11 | // 输入:n = 1 12 | // 输出:true 13 | // 解释:1 没有质因数,因此它的全部质因数是 {2, 3, 5} 的空集。习惯上将其视作第一个丑数。 14 | expect(isUgly(1)).toBeTruthy() 15 | 16 | // 示例 3: 17 | // 输入:n = 14 18 | // 输出:false 19 | // 解释:14 不是丑数,因为它包含了另外一个质因数 7 。 20 | expect(isUgly(14)).toBeFalsy() 21 | 22 | expect(isUgly(-1)).toBeFalsy() 23 | }) -------------------------------------------------------------------------------- /test/other/minimum-number-of-refueling-stops.test.ts: -------------------------------------------------------------------------------- 1 | import { minRefuelStops } from '../../src/other/minimum-number-of-refueling-stops' 2 | 3 | test('最低加油次数', () => { 4 | // 示例 1: 5 | // 输入:target = 1, startFuel = 1, stations = [] 6 | // 输出:0 7 | // 解释:我们可以在不加油的情况下到达目的地。 8 | 9 | // 示例 2: 10 | // 输入:target = 100, startFuel = 1, stations = [[10,100]] 11 | // 输出:-1 12 | // 解释:我们无法抵达目的地,甚至无法到达第一个加油站。 13 | 14 | // 示例 3: 15 | // 输入:target = 100, startFuel = 10, stations = [[10,60],[20,30],[30,30],[60,40]] 16 | // 输出:2 17 | // 解释: 18 | // 我们出发时有 10 升燃料。 19 | // 我们开车来到距起点 10 英里处的加油站,消耗 10 升燃料。将汽油从 0 升加到 60 升。 20 | // 然后,我们从 10 英里处的加油站开到 60 英里处的加油站(消耗 50 升燃料), 21 | // 并将汽油从 10 升加到 50 升。然后我们开车抵达目的地。 22 | // 我们沿途在1两个加油站停靠,所以返回 2 。 23 | 24 | expect(minRefuelStops(1, 1, [])).toBe(0) 25 | expect(minRefuelStops(100, 1, [[10, 100]])).toBe(-1) 26 | expect(minRefuelStops(100, 10, [[10, 60], [20, 30], [30, 30], [60, 40]])).toBe(2) 27 | expect(minRefuelStops(31, 1, [[1, 10], [11, 0]])).toBe(-1) 28 | }) -------------------------------------------------------------------------------- /test/search/array-nesting.test.ts: -------------------------------------------------------------------------------- 1 | import { arrayNesting } from '../../src/search/array-nesting' 2 | 3 | test('数组嵌套', () => { 4 | // 示例 1: 5 | // 输入: A = [5,4,0,3,1,6,2] 6 | // 输出: 4 7 | // 解释: 8 | // A[0] = 5, A[1] = 4, A[2] = 0, A[3] = 3, A[4] = 1, A[5] = 6, A[6] = 2. 9 | 10 | // 其中一种最长的 S[K]: 11 | // S[0] = {A[0], A[5], A[6], A[2]} = {5, 6, 2, 0} 12 | 13 | expect(arrayNesting([5, 4, 0, 3, 1, 6, 2])).toBe(4) 14 | }) -------------------------------------------------------------------------------- /test/sort/bubbleSort.test.ts: -------------------------------------------------------------------------------- 1 | import { bubbleSort } from './../../src/sort/bubbleSort' 2 | import { mergeSort } from './../../src/sort/mergeSort' 3 | 4 | test('冒泡排序', () => { 5 | expect(bubbleSort([2, 6, 1, 4, 8, 4, 7, 8, 97, 3, 2])).toEqual(mergeSort([2, 6, 1, 4, 8, 4, 7, 8, 97, 3, 2])) 6 | 7 | const data = [ 8 | [], 9 | [3], 10 | [2, 6, 1, 4, 8, 4, 7, 8, 97, 3, 2], 11 | [3, 5, 1, 4, 39, 4, 7, 8, 98, 3, 2] 12 | ] 13 | 14 | for (let i = 0; i < data.length; i++) { 15 | expect(bubbleSort(JSON.parse(JSON.stringify(data[i])))).toEqual(mergeSort(JSON.parse(JSON.stringify(data[i])))) 16 | } 17 | }) -------------------------------------------------------------------------------- /test/sort/insertSort.test.ts: -------------------------------------------------------------------------------- 1 | import { insertSort, insertSort2 } from '../../src/sort/insertSort' 2 | import { mergeSort } from '../../src/sort/mergeSort' 3 | 4 | test('插入排序', () => { 5 | expect(insertSort([2, 6, 1, 4, 8, 4, 7, 8, 97, 3, 2])).toEqual(mergeSort([2, 6, 1, 4, 8, 4, 7, 8, 97, 3, 2])) 6 | 7 | const data = [ 8 | [], 9 | [3], 10 | [2, 6, 1, 4, 8, 4, 7, 8, 97, 3, 2], 11 | [3, 5, 1, 4, 39, 4, 7, 8, 98, 3, 2] 12 | ] 13 | 14 | for (let i = 0; i < data.length; i++) { 15 | expect(insertSort(JSON.parse(JSON.stringify(data[i])))).toEqual(mergeSort(JSON.parse(JSON.stringify(data[i])))) 16 | } 17 | 18 | for (let i = 0; i < data.length; i++) { 19 | expect(insertSort2(JSON.parse(JSON.stringify(data[i])))).toEqual(mergeSort(JSON.parse(JSON.stringify(data[i])))) 20 | } 21 | }) -------------------------------------------------------------------------------- /test/sort/mergeSort.test.ts: -------------------------------------------------------------------------------- 1 | import { mergeSort } from "../../src/sort/mergeSort"; 2 | 3 | test('归并排序', () => { 4 | expect(mergeSort([2, 6, 1, 4, 8, 4, 7, 8, 97, 3, 2])).toEqual(mergeSort([2, 6, 1, 4, 8, 4, 7, 8, 97, 3, 2])) 5 | 6 | const data = [ 7 | [], 8 | [3], 9 | [2, 6, 1, 4, 8, 4, 7, 8, 97, 3, 2], 10 | [3, 5, 1, 4, 39, 4, 7, 8, 98, 3, 2] 11 | ] 12 | 13 | for (let i = 0; i < data.length; i++) { 14 | expect(mergeSort(JSON.parse(JSON.stringify(data[i])))).toEqual(mergeSort(JSON.parse(JSON.stringify(data[i])))) 15 | } 16 | }) -------------------------------------------------------------------------------- /test/sort/minimum-absolute-difference.test.ts: -------------------------------------------------------------------------------- 1 | import { minimumAbsDifference } from '../../src/sort/minimum-absolute-difference' 2 | 3 | test('最小绝对差', () => { 4 | // 示例 1: 5 | // 输入:arr = [4,2,1,3] 6 | // 输出:[[1,2],[2,3],[3,4]] 7 | expect(minimumAbsDifference([4, 2, 1, 3])).toEqual([[1, 2], [2, 3], [3, 4]]) 8 | 9 | // 示例 2: 10 | // 输入:arr = [1,3,6,10,15] 11 | // 输出:[[1,3]] 12 | expect(minimumAbsDifference([1, 3, 6, 10, 15])).toEqual([[1, 3]]) 13 | 14 | // 示例 3: 15 | // 输入:arr = [3,8,-10,23,19,-4,-14,27] 16 | // 输出:[[-14,-10],[19,23],[23,27]] 17 | expect(minimumAbsDifference([3, 8, -10, 23, 19, -4, -14, 27])).toEqual([[-14, -10], [19, 23], [23, 27]]) 18 | 19 | expect(minimumAbsDifference([5, 4, 3, 2])).toEqual([[2, 3], [3, 4], [4, 5]]) 20 | }) -------------------------------------------------------------------------------- /test/sort/quickSort.test.ts: -------------------------------------------------------------------------------- 1 | import { quickSort } from '../../src/sort/quickSort' 2 | import { mergeSort } from '../../src/sort/mergeSort' 3 | 4 | test('快排', () => { 5 | let arr = [2, 6, 1, 4, 8, 4, 7, 8, 97, 3, 2] 6 | quickSort(arr) 7 | expect(arr).toEqual(mergeSort([2, 6, 1, 4, 8, 4, 7, 8, 97, 3, 2])) 8 | 9 | const data = [ 10 | [], 11 | [3], 12 | [2, 6, 1, 4, 8, 4, 7, 8, 97, 3, 2], 13 | [3, 5, 1, 4, 39, 4, 7, 8, 98, 3, 2] 14 | ] 15 | 16 | for (let i = 0; i < data.length; i++) { 17 | let arr = data[i] 18 | quickSort(arr) 19 | expect(arr).toEqual(mergeSort(JSON.parse(JSON.stringify(data[i])))) 20 | } 21 | }) 22 | 23 | -------------------------------------------------------------------------------- /test/sort/selectSort.test.ts: -------------------------------------------------------------------------------- 1 | import { selectSort } from '../../src/sort/selectSort' 2 | import { mergeSort } from '../../src/sort/mergeSort' 3 | 4 | test ('选择排序', () => { 5 | expect(selectSort([2, 6, 1, 4, 8, 4, 7, 8, 97, 3, 2])).toEqual(mergeSort([2, 6, 1, 4, 8, 4, 7, 8, 97, 3, 2])) 6 | 7 | const data = [ 8 | [], 9 | [3], 10 | [2, 6, 1, 4, 8, 4, 7, 8, 97, 3, 2], 11 | [3, 5, 1, 4, 39, 4, 7, 8, 98, 3, 2] 12 | ] 13 | 14 | for (let i = 0; i < data.length; i++){ 15 | expect(selectSort(JSON.parse(JSON.stringify(data[i])))).toEqual(mergeSort(JSON.parse(JSON.stringify(data[i])))) 16 | } 17 | }) -------------------------------------------------------------------------------- /test/stack/build-an-array-with-stack-operations.test.ts: -------------------------------------------------------------------------------- 1 | import { buildArray } from '../../src/stack/build-an-array-with-stack-operations' 2 | 3 | test('用栈操作构建数组', () => { 4 | // 示例 1: 5 | // 输入:target = [1,3], n = 3 6 | // 输出:["Push","Push","Pop","Push"] 7 | // 解释: 8 | // 读取 1 并自动推入数组 -> [1] 9 | // 读取 2 并自动推入数组,然后删除它 -> [1] 10 | // 读取 3 并自动推入数组 -> [1,3] 11 | let target = [1, 3], n = 3 12 | expect(buildArray(target, n)).toEqual(["Push", "Push", "Pop", "Push"]) 13 | 14 | // 示例 2: 15 | // 输入:target = [1,2,3], n = 3 16 | // 输出:["Push","Push","Push"] 17 | target = [1, 2, 3]; n = 3 18 | expect(buildArray(target, n)).toEqual(["Push", "Push", "Push"]) 19 | 20 | // 示例 3: 21 | // 输入:target = [1,2], n = 4 22 | // 输出:["Push","Push"] 23 | // 解释:只需要读取前 2 个数字就可以停止。 24 | target = [1, 2]; n = 4 25 | expect(buildArray(target, n)).toEqual(["Push", "Push"]) 26 | }) -------------------------------------------------------------------------------- /test/stack/decode-string.test.ts: -------------------------------------------------------------------------------- 1 | import { decodeString } from '../../src/stack/decode-string' 2 | 3 | test('字符串解码', () => { 4 | // s = "3[a]2[bc]", 返回 "aaabcbc". 5 | expect(decodeString('3[a]2[bc]')).toBe('aaabcbc') 6 | // s = "3[a2[c]]", 返回 "accaccacc". 7 | expect(decodeString('3[a2[c]]')).toBe('accaccacc') 8 | // s = "2[abc]3[cd]ef", 返回 "abcabccdcdcdef". 9 | expect(decodeString('2[abc]3[cd]ef')).toBe('abcabccdcdcdef') 10 | }) 11 | -------------------------------------------------------------------------------- /test/stack/min-stack.test.ts: -------------------------------------------------------------------------------- 1 | import { MinStack } from '../../src/stack/min-stack' 2 | 3 | test('最小栈', () => { 4 | var obj = new MinStack() 5 | obj.push(1) 6 | obj.push(3) 7 | obj.push(2) 8 | obj.pop() 9 | var top = obj.top() 10 | var min = obj.getMin() 11 | expect(top).toBe(3) 12 | expect(min).toBe(1) 13 | }) 14 | -------------------------------------------------------------------------------- /test/stack/simplify-path.test.ts: -------------------------------------------------------------------------------- 1 | import { simplifyPath } from '../../src/stack/simplify-path' 2 | 3 | test('简化路径', () => { 4 | // 示例 1: 5 | // 输入:path = "/home/" 6 | // 输出:"/home" 7 | // 解释:注意,最后一个目录名后面没有斜杠。 8 | expect(simplifyPath('/home/')).toBe('/home') 9 | 10 | // 示例 2: 11 | // 输入:path = "/../" 12 | // 输出:"/" 13 | // 解释:从根目录向上一级是不可行的,因为根目录是你可以到达的最高级。 14 | expect(simplifyPath('/../')).toBe('/') 15 | 16 | // 示例 3: 17 | // 输入:path = "/home//foo/" 18 | // 输出:"/home/foo" 19 | // 解释:在规范路径中,多个连续斜杠需要用一个斜杠替换。 20 | expect(simplifyPath('/home//foo/')).toBe('/home/foo') 21 | 22 | // 示例 4: 23 | // 输入:path = "/a/./b/../../c/" 24 | // 输出:"/c" 25 | expect(simplifyPath('/a/./b/../../c/')).toBe('/c') 26 | }) -------------------------------------------------------------------------------- /test/string/check-if-a-word-occurs-as-a-prefix-of-any-word-in-a-sentence.test.ts: -------------------------------------------------------------------------------- 1 | import { isPrefixOfWord } from '../../src/string/check-if-a-word-occurs-as-a-prefix-of-any-word-in-a-sentence' 2 | 3 | test('检查单词是否为句中其他单词的前缀', () => { 4 | expect(isPrefixOfWord('i love eating burger', 'burg')).toBe(4) 5 | expect(isPrefixOfWord('abc', 'd')).toBe(-1) 6 | }) 7 | -------------------------------------------------------------------------------- /test/string/check-if-binary-string-has-at-most-one-segment-of-ones.test.ts: -------------------------------------------------------------------------------- 1 | import { checkOnesSegment } from '../../src/string/check-if-binary-string-has-at-most-one-segment-of-ones' 2 | 3 | test('检查二进制字符串字段', () => { 4 | // 示例 1: 5 | // 输入:s = "1001" 6 | // 输出:false 7 | // 解释:由连续若干个 '1' 组成的字段数量为 2,返回 false 8 | expect(checkOnesSegment("1001")).toBeFalsy() 9 | 10 | // 示例 2: 11 | // 输入:s = "110" 12 | // 输出:true 13 | expect(checkOnesSegment("110")).toBeTruthy() 14 | }) -------------------------------------------------------------------------------- /test/string/compare-strings.test.ts: -------------------------------------------------------------------------------- 1 | import { compareStrings } from '../../src/string/compare-strings' 2 | 3 | test('比较字符串', () => { 4 | expect(compareStrings('ABCD', 'AB')).toBe(true) 5 | expect(compareStrings('ABCD', 'ACD')).toBe(true) 6 | expect(compareStrings('ABCD', 'AABC')).toBe(false) 7 | }) 8 | -------------------------------------------------------------------------------- /test/string/contains-duplicate.test.ts: -------------------------------------------------------------------------------- 1 | import { containsDuplicate } from '../../src/string/contains-duplicate' 2 | 3 | test('存在重复元素', () => { 4 | expect(containsDuplicate([1, 2, 3, 1])).toBe(true) 5 | expect(containsDuplicate([1, 2, 3, 4])).toBe(false) 6 | expect(containsDuplicate([1, 1, 1, 3, 3, 4, 3, 2, 4, 2])).toBe(true) 7 | }) 8 | -------------------------------------------------------------------------------- /test/string/defanging-an-ip-address.test.ts: -------------------------------------------------------------------------------- 1 | import { defangIPaddr } from '../../src/string/defanging-an-ip-address' 2 | 3 | test('IP地址无效化', () => { 4 | expect(defangIPaddr('1.1.1.1')).toBe('1[.]1[.]1[.]1') 5 | expect(defangIPaddr('255.100.50.0')).toBe('255[.]100[.]50[.]0') 6 | }) 7 | -------------------------------------------------------------------------------- /test/string/different-ways-to-add-parentheses.test.ts: -------------------------------------------------------------------------------- 1 | import { diffWaysToCompute } from '../../src/string/different-ways-to-add-parentheses' 2 | 3 | test('为运算表达式设计优先级', () => { 4 | // 示例 1: 5 | // 输入:expression = "2-1-1" 6 | // 输出:[0,2] 7 | // 解释: 8 | // ((2-1)-1) = 0 9 | // (2-(1-1)) = 2 10 | 11 | // 示例 2: 12 | // 输入:expression = "2*3-4*5" 13 | // 输出:[-34,-14,-10,-10,10] 14 | // 解释: 15 | // (2*(3-(4*5))) = -34 16 | // ((2*3)-(4*5)) = -14 17 | // ((2*(3-4))*5) = -10 18 | // (2*((3-4)*5)) = -10 19 | // (((2*3)-4)*5) = 10 20 | 21 | expect(diffWaysToCompute('2-1-1')).toEqual([2, 0]) 22 | expect(diffWaysToCompute('2*3-4*5')).toEqual([-34, -10, -14, -10, 10]) 23 | expect(diffWaysToCompute('1+1')).toEqual([2]) 24 | }) -------------------------------------------------------------------------------- /test/string/find-the-longest-substring-containing-vowels-in-even-counts.test.ts: -------------------------------------------------------------------------------- 1 | import { findTheLongestSubstring } from '../../src/string/find-the-longest-substring-containing-vowels-in-even-counts' 2 | 3 | test('每个元音包含偶数次的最长子字符串', () => { 4 | expect(findTheLongestSubstring('eleetminicoworoep')).toBe(13) 5 | expect(findTheLongestSubstring('leetcodeisgreat')).toBe(5) 6 | expect(findTheLongestSubstring('bcbcbc')).toBe(6) 7 | expect(findTheLongestSubstring('bcbucbc')).toBe(3) 8 | }) 9 | -------------------------------------------------------------------------------- /test/string/generate-a-string-with-characters-that-have-odd-counts.test.ts: -------------------------------------------------------------------------------- 1 | import { generateTheString } from '../../src/string/generate-a-string-with-characters-that-have-odd-counts' 2 | 3 | test('生成每种字符都是奇数个的字符串', () => { 4 | // 示例 1: 5 | // 输入:n = 4 6 | // 输出:"pppz" 7 | // 解释:"pppz" 是一个满足题目要求的字符串,因为 'p' 出现 3 次,且 'z' 出现 1 次。当然,还有很多其他字符串也满足题目要求,比如:"ohhh" 和 "love"。 8 | expect(generateTheString(4)).toBe('aaab') 9 | 10 | // 示例 2: 11 | // 输入:n = 2 12 | // 输出:"xy" 13 | // 解释:"xy" 是一个满足题目要求的字符串,因为 'x' 和 'y' 各出现 1 次。当然,还有很多其他字符串也满足题目要求,比如:"ag" 和 "ur"。 14 | expect(generateTheString(2)).toBe('ab') 15 | 16 | // 示例 3: 17 | // 输入:n = 7 18 | // 输出:"holasss" 19 | expect(generateTheString(7)).toBe('aaaaaaa') 20 | }) -------------------------------------------------------------------------------- /test/string/generate-parentheses.test.ts: -------------------------------------------------------------------------------- 1 | import { generateParenthesis } from '../../src/string/generate-parentheses' 2 | 3 | test('括号生成', () => { 4 | expect(generateParenthesis(3)).toEqual(["((()))", "(()())", "(())()", "()(())", "()()()"]) 5 | expect(generateParenthesis(1)).toEqual(["()"]) 6 | }) -------------------------------------------------------------------------------- /test/string/integer-to-roman.test.ts: -------------------------------------------------------------------------------- 1 | import { intToRoman } from '../../src/string/integer-to-roman' 2 | 3 | test('整数转罗马数字', () => { 4 | expect(intToRoman(2)).toBe('II') 5 | expect(intToRoman(3)).toBe('III') 6 | expect(intToRoman(4)).toBe('IV') 7 | expect(intToRoman(9)).toBe('IX') 8 | expect(intToRoman(58)).toBe('LVIII') 9 | }) 10 | -------------------------------------------------------------------------------- /test/string/largest-number.test.ts: -------------------------------------------------------------------------------- 1 | import { largestNumber } from '../../src/string/largest-number' 2 | 3 | test('最大数', () => { 4 | expect(largestNumber([10, 2])).toBe('210') 5 | expect(largestNumber([3, 30, 34, 5, 9])).toBe('9534330') 6 | expect(largestNumber([1, 20, 23, 4, 8])).toBe('8423201') 7 | expect(largestNumber([4, 6, 65])).toBe('6654') 8 | expect(largestNumber([])).toBe('0') 9 | expect(largestNumber([0, 0])).toBe('0') 10 | }) 11 | -------------------------------------------------------------------------------- /test/string/length-of-last-word.test.ts: -------------------------------------------------------------------------------- 1 | import { lengthOfLastWord } from '../../src/string/length-of-last-word' 2 | 3 | test('最后一个单词的长度', () => { 4 | expect(lengthOfLastWord('b a ')).toBe(1) 5 | expect(lengthOfLastWord('')).toBe(0) 6 | }) 7 | -------------------------------------------------------------------------------- /test/string/longest-common-prefix.test.ts: -------------------------------------------------------------------------------- 1 | import { longestCommonPrefix } from '../../src/string/longest-common-prefix' 2 | 3 | test('最长公共前缀', () => { 4 | expect(longestCommonPrefix(['flower', 'flow', 'flight'])).toBe('fl') 5 | expect(longestCommonPrefix(['dog', 'racecar', 'car'])).toBe('') 6 | expect(longestCommonPrefix(['a'])).toBe('a') 7 | expect(longestCommonPrefix(['caa', '', 'a', 'acb'])).toBe('') 8 | expect(longestCommonPrefix([])).toBe('') 9 | }) 10 | -------------------------------------------------------------------------------- /test/string/longest-palindromic-substring.test.ts: -------------------------------------------------------------------------------- 1 | import { longestPalindrome } from '../../src/string/longest-palindromic-substring' 2 | 3 | test('最长回文字符串', () => { 4 | expect(longestPalindrome('a')).toBe('a') // 边界条件 5 | expect(longestPalindrome('bb')).toBe('bb') // 边界条件 6 | expect(longestPalindrome('ab')).toBe('b') // 边界条件 7 | expect(longestPalindrome(' ')).toBe('') // 边界条件 8 | expect(longestPalindrome('babad')).toBe('aba') // bab也是有效答案 9 | expect(longestPalindrome('cbbd')).toBe('bb') 10 | }) 11 | -------------------------------------------------------------------------------- /test/string/longest-substring-without-repeating-characters.test.ts: -------------------------------------------------------------------------------- 1 | import { lengthOfLongestSubstring } from '../../src/string/longest-substring-without-repeating-characters' 2 | 3 | test('最长无重复字符的子串', () => { 4 | expect(lengthOfLongestSubstring('abcabcbb')).toBe(3) 5 | expect(lengthOfLongestSubstring('bbbbb')).toBe(1) 6 | expect(lengthOfLongestSubstring('pwwkew')).toBe(3) 7 | expect(lengthOfLongestSubstring('')).toBe(0) 8 | expect(lengthOfLongestSubstring(' ')).toBe(1) 9 | expect(lengthOfLongestSubstring('au')).toBe(2) 10 | expect(lengthOfLongestSubstring('dvdf')).toBe(3) 11 | }) 12 | -------------------------------------------------------------------------------- /test/string/maximum-number-of-vowels-in-a-substring-of-given-length.test.ts: -------------------------------------------------------------------------------- 1 | import { maxVowels } from '../../src/string/maximum-number-of-vowels-in-a-substring-of-given-length' 2 | 3 | test('定长子串中元音的最大数目', () => { 4 | expect(maxVowels('abciiidef', 3)).toBe(3) 5 | expect(maxVowels('rhythms', 4)).toBe(0) 6 | }) 7 | -------------------------------------------------------------------------------- /test/string/minimum-window-substring.test.ts: -------------------------------------------------------------------------------- 1 | import { minWindow } from '../../src/string/minimum-window-substring' 2 | 3 | test('最小覆盖子串', () => { 4 | expect(minWindow('ab', 'a')).toBe('a') 5 | expect(minWindow('ADOBECODEBANC', 'ABC')).toBe('BANC') 6 | expect(minWindow('a', 'a')).toBe('a') 7 | expect(minWindow('a', 'aa')).toBe('') 8 | expect(minWindow('abcdc', 'da')).toBe('abcd') 9 | }) 10 | -------------------------------------------------------------------------------- /test/string/regular-expression-matching.test.ts: -------------------------------------------------------------------------------- 1 | import regularExpressionMatching from '../../src/string/regular-expression-matching' 2 | 3 | test('regularExpressionMatching', () => { 4 | expect(regularExpressionMatching('aa', 'a')).toEqual(false) 5 | expect(regularExpressionMatching('aaa', 'aa')).toEqual(false) 6 | expect(regularExpressionMatching('aa', 'aa')).toEqual(true) 7 | expect(regularExpressionMatching('aa', 'a*')).toEqual(true) 8 | expect(regularExpressionMatching('ab', '.*')).toEqual(true) 9 | expect(regularExpressionMatching('aab', 'c*a*b')).toEqual(true) 10 | expect(regularExpressionMatching('mississippi', 'mis*is*p*.')).toEqual(false) 11 | expect(regularExpressionMatching('mississippi', 'mis*is*ip*.')).toEqual(true) 12 | }) 13 | -------------------------------------------------------------------------------- /test/string/repeated-substring-pattern.test.ts: -------------------------------------------------------------------------------- 1 | import repeatedSubstringPattern from '../../src/string/repeated-substring-pattern' 2 | 3 | test('repeatedSubstringPattern', () => { 4 | expect(repeatedSubstringPattern('abab')).toEqual(true) 5 | expect(repeatedSubstringPattern('ab')).toEqual(false) 6 | expect(repeatedSubstringPattern('aba')).toEqual(false) 7 | expect(repeatedSubstringPattern('abcabcabcabc')).toEqual(true) 8 | }) 9 | -------------------------------------------------------------------------------- /test/string/restore-ip-addresses.test.ts: -------------------------------------------------------------------------------- 1 | import restoreIpAddresses from '../../src/string/restore-ip-addresses' 2 | 3 | test('恢复IP地址', () => { 4 | expect(restoreIpAddresses('25525511135')).toEqual(['255.255.11.135', '255.255.111.35']) 5 | expect(restoreIpAddresses('1116512311')).toEqual(['11.165.123.11', '111.65.123.11']) 6 | expect(restoreIpAddresses('00000')).toEqual([]) 7 | expect(restoreIpAddresses('0000')).toEqual(['0.0.0.0']) 8 | expect(restoreIpAddresses('010010')).toEqual(['0.10.0.10', '0.100.1.0']) 9 | }) 10 | -------------------------------------------------------------------------------- /test/string/reverse-words-in-a-string.test.ts: -------------------------------------------------------------------------------- 1 | import ReverseWordsInAString from '../../src/string/reverse-words-in-a-string' 2 | 3 | test('ReverseWordsInAString', () => { 4 | expect(ReverseWordsInAString('Let\'s take LeetCode contest')).toBe('s\'teL ekat edoCteeL tsetnoc') 5 | }) 6 | -------------------------------------------------------------------------------- /test/string/roman-to-integer.test.ts: -------------------------------------------------------------------------------- 1 | import { romanToInt } from '../../src/string/roman-to-integer' 2 | 3 | test('罗马数字转整数', () => { 4 | expect(romanToInt('1')).toBe(0) 5 | expect(romanToInt('III')).toBe(3) 6 | expect(romanToInt('IV')).toBe(4) 7 | expect(romanToInt('IX')).toBe(9) 8 | expect(romanToInt('LVIII')).toBe(58) 9 | }) 10 | -------------------------------------------------------------------------------- /test/string/string-matching-in-an-array.test.ts: -------------------------------------------------------------------------------- 1 | import { stringMatching } from '../../src/string/string-matching-in-an-array' 2 | 3 | test('数组中的字符串匹配', () => { 4 | // 示例 1: 5 | // 输入:words = ["mass","as","hero","superhero"] 6 | // 输出:["as","hero"] 7 | // 解释:"as" 是 "mass" 的子字符串,"hero" 是 "superhero" 的子字符串。 8 | // ["hero","as"] 也是有效的答案。 9 | expect(stringMatching(["mass", "as", "hero", "superhero"])).toEqual(["as", "hero"]) 10 | 11 | // 示例 2: 12 | // 输入:words = ["leetcode","et","code"] 13 | // 输出:["et","code"] 14 | // 解释:"et" 和 "code" 都是 "leetcode" 的子字符串。 15 | expect(stringMatching(["leetcode", "et", "code"])).toEqual(["et", "code"]) 16 | 17 | // 示例 3: 18 | // 输入:words = ["blue","green","bu"] 19 | // 输出:[] 20 | 21 | expect(stringMatching(["blue", "green", "bu"])).toEqual([]) 22 | }) -------------------------------------------------------------------------------- /test/string/string2int.test.ts: -------------------------------------------------------------------------------- 1 | import { string2int } from '../../src/string/string2int' 2 | 3 | test('实现string2int()函数', () => { 4 | // 测试: 5 | if (string2int('0') === 0 && string2int('12345') === 12345 && string2int('12300') === 12300) { 6 | if (string2int.toString().indexOf('parseInt') !== -1) { 7 | console.log('请勿使用parseInt()!') 8 | } else if (string2int.toString().indexOf('Number') !== -1) { 9 | console.log('请勿使用Number()!') 10 | } else { 11 | console.log('测试通过!') 12 | } 13 | } else { 14 | console.log('测试失败!') 15 | } 16 | 17 | expect(string2int('123')).toBe(123) 18 | expect(string2int('12300')).toBe(12300) 19 | expect(string2int('0')).toBe(0) 20 | 21 | // 注意,仅为提供面试思路,实现不严谨 22 | }) 23 | -------------------------------------------------------------------------------- /test/string/unique-characters.test.ts: -------------------------------------------------------------------------------- 1 | import { isUnique } from '../../src/string/unique-characters' 2 | 3 | test('判断字符串是否没有重复字符', () => { 4 | expect(isUnique('abc___')).toBe(false) 5 | expect(isUnique('abc')).toBe(true) 6 | }) 7 | -------------------------------------------------------------------------------- /test/string/valid-palindrome-ii.test.ts: -------------------------------------------------------------------------------- 1 | import { validPalindrome } from '../../src/string/valid-palindrome-ii' 2 | 3 | test('验证回文字符串 Ⅱ', () => { 4 | expect(validPalindrome('aba')).toBe(true) 5 | expect(validPalindrome('abba')).toBe(true) 6 | expect(validPalindrome('abca')).toBe(true) 7 | expect(validPalindrome('abcda')).toBe(false) 8 | }) 9 | -------------------------------------------------------------------------------- /test/string/zuo-xuan-zhuan-zi-fu-chuan-lcof.test.ts: -------------------------------------------------------------------------------- 1 | import { reverseLeftWords } from '../../src/string/zuo-xuan-zhuan-zi-fu-chuan-lcof' 2 | 3 | test('左旋转字符串', () => { 4 | expect(reverseLeftWords('abcdefg', 2)).toBe('cdefgab') 5 | expect(reverseLeftWords('lrloseumgh', 6)).toBe('umghlrlose') 6 | }) 7 | -------------------------------------------------------------------------------- /test/tree/bfs.test.ts: -------------------------------------------------------------------------------- 1 | import { bfs } from '../../src/tree/bfs' 2 | import { TreeNode } from '../../src/lib/TreeNode' 3 | 4 | // * 为了方便查看整个Tree的定义方式。建议通过常规方法创建整棵树 5 | const tree: TreeNode = { 6 | val: 1, 7 | left: { 8 | val: 2, 9 | left: { 10 | val: 4, 11 | left: null, 12 | right: null 13 | }, 14 | right: { 15 | val: 5, 16 | left: null, 17 | right: null 18 | } 19 | }, 20 | right: { 21 | val: 3, 22 | left: { 23 | val: 6, 24 | left: null, 25 | right: null 26 | }, 27 | right: null 28 | } 29 | } 30 | 31 | test('二叉树广度优先遍历', () => { 32 | expect(bfs(tree)).toEqual([1, 2, 3, 4, 5, 6]) 33 | }) -------------------------------------------------------------------------------- /test/tree/binary-tree-level-order-traversal-ii.test.ts: -------------------------------------------------------------------------------- 1 | import { levelOrder } from '../../src/tree/binary-tree-level-order-traversal-ii' 2 | import Tree from '../../src/tree/Tree' 3 | 4 | test('二叉树的层序遍历 II', () => { 5 | const source = [3, 9, 20, null, null, 15, 7] 6 | expect(levelOrder(Tree.arrToTree(source))).toEqual([ 7 | [15, 7], 8 | [9, 20], 9 | [3] 10 | ]) 11 | 12 | expect(levelOrder(Tree.arrToTree([]))).toEqual([]) 13 | }) 14 | -------------------------------------------------------------------------------- /test/tree/binary-tree-level-order-traversal.test.ts: -------------------------------------------------------------------------------- 1 | import { levelOrder } from '../../src/tree/binary-tree-level-order-traversal' 2 | import Tree from '../../src/tree/Tree' 3 | 4 | test('二叉树的层序遍历', () => { 5 | const source = [3, 9, 20, null, null, 15, 7] 6 | expect(levelOrder(Tree.arrToTree(source))).toEqual([ 7 | [3], 8 | [9, 20], 9 | [15, 7] 10 | ]) 11 | 12 | expect(levelOrder(Tree.arrToTree([]))).toEqual([]) 13 | }) 14 | -------------------------------------------------------------------------------- /test/tree/binary-tree-right-side-view.test.ts: -------------------------------------------------------------------------------- 1 | import { rightSideView } from '../../src/tree/binary-tree-right-side-view' 2 | import Tree from '../../src/tree/Tree' 3 | 4 | test('二叉树的右视图', () => { 5 | const arr = [1, 2, 3, null, 5, null, 4] 6 | 7 | expect(rightSideView(Tree.arrToTree(arr))).toEqual([1, 3, 4]) 8 | expect(rightSideView(Tree.arrToTree([]))).toEqual([]) 9 | }) 10 | -------------------------------------------------------------------------------- /test/tree/construct-binary-tree-from-preorder-and-inorder-traversal.test.ts: -------------------------------------------------------------------------------- 1 | import { buildTree } from '../../src/tree/construct-binary-tree-from-preorder-and-inorder-traversal' 2 | 3 | test('从前序与中序遍历序列构造二叉树', () => { 4 | expect(buildTree([3, 9, 20, 15, 7], [9, 3, 15, 20, 7])).toEqual({ left: { left: null, right: null, val: 9 }, right: { left: { left: null, right: null, val: 15 }, right: { left: null, right: null, val: 7 }, val: 20 }, val: 3 }) 5 | }) 6 | -------------------------------------------------------------------------------- /test/tree/convert-sorted-array-to-binary-search-tree.test.ts: -------------------------------------------------------------------------------- 1 | import { sortedArrayToBST } from '../../src/tree/convert-sorted-array-to-binary-search-tree' 2 | 3 | test('将有序数组转换为二叉搜索树', () => { 4 | expect(sortedArrayToBST([])).toEqual(null) 5 | expect(sortedArrayToBST([-10, -3, 0, 5, 9])).toEqual({ left: { left: null, right: { left: null, right: null, val: -3 }, val: -10 }, right: { left: null, right: { left: null, right: null, val: 9 }, val: 5 }, val: 0 }) 6 | }) 7 | -------------------------------------------------------------------------------- /test/tree/lowest-common-ancestor-of-a-binary-tree.test.ts: -------------------------------------------------------------------------------- 1 | import { lowestCommonAncestor } from '../../src/tree/lowest-common-ancestor-of-a-binary-tree' 2 | import Tree from '../../src/tree/Tree' 3 | 4 | test('二叉树的最近公共祖先', () => { 5 | const head = Tree.arrToTree([3, 5, 1, 6, 2, 0, 8, null, null, 7, 4]) 6 | expect(lowestCommonAncestor(head, head!.left, head!.right)).toEqual(head) 7 | expect(lowestCommonAncestor(head, head!.left, head!.left!.right!.right)).toEqual(head!.left) 8 | 9 | const head2 = Tree.arrToTree([1, 2]) 10 | expect(lowestCommonAncestor(head2, head2!.left, head2!.right)).toEqual(head2) 11 | 12 | const head3 = Tree.arrToTree([1, 2, 3]) 13 | expect(lowestCommonAncestor(head3, head3!.right, head3!.left)).toEqual(head3) 14 | }) 15 | -------------------------------------------------------------------------------- /test/tree/my-calendar-i.test.ts: -------------------------------------------------------------------------------- 1 | import { MyCalendar } from '../../src/tree/my-calendar-i' 2 | 3 | test('我的日程安排表 I', () => { 4 | // 示例: 5 | // 输入: 6 | // ["MyCalendar", "book", "book", "book"] 7 | // [[], [10, 20], [15, 25], [20, 30]] 8 | // 输出: 9 | // [null, true, false, true] 10 | 11 | // 解释: 12 | const myCalendar = new MyCalendar() 13 | expect(myCalendar.book(10, 20)).toBeTruthy() // return True 14 | expect(myCalendar.book(15, 25)).toBeFalsy() // return False ,这个日程安排不能添加到日历中,因为时间 15 已经被另一个日程安排预订了。 15 | expect(myCalendar.book(20, 30)).toBeTruthy() // return True ,这个日程安排可以添加到日历中,因为第一个日程安排预订的每个时间都小于 20 ,且不包含时间 20 。 16 | expect(myCalendar.book(0, 10)).toBeTruthy() 17 | expect(myCalendar.book(0, 0)).toBeTruthy() 18 | expect(myCalendar.book(31, 32)).toBeTruthy() 19 | }) -------------------------------------------------------------------------------- /test/tree/same-tree.test.ts: -------------------------------------------------------------------------------- 1 | import { isSameTree } from '../../src/tree/same-tree' 2 | import Tree from '../../src/tree/Tree' 3 | 4 | test('相同的树', () => { 5 | // 示例 1: 6 | // 输入:p = [1,2,3], q = [1,2,3] 7 | // 输出:true 8 | expect(isSameTree(Tree.arrToTree([1, 2, 3]), Tree.arrToTree([1, 2, 3]))).toBeTruthy() 9 | 10 | // 示例 2: 11 | // 输入:p = [1,2], q = [1,null,2] 12 | // 输出:false 13 | expect(isSameTree(Tree.arrToTree([1, 2]), Tree.arrToTree([1, null, 2]))).toBeFalsy() 14 | 15 | // 示例 3: 16 | // 输入:p = [1,2,1], q = [1,1,2] 17 | // 输出:false 18 | expect(isSameTree(Tree.arrToTree([1, 2, 1]), Tree.arrToTree([1, 1, 2]))).toBeFalsy() 19 | 20 | expect(isSameTree(Tree.arrToTree([]), Tree.arrToTree([]))).toBeTruthy() 21 | expect(isSameTree(Tree.arrToTree([]), Tree.arrToTree([1, 1]))).toBeFalsy() 22 | expect(isSameTree(Tree.arrToTree([1, 1, 2]), Tree.arrToTree([1, 1]))).toBeFalsy() 23 | expect(isSameTree(Tree.arrToTree([1, 1]), Tree.arrToTree([1, 1, 2]))).toBeFalsy() 24 | expect(isSameTree(Tree.arrToTree([1, null, 2]), Tree.arrToTree([1, 1, 2]))).toBeFalsy() 25 | }) -------------------------------------------------------------------------------- /test/tree/subtree-of-another-tree.test.ts: -------------------------------------------------------------------------------- 1 | import { isSubtree } from '../../src/tree/subtree-of-another-tree' 2 | import Tree from '../../src/tree/Tree' 3 | 4 | test('另一个树的子树', () => { 5 | expect(isSubtree(Tree.arrToTree([3, 4, 5, 1, 2]), Tree.arrToTree([4, 1, 2]))).toBe(true) 6 | expect(isSubtree(Tree.arrToTree([3, 4, 5, 1, 2, null, null, null, null, 0]), Tree.arrToTree([4, 1, 2]))).toBe(false) 7 | }) 8 | -------------------------------------------------------------------------------- /test/tree/trim-a-binary-search-tree.test.ts: -------------------------------------------------------------------------------- 1 | import { trimBST } from '../../src/tree/trim-a-binary-search-tree' 2 | import Tree from '../../src/tree/Tree' 3 | 4 | test('修剪二叉搜索树', () => { 5 | // 示例 1: 6 | // 输入:root = [1,0,2], low = 1, high = 2 7 | // 输出:[1,null,2] 8 | expect(trimBST(Tree.arrToTree([1, 0, 2]), 1, 2)).toEqual(Tree.arrToTree([1, null, 2])) 9 | 10 | // 示例 2: 11 | // 输入:root = [3,0,4,null,2,null,null,1], low = 1, high = 3 12 | // 输出:[3,2,null,1] 13 | expect(trimBST(Tree.arrToTree([3, 0, 4, null, 2, null, null, 1]), 1, 3)).toEqual(Tree.arrToTree([3, 2, null, 1])) 14 | }) -------------------------------------------------------------------------------- /test/tree/unique-binary-search-trees.test.ts: -------------------------------------------------------------------------------- 1 | import { numTrees } from '../../src/tree/unique-binary-search-trees' 2 | 3 | test('不同的二叉搜索树', () => { 4 | expect(numTrees(3)).toBe(5) 5 | }) 6 | -------------------------------------------------------------------------------- /test/tree/validate-binary-search-tree.test.ts: -------------------------------------------------------------------------------- 1 | import { isValidBST } from '../../src/tree/validate-binary-search-tree' 2 | import Tree from '../../src/tree/Tree' 3 | 4 | test('验证二叉搜索树', () => { 5 | expect(isValidBST(Tree.arrToTree([1, 1]))).toBe(false) 6 | expect(isValidBST(Tree.arrToTree([2, 1, 3]))).toBe(true) 7 | expect(isValidBST(Tree.arrToTree([5, 1, 4, null, null, 3, 6]))).toBe(false) 8 | expect(isValidBST(Tree.arrToTree([-1]))).toBe(true) 9 | expect(isValidBST(Tree.arrToTree([2, 1, 4, null, null, 3, 5]))).toBe(true) 10 | expect(isValidBST(null)).toBe(true) 11 | expect(isValidBST(Tree.arrToTree([10, 5, 15, null, null, 6, 20]))).toBe(false) 12 | }) 13 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": true, 3 | "compilerOptions": { 4 | "importHelpers": true, 5 | "module": "esnext", 6 | "rootDir": "./", 7 | "target": "esnext", 8 | "sourceMap": true, 9 | "composite": true, 10 | "strict": true, 11 | "lib": [ 12 | "WebWorker", 13 | "ES2015", 14 | "ES2016", 15 | "ES2017", 16 | "ES2018", 17 | "ES2019", 18 | "ES2020", 19 | "ES2021", 20 | "ESNext" 21 | ], 22 | "moduleResolution": "nodenext", 23 | "experimentalDecorators": true, 24 | "emitDecoratorMetadata": true, 25 | "noImplicitThis": true, 26 | "noUnusedLocals": true, 27 | "resolveJsonModule": true, 28 | "esModuleInterop": true, 29 | "noImplicitAny": true 30 | }, 31 | "include": ["./src/**/*.ts", "./src/**/*.json"], 32 | "exclude": ["dist", "node_modules"] 33 | } 34 | --------------------------------------------------------------------------------