├── .babelrc ├── .eslintrc ├── .gitignore ├── .npmignore ├── .prettierrc ├── README.md ├── cover.jpg ├── package.json ├── src ├── algo │ ├── bfs │ │ └── level-order-traversal.js │ ├── binary-search │ │ ├── v1 │ │ │ ├── README.md │ │ │ ├── binary-search.js │ │ │ ├── binary-search.spec.js │ │ │ ├── ceil.js │ │ │ ├── ceil.spec.js │ │ │ ├── docs │ │ │ │ └── lower-bound-upper-bound.png │ │ │ ├── floor.js │ │ │ ├── floor.spec.js │ │ │ ├── lower-bound.js │ │ │ ├── lower-bound.spec.js │ │ │ ├── upper-bound.js │ │ │ └── upper-bound.spec.js │ │ └── v2 │ │ │ ├── index.js │ │ │ └── index.spec.js │ ├── gcd │ │ └── index.js │ ├── graph │ │ └── articulation-point │ │ │ ├── articulation-point.pdf │ │ │ └── index.js │ ├── heap │ │ ├── index.js │ │ └── index.spec.js │ ├── merge-sort │ │ ├── index.js │ │ ├── index.spec.js │ │ └── v1.js │ ├── numbers │ │ ├── README.md │ │ ├── to-binary.js │ │ ├── to-binary.spec.js │ │ ├── to-hex.js │ │ └── to-hex.spec.js │ ├── quick-select │ │ ├── index.js │ │ └── index.spec.js │ ├── quick-sort │ │ ├── index.js │ │ ├── index.spec.js │ │ └── v1.js │ └── topological-sort │ │ ├── index.js │ │ └── index.spec.js ├── data-structure │ ├── binary-indexed-tree-2d │ │ ├── index.js │ │ └── index.spec.js │ ├── binary-indexed-tree │ │ ├── Binary Indexed Tree.pdf │ │ ├── README.md │ │ ├── index.js │ │ └── index.spec.js │ ├── bst │ │ ├── index.js │ │ └── index.spec.js │ ├── priority-queue │ │ ├── v1 │ │ │ ├── __tests__ │ │ │ │ └── index.js │ │ │ ├── bubbleDown.js │ │ │ ├── bubbleUp.js │ │ │ ├── defaultComparator.js │ │ │ ├── index.js │ │ │ └── swap.js │ │ ├── v2 │ │ │ └── index.js │ │ ├── v3 │ │ │ ├── index.js │ │ │ └── index.spec.js │ │ └── v4 │ │ │ ├── index.js │ │ │ └── index.spec.js │ ├── sorted-map │ │ ├── index.js │ │ └── index.spec.js │ ├── trie │ │ ├── index.js │ │ └── index.spec.js │ └── union-find │ │ ├── index.js │ │ └── index.spec.js ├── interviews │ └── facebook │ │ └── 2020-03-20 │ │ └── index.js ├── leetcode │ ├── 01-matrix │ │ └── index.js │ ├── 24-game │ │ └── index.js │ ├── 3sum-closest │ │ ├── index.js │ │ └── no-sorting.js │ ├── 3sum-smaller │ │ └── index.js │ ├── 3sum-with-multiplicity │ │ └── index.js │ ├── 3sum │ │ ├── hash.js │ │ └── index.js │ ├── 4-keys-keyboard │ │ ├── README.md │ │ └── index.js │ ├── 4sum-ii │ │ └── index.js │ ├── 4sum │ │ ├── index.js │ │ └── index.spec.js │ ├── README.md │ ├── accounts-merge │ │ ├── 721. Accounts Merge.pdf │ │ ├── index.error.js │ │ └── index.js │ ├── add-and-search-word-data-structure-design │ │ ├── Add and Search Word - Data structure design.pdf │ │ └── index.js │ ├── add-binary │ │ └── index.js │ ├── add-bold-tag-in-string │ │ └── index.js │ ├── add-digits │ │ └── index.js │ ├── add-strings │ │ └── index.js │ ├── add-two-numbers-ii │ │ └── index.js │ ├── add-two-numbers │ │ ├── 2. Add Two Numbers.pdf │ │ └── index.js │ ├── adding-two-negabinary-numbers │ │ ├── 1073. Adding Two Negabinary Numbers 2019-08-04.pdf │ │ ├── README.md │ │ └── index.js │ ├── alien-dictionary │ │ ├── 2019-02-17.js │ │ ├── Alien Dictionary.pdf │ │ ├── README.md │ │ └── index.js │ ├── all-nodes-distance-k-in-binary-tree │ │ ├── bfs.js │ │ └── index.js │ ├── all-oone-data-structure │ │ ├── IMG_3581.JPG │ │ ├── README.md │ │ └── index.js │ ├── all-paths-from-source-lead-to-destination │ │ └── index.js │ ├── all-paths-from-source-to-target │ │ └── index.js │ ├── all-possible-full-binary-trees │ │ ├── dp.js │ │ └── index.js │ ├── alphabet-board-path │ │ └── index.js │ ├── as-far-from-land-as-possible │ │ ├── README.md │ │ └── index.js │ ├── average-of-levels-in-binary-tree │ │ └── index.js │ ├── backspace-string-compare │ │ └── index.js │ ├── balance-a-binary-search-tree │ │ └── index.js │ ├── balanced-binary-tree │ │ └── index.js │ ├── basic-calculator-ii │ │ ├── 227. Basic Calculator II.pdf │ │ └── index.js │ ├── basic-calculator-iii │ │ ├── index.js │ │ └── submit.png │ ├── basic-calculator │ │ ├── README.md │ │ └── index.js │ ├── battleships-in-a-board │ │ └── index.js │ ├── best-meeting-point │ │ └── index.js │ ├── best-time-to-buy-and-sell-stock-ii │ │ └── index.js │ ├── best-time-to-buy-and-sell-stock-iii │ │ ├── 123. Best Time to Buy and Sell Stock III.pdf │ │ ├── 2019-11-14-v2.js │ │ ├── 2019-11-14-v3.js │ │ ├── 2019-11-14.js │ │ ├── README.md │ │ ├── index.js │ │ ├── k.js │ │ ├── left-right.js │ │ └── space-O(m).js │ ├── best-time-to-buy-and-sell-stock-iv │ │ ├── 188. Best Time to Buy and Sell Stock IV.pdf │ │ ├── README.md │ │ └── index.js │ ├── best-time-to-buy-and-sell-stock-with-cooldown │ │ ├── README.md │ │ ├── index.js │ │ ├── time-n.js │ │ └── time-n2.js │ ├── best-time-to-buy-and-sell-stock │ │ └── index.js │ ├── binary-search-tree-iterator │ │ └── index.js │ ├── binary-search │ │ ├── index.js │ │ └── index.spec.js │ ├── binary-subarrays-with-sum │ │ └── index.js │ ├── binary-tree-coloring-game │ │ └── index.js │ ├── binary-tree-inorder-traversal │ │ └── index.js │ ├── binary-tree-level-order-traversal-ii │ │ ├── Binary Tree Level Order Traversal II.pdf │ │ └── index.js │ ├── binary-tree-level-order-traversal │ │ └── index.js │ ├── binary-tree-longest-consecutive-sequence-ii │ │ ├── index.js │ │ └── submit.png │ ├── binary-tree-longest-consecutive-sequence │ │ └── index.js │ ├── binary-tree-maximum-path-sum │ │ ├── 124. Binary Tree Maximum Path Sum.pdf │ │ ├── README.md │ │ └── index.js │ ├── binary-tree-paths │ │ └── index.js │ ├── binary-tree-postorder-traversal │ │ └── index.js │ ├── binary-tree-preorder-traversal │ │ └── index.js │ ├── binary-tree-right-side-view │ │ └── index.js │ ├── binary-tree-upside-down │ │ └── index.js │ ├── binary-tree-vertical-order-traversal │ │ └── index.js │ ├── binary-tree-zigzag-level-order-traversal │ │ └── index.js │ ├── bomb-enemy │ │ ├── index.js │ │ └── v1.js │ ├── boundary-of-binary-tree │ │ └── index.js │ ├── brace-expansion-ii │ │ ├── README.md │ │ └── index.js │ ├── brace-expansion │ │ ├── README.md │ │ └── index.js │ ├── bulb-switcher-ii │ │ └── index.js │ ├── bulb-switcher │ │ └── index.js │ ├── bulls-and-cows │ │ └── index.js │ ├── bus-routes │ │ ├── README.md │ │ └── index.js │ ├── campus-bikes-ii │ │ ├── README.md │ │ ├── index.js │ │ └── submit.png │ ├── campus-bikes │ │ └── index.js │ ├── can-make-palindrome-from-substring │ │ └── index.js │ ├── candy │ │ └── index.js │ ├── capacity-to-ship-packages-within-d-days │ │ ├── README.md │ │ └── index.js │ ├── car-pooling │ │ └── index.js │ ├── cells-with-odd-values-in-a-matrix │ │ └── index.js │ ├── cheapest-flights-within-k-stops │ │ ├── README.md │ │ └── index.js │ ├── check-completeness-of-a-binary-tree │ │ ├── README.md │ │ └── index.js │ ├── check-if-it-is-a-good-array │ │ ├── README.md │ │ └── index.js │ ├── check-if-it-is-a-straight-line │ │ └── index.js │ ├── check-if-n-and-its-double-exist │ │ └── index.js │ ├── cherry-pickup │ │ ├── README.md │ │ └── index.js │ ├── circular-permutation-in-binary-representation │ │ └── index.js │ ├── climbing-stairs │ │ └── index.js │ ├── clone-graph │ │ └── index.js │ ├── closest-binary-search-tree-value-ii │ │ ├── 272. Closest Binary Search Tree Value II.pdf │ │ └── index.js │ ├── closest-binary-search-tree-value │ │ └── index.js │ ├── closest-divisors │ │ └── index.js │ ├── coin-change-2 │ │ ├── 518. Coin Change 2.pdf │ │ └── index.js │ ├── coin-change │ │ ├── README.md │ │ └── index.js │ ├── combination-sum-ii │ │ └── index.js │ ├── combination-sum-iii │ │ └── index.js │ ├── combination-sum │ │ └── index.js │ ├── combinations │ │ ├── index.js │ │ └── index.spec.js │ ├── compare-strings-by-frequency-of-the-smallest-character │ │ └── index.js │ ├── compare-version-numbers │ │ └── index.js │ ├── concatenated-words │ │ └── index.js │ ├── confusing-number │ │ └── index.js │ ├── connecting-cities-with-minimum-cost │ │ ├── README.md │ │ └── index.js │ ├── construct-binary-search-tree-from-preorder-traversal │ │ └── index.js │ ├── construct-binary-tree-from-inorder-and-postorder-traversal │ │ └── index.js │ ├── construct-binary-tree-from-preorder-and-inorder-traversal │ │ └── index.js │ ├── construct-binary-tree-from-preorder-and-postorder-traversal │ │ ├── README.md │ │ ├── index.js │ │ └── submit.png │ ├── construct-binary-tree-from-string │ │ └── index.js │ ├── construct-quad-tree │ │ └── index.js │ ├── construct-string-from-binary-tree │ │ └── index.js │ ├── container-with-most-water │ │ ├── 11. Container With Most Water.pdf │ │ ├── index.js │ │ └── index.spec.js │ ├── contains-duplicate │ │ └── index.js │ ├── contiguous-array │ │ └── index.js │ ├── continuous-subarray-sum │ │ ├── README.md │ │ ├── index.js │ │ └── note.pdf │ ├── convert-a-number-to-hexadecimal │ │ ├── README.md │ │ └── index.js │ ├── convert-binary-number-in-a-linked-list-to-integer │ │ └── index.js │ ├── convert-binary-search-tree-to-sorted-doubly-linked-list │ │ └── index.js │ ├── convert-sorted-array-to-binary-search-tree │ │ └── index.js │ ├── convert-sorted-list-to-binary-search-tree │ │ └── index.js │ ├── convert-to-base-2 │ │ ├── README.md │ │ ├── index.js │ │ ├── to base -2.pdf │ │ ├── to base -8.pdf │ │ └── what happens to 9 >> 1.pdf │ ├── copy-list-with-random-pointer │ │ ├── 138. Copy List with Random Pointer.pdf │ │ └── index.js │ ├── count-and-say │ │ └── index.js │ ├── count-complete-tree-nodes │ │ └── index.js │ ├── count-negative-numbers-in-a-sorted-matrix │ │ └── index.js │ ├── count-number-of-nice-subarrays │ │ └── index.js │ ├── count-of-range-sum │ │ ├── README.md │ │ └── index.js │ ├── count-of-smaller-numbers-after-self │ │ └── binary-search.js │ ├── count-primes │ │ ├── index.js │ │ └── index.spec.js │ ├── count-servers-that-communicate │ │ └── index.js │ ├── count-square-submatrices-with-all-ones │ │ ├── README.md │ │ └── index.js │ ├── course-schedule-ii │ │ └── index.js │ ├── course-schedule-iii │ │ └── index.js │ ├── course-schedule │ │ ├── README.md │ │ └── index.js │ ├── cracking-the-safe │ │ └── index.js │ ├── critical-connections-in-a-network │ │ ├── 1192. Critical Connections in a Network.pdf │ │ ├── README.md │ │ ├── index.js │ │ └── v1.js │ ├── custom-sort-string │ │ └── index.js │ ├── cut-off-trees-for-golf-event │ │ ├── README.md │ │ └── index.js │ ├── daily-temperatures │ │ └── index.js │ ├── data-stream-as-disjoint-intervals │ │ └── index.js │ ├── decode-string │ │ ├── README.md │ │ ├── index.js │ │ ├── recursive.js │ │ └── stack.js │ ├── decode-ways-ii │ │ └── index.js │ ├── decode-ways │ │ ├── Decode ways.pdf │ │ ├── README.md │ │ └── index.js │ ├── decrypt-string-from-alphabet-to-integer-mapping │ │ └── index.js │ ├── defanging-an-ip-address │ │ └── index.js │ ├── delete-and-earn │ │ ├── README.md │ │ └── index.js │ ├── delete-leaves-with-a-given-value │ │ └── index.js │ ├── delete-node-in-a-bst │ │ └── index.js │ ├── delete-nodes-and-return-forest │ │ └── index.js │ ├── delete-operation-for-two-strings │ │ ├── README.md │ │ └── index.js │ ├── design-a-leaderboard │ │ ├── README.md │ │ └── index.js │ ├── design-add-and-search-words-data-structure │ │ └── index.js │ ├── design-circular-deque │ │ └── index.js │ ├── design-circular-queue │ │ └── index.js │ ├── design-hashmap │ │ └── index.js │ ├── design-hit-counter │ │ └── index.js │ ├── design-linked-list │ │ └── inedx.js │ ├── design-search-autocomplete-system │ │ ├── README.md │ │ ├── index.js │ │ └── trie.js │ ├── design-tic-tac-toe │ │ └── index.js │ ├── design-twitter │ │ └── index.js │ ├── diagonal-traverse │ │ ├── 498. Diagonal Traverse.pdf │ │ └── index.js │ ├── diameter-of-binary-tree │ │ └── index.js │ ├── diet-plan-performance │ │ └── index.js │ ├── different-ways-to-add-parentheses │ │ └── index.js │ ├── distance-between-bus-stops │ │ └── index.js │ ├── distinct-subsequences │ │ └── index.js │ ├── distribute-coins-in-binary-tree │ │ ├── README.md │ │ └── index.js │ ├── divide-array-in-sets-of-k-consecutive-numbers │ │ └── index.js │ ├── divide-two-integers │ │ ├── 29. Divide Two Integers.pdf │ │ ├── index.js │ │ ├── index.spec.js │ │ └── screencapture-leetcode-submissions-detail-179251987-2018-09-29-20_31_17.png │ ├── dot-product-of-two-sparse-vectors │ │ └── index.js │ ├── duplicate-zeros │ │ ├── index.js │ │ └── v2.js │ ├── edit-distance │ │ ├── README.md │ │ ├── index.js │ │ └── v1.js │ ├── employee-free-time │ │ └── index.js │ ├── encode-and-decode-strings │ │ └── index.js │ ├── encode-and-decode-tinyurl │ │ └── index.js │ ├── equal-tree-partition │ │ └── index.js │ ├── evaluate-division │ │ ├── README.md │ │ └── index.js │ ├── evaluate-reverse-polish-notation │ │ └── index.js │ ├── exam-room │ │ └── index.js │ ├── excel-sheet-column-number │ │ └── index.js │ ├── excel-sheet-column-title │ │ ├── README.md │ │ └── index.js │ ├── exclusive-time-of-functions │ │ ├── 636. Exclusive Time of Functions.pdf │ │ └── index.js │ ├── expression-add-operators │ │ ├── README.md │ │ ├── index.js │ │ ├── v1.js │ │ └── v2.js │ ├── expressive-words │ │ └── index.js │ ├── factor-combinations │ │ └── index.js │ ├── falling-squares │ │ └── index.js │ ├── fibonacci-number │ │ └── index.js │ ├── find-all-anagrams-in-a-string │ │ ├── index.js │ │ └── index.tle.js │ ├── find-all-duplicates-in-an-array │ │ └── index.js │ ├── find-and-replace-in-string │ │ └── index.js │ ├── find-bottom-left-tree-value │ │ └── index.js │ ├── find-duplicate-subtrees │ │ └── index.js │ ├── find-first-and-last-position-of-element-in-sorted-array │ │ └── index.js │ ├── find-in-mountain-array │ │ └── index.js │ ├── find-k-closest-elements │ │ ├── README.md │ │ └── index.js │ ├── find-k-length-substrings-with-no-repeated-characters │ │ └── index.js │ ├── find-k-pairs-with-smallest-sums │ │ ├── README.md │ │ └── index.js │ ├── find-k-th-smallest-pair-distance │ │ └── index.js │ ├── find-largest-value-in-each-tree-row │ │ └── index.js │ ├── find-leaves-of-binary-tree │ │ ├── README.md │ │ └── index.js │ ├── find-median-from-data-stream │ │ ├── 295. Find Median from Data Stream 2.pdf │ │ ├── 295. Find Median from Data Stream.pdf │ │ └── index.js │ ├── find-minimum-in-rotated-sorted-array-ii │ │ ├── README.md │ │ └── index.js │ ├── find-minimum-in-rotated-sorted-array │ │ ├── README.md │ │ └── index.js │ ├── find-peak-element │ │ ├── README.md │ │ └── index.js │ ├── find-pivot-index │ │ └── index.js │ ├── find-right-interval │ │ └── index.js │ ├── find-smallest-common-element-in-all-rows │ │ └── index.js │ ├── find-the-celebrity │ │ └── index.js │ ├── find-the-closest-palindrome │ │ ├── README.md │ │ └── index.js │ ├── find-the-duplicate-number │ │ └── index.js │ ├── find-the-shortest-superstring │ │ ├── README.md │ │ ├── index.js │ │ └── tle.js │ ├── find-the-smallest-divisor-given-a-threshold │ │ └── index.js │ ├── find-words-that-can-be-formed-by-characters │ │ └── index.js │ ├── first-bad-version │ │ ├── 278. First Bad Version.pdf │ │ └── index.js │ ├── first-missing-positive │ │ └── index.js │ ├── first-unique-character-in-a-string │ │ └── index.js │ ├── fixed-point │ │ └── index.js │ ├── flatten-2d-vector │ │ └── index.js │ ├── flatten-a-multilevel-doubly-linked-list │ │ ├── index.js │ │ └── recursive.js │ ├── flatten-binary-tree-to-linked-list │ │ ├── index.js │ │ └── v1.js │ ├── flatten-nested-list-iterator │ │ └── index.js │ ├── flip-equivalent-binary-trees │ │ └── index.js │ ├── flood-fill │ │ └── index.js │ ├── four-divisors │ │ └── index.js │ ├── fraction-to-recurring-decimal │ │ ├── README.md │ │ ├── index.js │ │ └── submit.png │ ├── friend-circles │ │ └── index.js │ ├── friends-of-appropriate-ages │ │ ├── README.md │ │ └── index.js │ ├── fruit-into-baskets │ │ └── index.js │ ├── game-of-life │ │ └── index.js │ ├── gas-station │ │ └── index.js │ ├── generalized-abbreviation │ │ └── index.js │ ├── generate-parentheses │ │ ├── README.md │ │ └── index.js │ ├── get-equal-substrings-within-budget │ │ └── index.js │ ├── get-watched-videos-by-your-friends │ │ └── index.js │ ├── goat-latin │ │ ├── Goat Latin.pdf │ │ └── index.js │ ├── graph-valid-tree │ │ ├── README.md │ │ └── index.js │ ├── gray-code │ │ ├── README.md │ │ └── idnex.js │ ├── greatest-common-divisor-of-strings │ │ └── index.js │ ├── greatest-sum-divisible-by-three │ │ ├── README.md │ │ └── index.js │ ├── group-anagrams │ │ └── index.js │ ├── group-shifted-strings │ │ └── index.js │ ├── group-the-people-given-the-group-size-they-belong-to │ │ └── index.js │ ├── guess-the-word │ │ └── index.js │ ├── h-index-ii │ │ └── index.js │ ├── h-index │ │ └── index.js │ ├── hamming-distance │ │ └── index.js │ ├── happy-number │ │ ├── README.md │ │ └── index.js │ ├── high-five │ │ └── index.js │ ├── house-robber-ii │ │ └── index.js │ ├── house-robber-iii │ │ ├── FireShot_Capture_2_-__1__House_Robber_III_-_Su__-_https___leetcode_com_submissions_detail_174593214_.png │ │ └── index.js │ ├── house-robber │ │ └── index.js │ ├── how-many-numbers-are-smaller-than-the-current-number │ │ └── index.js │ ├── image-overlap │ │ └── index.js │ ├── implement-magic-dictionary │ │ ├── README.md │ │ └── index.js │ ├── implement-strstr │ │ ├── index.js │ │ └── kmp.js │ ├── implement-trie-prefix-tree │ │ └── index.js │ ├── increasing-subsequences │ │ ├── index.js │ │ └── submit.png │ ├── increasing-triplet-subsequence │ │ ├── README.md │ │ └── index.js │ ├── inorder-successor-in-bst-ii │ │ └── index.js │ ├── inorder-successor-in-bst │ │ └── index.js │ ├── insert-delete-getrandom-o1-duplicates-allowed │ │ ├── 381. Insert Delete GetRandom O(1) - Duplicates allowed.pdf │ │ └── index.js │ ├── insert-delete-getrandom-o1 │ │ └── index.js │ ├── insert-interval │ │ ├── 57. Insert Interval.pdf │ │ └── index.js │ ├── insert-into-a-binary-search-tree │ │ └── index.js │ ├── insert-into-a-cyclic-sorted-list │ │ ├── README.md │ │ └── index.js │ ├── insertion-sort-list │ │ ├── 147. Insertion Sort List.pdf │ │ └── index.js │ ├── insufficient-nodes-in-root-to-leaf-paths │ │ └── index.js │ ├── integer-to-english-words │ │ ├── index.js │ │ ├── index.spec.js │ │ ├── v2.js │ │ └── v3.js │ ├── integer-to-roman │ │ ├── README.md │ │ └── index.js │ ├── interleaving-string │ │ ├── README.md │ │ └── index.js │ ├── intersection-of-three-sorted-arrays │ │ └── index.js │ ├── intersection-of-two-arrays-ii │ │ └── index.js │ ├── intersection-of-two-arrays │ │ └── index.js │ ├── intersection-of-two-linked-lists │ │ └── index.js │ ├── interval-list-intersections │ │ └── index.js │ ├── invert-binary-tree │ │ └── index.js │ ├── is-graph-bipartite │ │ ├── Is graph bipartite.pdf │ │ └── index.js │ ├── is-subsequence │ │ ├── index.js │ │ ├── recursive.js │ │ └── two-ptrs.js │ ├── island-perimeter │ │ └── index.js │ ├── isomorphic-strings │ │ └── index.js │ ├── jewels-and-stones │ │ └── index.js │ ├── jump-game-ii │ │ ├── 45. Jump Game II.pdf │ │ └── index.js │ ├── jump-game-iii │ │ └── index.js │ ├── jump-game-v │ │ └── index.js │ ├── jump-game │ │ ├── 55. Jump Game.pdf │ │ └── index.js │ ├── k-closest-points-to-origin │ │ ├── 973. K Closest Points to Origin.pdf │ │ ├── index.js │ │ ├── recursive.js │ │ └── topk.pdf │ ├── k-concatenation-maximum-sum │ │ └── index.js │ ├── knight-dialer │ │ ├── README.md │ │ └── index.js │ ├── knight-probability-in-chessboard │ │ ├── README.md │ │ └── index.js │ ├── koko-eating-bananas │ │ └── index.js │ ├── kth-largest-element-in-a-stream │ │ ├── index.bst.js │ │ ├── index.js │ │ └── index.spec.js │ ├── kth-largest-element-in-an-array │ │ ├── README.md │ │ ├── index.js │ │ └── index.spec.js │ ├── kth-smallest-element-in-a-bst │ │ └── index.js │ ├── kth-smallest-element-in-a-sorted-matrix │ │ ├── 378. Kth Smallest Element in a Sorted Matrix.pdf │ │ └── index.js │ ├── kth-smallest-number-in-multiplication-table │ │ └── index.js │ ├── largest-divisible-subset │ │ ├── index.js │ │ └── index.spec.js │ ├── largest-plus-sign │ │ └── index.js │ ├── largest-rectangle-in-histogram │ │ ├── Largest Rectangle in Histogram 3.pdf │ │ └── index.js │ ├── last-substring-in-lexicographical-order │ │ └── index.js │ ├── leftmost-column-with-at-least-a-one │ │ ├── binary-search.js │ │ └── index.js │ ├── length-of-last-word │ │ └── index.js │ ├── length-of-longest-fibonacci-subsequence │ │ └── index.js │ ├── letter-combinations-of-a-phone-number │ │ └── index.js │ ├── license-key-formatting │ │ └── index.js │ ├── linked-list-components │ │ └── index.js │ ├── linked-list-cycle-ii │ │ └── index.js │ ├── linked-list-cycle │ │ └── index.js │ ├── linked-list-in-binary-tree │ │ └── index.js │ ├── linked-list-random-node │ │ └── index.js │ ├── logger-rate-limiter │ │ └── index.js │ ├── lonely-pixel-i │ │ └── index.js │ ├── longest-absolute-file-path │ │ ├── README.md │ │ └── index.js │ ├── longest-arithmetic-sequence │ │ ├── README.md │ │ └── index.js │ ├── longest-common-prefix │ │ └── index.js │ ├── longest-common-subsequence │ │ ├── README.md │ │ └── index.js │ ├── longest-consecutive-sequence │ │ └── index.js │ ├── longest-continuous-increasing-subsequence │ │ └── index.js │ ├── longest-duplicate-substring │ │ └── index.js │ ├── longest-increasing-path-in-a-matrix │ │ └── index.js │ ├── longest-increasing-subsequence │ │ └── index.js │ ├── longest-line-of-consecutive-one-in-matrix │ │ └── index.js │ ├── longest-mountain-in-array │ │ └── index.js │ ├── longest-palindrome │ │ ├── index.js │ │ └── index.spec.js │ ├── longest-palindromic-subsequence │ │ ├── README.md │ │ └── index.js │ ├── longest-palindromic-substring │ │ ├── README.md │ │ ├── dp.js │ │ └── index.js │ ├── longest-repeating-character-replacement │ │ ├── README.md │ │ └── index.js │ ├── longest-string-chain │ │ ├── README.md │ │ ├── index.js │ │ └── v1.js │ ├── longest-substring-with-at-least-k-repeating-characters │ │ └── index.js │ ├── longest-substring-with-at-most-k-distinct-characters │ │ └── index.js │ ├── longest-substring-with-at-most-two-distinct-characters │ │ └── index.js │ ├── longest-substring-without-repeating-characters │ │ └── index.js │ ├── longest-valid-parentheses │ │ ├── 32. Longest Valid Parentheses.pdf │ │ └── index.js │ ├── longest-word-in-dictionary-through-deleting │ │ └── index.js │ ├── lowest-common-ancestor-of-a-binary-search-tree │ │ └── index.js │ ├── lowest-common-ancestor-of-a-binary-tree-iii │ │ └── index.js │ ├── lowest-common-ancestor-of-a-binary-tree │ │ └── index.js │ ├── lowest-common-ancestor-of-deepest-leaves │ │ └── index.js │ ├── lru-cache │ │ ├── index.js │ │ └── map.js │ ├── lucky-numbers-in-a-matrix │ │ └── index.js │ ├── majority-element-ii │ │ └── index.js │ ├── majority-element │ │ ├── bit.js │ │ ├── index.js │ │ └── v1.js │ ├── making-a-large-island │ │ └── index.js │ ├── max-area-of-island │ │ └── index.js │ ├── max-chunks-to-make-sorted │ │ └── index.js │ ├── max-consecutive-ones-ii │ │ ├── README.md │ │ └── index.js │ ├── max-consecutive-ones-iii │ │ ├── dp.js │ │ └── index.js │ ├── max-consecutive-ones │ │ └── index.js │ ├── max-increase-to-keep-city-skyline │ │ └── index.js │ ├── max-points-on-a-line │ │ ├── README.md │ │ ├── index.js │ │ └── submit.png │ ├── max-stack │ │ └── index.js │ ├── max-sum-of-rectangle-no-larger-than-k │ │ ├── README.md │ │ └── index.js │ ├── maximal-rectangle │ │ └── index.js │ ├── maximal-square │ │ ├── README.md │ │ └── index.js │ ├── maximize-distance-to-closest-person │ │ └── index.js │ ├── maximum-69-number │ │ └── index.js │ ├── maximum-binary-tree │ │ └── index.js │ ├── maximum-depth-of-binary-tree │ │ └── index.js │ ├── maximum-difference-between-node-and-ancestor │ │ └── index.js │ ├── maximum-frequency-stack │ │ └── index.js │ ├── maximum-length-of-a-concatenated-string-with-unique-characters │ │ ├── README.md │ │ └── index.js │ ├── maximum-length-of-repeated-subarray │ │ ├── README.md │ │ └── index.js │ ├── maximum-level-sum-of-a-binary-tree │ │ └── index.js │ ├── maximum-number-of-balloons │ │ └── index.js │ ├── maximum-number-of-events-that-can-be-attended │ │ └── index.js │ ├── maximum-performance-of-a-team │ │ ├── README.md │ │ └── index.js │ ├── maximum-product-of-splitted-binary-tree │ │ └── index.js │ ├── maximum-product-of-three-numbers │ │ └── index.js │ ├── maximum-product-subarray │ │ ├── index.js │ │ └── index.spec.js │ ├── maximum-side-length-of-a-square-with-sum-less-than-or-equal-to-threshold │ │ ├── README.md │ │ └── index.js │ ├── maximum-size-subarray-sum-equals-k │ │ └── index.js │ ├── maximum-students-taking-exam │ │ ├── README.md │ │ ├── index.js │ │ ├── v1.js │ │ ├── v2.js │ │ └── v3.js │ ├── maximum-subarray-sum-with-one-deletion │ │ ├── 1186. Maximum Subarray Sum with One Deletion.pdf │ │ ├── README.md │ │ └── index.js │ ├── maximum-subarray │ │ ├── index.js │ │ └── index.spec.js │ ├── maximum-sum-circular-subarray │ │ ├── 918. Maximum Sum Circular Subarray.pdf │ │ └── index.js │ ├── maximum-sum-of-3-non-overlapping-subarrays │ │ ├── 689. Maximum Sum of 3 Non-Overlapping Subarrays.pdf │ │ ├── README.md │ │ └── index.js │ ├── maximum-sum-of-two-non-overlapping-subarrays │ │ └── index.js │ ├── maximum-swap │ │ ├── README.md │ │ └── index.js │ ├── maximum-vacation-days │ │ ├── README.md │ │ ├── index.js │ │ └── v1.js │ ├── maximum-width-of-binary-tree │ │ └── index.js │ ├── median-of-two-sorted-arrays │ │ ├── IMG_1777.JPG │ │ ├── index.js │ │ └── readme.md │ ├── meeting-rooms-ii │ │ └── index.js │ ├── meeting-rooms │ │ └── index.js │ ├── meeting-scheduler │ │ └── index.js │ ├── merge-intervals │ │ └── index.js │ ├── merge-k-sorted-lists │ │ ├── index.js │ │ └── screencapture-leetcode-submissions-detail-191108256-2018-11-23-01_51_44.png │ ├── merge-sorted-array │ │ └── index.js │ ├── merge-two-binary-trees │ │ └── index.js │ ├── merge-two-sorted-lists │ │ └── index.js │ ├── min-cost-climbing-stairs │ │ └── index.js │ ├── min-stack │ │ └── index.js │ ├── minesweeper │ │ └── index.js │ ├── minimize-malware-spread │ │ ├── 924. Minimize Malware Spread.pdf │ │ └── index.js │ ├── minimize-max-distance-to-gas-station │ │ ├── README.md │ │ └── index.js │ ├── minimum-add-to-make-parentheses-valid │ │ └── index.js │ ├── minimum-area-rectangle │ │ ├── README.md │ │ └── index.js │ ├── minimum-cost-for-tickets │ │ ├── README.md │ │ ├── index.js │ │ └── v1.js │ ├── minimum-cost-to-connect-sticks │ │ ├── index.js │ │ └── priority-queue.js │ ├── minimum-cost-to-make-at-least-one-valid-path-in-a-grid │ │ └── index.js │ ├── minimum-cost-tree-from-leaf-values │ │ └── index.js │ ├── minimum-depth-of-binary-tree │ │ └── index.js │ ├── minimum-domino-rotations-for-equal-row │ │ ├── README.md │ │ └── index.js │ ├── minimum-falling-path-sum │ │ ├── README.md │ │ └── index.js │ ├── minimum-height-trees │ │ ├── README.md │ │ ├── dfs-tls.js │ │ └── index.js │ ├── minimum-insertion-steps-to-make-a-string-palindrome │ │ ├── README.md │ │ └── index.js │ ├── minimum-knight-moves │ │ ├── README.md │ │ └── index.js │ ├── minimum-number-of-arrows-to-burst-balloons │ │ └── index.js │ ├── minimum-number-of-flips-to-convert-binary-matrix-to-zero-matrix │ │ ├── bit.js │ │ └── index.js │ ├── minimum-number-of-refueling-stops │ │ ├── README.md │ │ ├── index.js │ │ └── recursive.js │ ├── minimum-number-of-steps-to-make-two-strings-anagram │ │ └── index.js │ ├── minimum-number-of-taps-to-open-to-water-a-garden │ │ └── index.js │ ├── minimum-path-sum │ │ ├── index.js │ │ └── index.spec.js │ ├── minimum-remove-to-make-valid-parentheses │ │ └── index.js │ ├── minimum-size-subarray-sum │ │ └── index.js │ ├── minimum-swaps-to-make-sequences-increasing │ │ ├── README.md │ │ ├── index.js │ │ ├── space-2.js │ │ └── space-2n.js │ ├── minimum-time-visiting-all-points │ │ └── index.js │ ├── minimum-window-subsequence │ │ ├── 727. Minimum Window Subsequence.pdf │ │ ├── README.md │ │ └── index.js │ ├── minimum-window-substring │ │ ├── README.md │ │ └── index.js │ ├── missing-element-in-sorted-array │ │ ├── README.md │ │ └── index.js │ ├── missing-number-in-arithmetic-progression │ │ └── index.js │ ├── missing-number │ │ └── index.js │ ├── missing-ranges │ │ └── index.js │ ├── monotonic-array │ │ └── index.js │ ├── most-common-word │ │ └── index.js │ ├── most-frequent-subtree-sum │ │ └── index.js │ ├── most-stones-removed-with-same-row-or-column │ │ ├── 947. Most Stones Removed with Same Row or Column.pdf │ │ └── index.js │ ├── move-zeroes │ │ └── index.js │ ├── moving-average-from-data-stream │ │ └── index.js │ ├── multiply-strings │ │ ├── index.js │ │ └── index.spec.js │ ├── my-calendar-i │ │ ├── README.md │ │ └── index.js │ ├── my-calendar-ii │ │ ├── index.js │ │ ├── v2.js │ │ └── wrong-answer.js │ ├── n-queens-ii │ │ └── index.js │ ├── n-queens │ │ ├── N-Queens.pdf │ │ └── index.js │ ├── nested-list-weight-sum-ii │ │ └── index.js │ ├── nested-list-weight-sum │ │ └── index.js │ ├── network-delay-time │ │ └── index.js │ ├── new-21-game │ │ └── index.js │ ├── next-closest-time │ │ └── index.js │ ├── next-greater-element-i │ │ ├── 496. Next Greater Element I.pdf │ │ └── index.js │ ├── next-greater-element-ii │ │ └── index.js │ ├── next-greater-node-in-linked-list │ │ ├── README.md │ │ └── index.js │ ├── next-permutation │ │ ├── Next Permutation.pdf │ │ └── index.js │ ├── non-overlapping-intervals │ │ ├── README.md │ │ └── index.js │ ├── number-of-burgers-with-no-waste-of-ingredients │ │ ├── README.md │ │ └── index.js │ ├── number-of-closed-islands │ │ └── index.js │ ├── number-of-connected-components-in-an-undirected-graph │ │ ├── index.js │ │ └── union-find.js │ ├── number-of-days-between-two-dates │ │ └── index.js │ ├── number-of-distinct-islands-ii │ │ ├── README.md │ │ └── index.js │ ├── number-of-distinct-islands │ │ └── index.js │ ├── number-of-islands-ii │ │ ├── index.js │ │ └── submit.png │ ├── number-of-islands │ │ └── index.js │ ├── number-of-longest-increasing-subsequence │ │ ├── README.md │ │ └── index.js │ ├── number-of-matching-subsequences │ │ └── index.js │ ├── number-of-operations-to-make-network-connected │ │ ├── README.md │ │ └── index.js │ ├── number-of-subarrays-with-bounded-maximum │ │ ├── README.md │ │ └── index.js │ ├── number-of-submatrices-that-sum-to-target │ │ ├── README.md │ │ ├── index.js │ │ └── space-n**2.js │ ├── number-of-valid-subarrays │ │ └── index.js │ ├── number-of-ways-to-stay-in-the-same-place-after-some-steps │ │ ├── README.md │ │ ├── dp-space-n2.js │ │ └── index.js │ ├── odd-even-linked-list │ │ └── index.js │ ├── one-edit-distance │ │ ├── README.md │ │ └── index.js │ ├── online-election │ │ └── index.js │ ├── open-the-lock │ │ ├── README.md │ │ ├── bfs.js │ │ └── index.js │ ├── optimal-account-balancing │ │ ├── README.md │ │ ├── index.js │ │ └── v1.js │ ├── pacific-atlantic-water-flow │ │ └── index.js │ ├── paint-fence │ │ └── index.js │ ├── paint-house-ii │ │ └── index.js │ ├── paint-house │ │ └── index.js │ ├── palindrome-linked-list │ │ ├── README.md │ │ └── index.js │ ├── palindrome-number │ │ ├── 9. Palindrome Number.pdf │ │ └── index.js │ ├── palindrome-pairs │ │ ├── README.md │ │ ├── index.js │ │ └── tle.js │ ├── palindrome-partitioning-ii │ │ └── index.js │ ├── palindrome-partitioning-iii │ │ ├── README.md │ │ └── index.js │ ├── palindrome-partitioning │ │ └── index.js │ ├── palindrome-permutation-ii │ │ └── index.js │ ├── palindrome-permutation │ │ └── index.js │ ├── palindromic-substrings │ │ └── index.js │ ├── pancake-sorting │ │ ├── README.md │ │ └── index.js │ ├── partition-array-into-disjoint-intervals │ │ ├── index.js │ │ └── v1.js │ ├── partition-equal-subset-sum │ │ ├── README.md │ │ ├── dp-v1.js │ │ ├── dp.js │ │ └── index.js │ ├── partition-labels │ │ └── index.js │ ├── partition-list │ │ └── index.js │ ├── partition-to-k-equal-sum-subsets │ │ └── index.js │ ├── pascals-triangle-ii │ │ ├── index.js │ │ └── index.spec.js │ ├── pascals-triangle │ │ ├── index.js │ │ └── index.spec.js │ ├── path-sum-ii │ │ └── index.js │ ├── path-sum-iii │ │ └── index.js │ ├── path-sum-iv │ │ └── index.js │ ├── path-sum │ │ └── index.js │ ├── path-with-maximum-gold │ │ └── index.js │ ├── path-with-maximum-minimum-value │ │ ├── README.md │ │ └── index.js │ ├── peak-index-in-a-mountain-array │ │ └── index.js │ ├── perfect-squares │ │ ├── index.js │ │ └── index.spec.js │ ├── permutation-in-string │ │ └── index.js │ ├── permutation-sequence │ │ └── index.js │ ├── permutations-ii │ │ └── index.js │ ├── permutations │ │ ├── index.js │ │ └── index.spec.js │ ├── plus-one-linked-list │ │ └── idnex.js │ ├── plus-one │ │ └── index.js │ ├── populating-next-right-pointers-in-each-node-ii │ │ ├── 117. Populating Next Right Pointers in Each Node II.pdf │ │ └── index.js │ ├── populating-next-right-pointers-in-each-node │ │ ├── 116. Populating Next Right Pointers in Each Node.pdf │ │ └── index.js │ ├── power-of-two │ │ └── index.js │ ├── powerful-integers │ │ └── index.js │ ├── powx-n │ │ ├── 50. Pow(x, n).pdf │ │ ├── index.js │ │ └── recursive.js │ ├── predict-the-winner │ │ ├── READMD.md │ │ └── index.js │ ├── print-binary-tree │ │ └── index.js │ ├── print-words-vertically │ │ └── index.js │ ├── prison-cells-after-n-days │ │ └── index.js │ ├── product-of-array-except-self │ │ ├── index.js │ │ └── index.spec.js │ ├── product-of-the-last-k-numbers │ │ └── index.js │ ├── queens-that-can-attack-the-king │ │ ├── README.md │ │ └── index.js │ ├── random-pick-index │ │ ├── README.md │ │ ├── index.js │ │ └── reservoir_sampling.png │ ├── random-pick-with-blacklist │ │ └── index.js │ ├── random-pick-with-weight │ │ ├── README.md │ │ └── index.js │ ├── range-sum-of-bst │ │ └── index.js │ ├── range-sum-query-2d-immutable │ │ ├── 304. Range Sum Query 2D - Immutable.pdf │ │ └── index.js │ ├── range-sum-query-2d-mutable │ │ ├── README.md │ │ ├── index.js │ │ └── v1.js │ ├── range-sum-query-immutable │ │ └── index.js │ ├── range-sum-query-mutable │ │ ├── index.js │ │ └── segment-tree.js │ ├── rank-teams-by-votes │ │ └── index.js │ ├── reaching-points │ │ ├── 780. Reaching Points.pdf │ │ └── index.js │ ├── read-n-characters-given-read4-ii-call-multiple-times │ │ └── index.js │ ├── read-n-characters-given-read4 │ │ └── index.js │ ├── rearrange-string-k-distance-apart │ │ ├── index.js │ │ └── index.spec.js │ ├── reconstruct-a-2-row-binary-matrix │ │ └── index.js │ ├── reconstruct-itinerary │ │ ├── 332. Reconstruct Itinerary.pdf │ │ └── index.js │ ├── recover-a-tree-from-preorder-traversal │ │ └── index.js │ ├── recover-binary-search-tree │ │ └── index.js │ ├── rectangle-area-ii │ │ ├── bfs.js │ │ ├── index.js │ │ └── v1.js │ ├── rectangle-area │ │ └── index.js │ ├── rectangle-overlap │ │ └── index.js │ ├── reduce-array-size-to-the-half │ │ └── index.js │ ├── redundant-connection │ │ └── index.js │ ├── regular-expression-matching │ │ ├── 10. Regular Expression Matching.pdf │ │ ├── README.md │ │ ├── RECURSIVE.md │ │ ├── constant-space.js │ │ ├── dp-2d.js │ │ ├── index.js │ │ └── recursive.js │ ├── remove-all-adjacent-duplicates-in-string-ii │ │ └── index.js │ ├── remove-duplicates-from-sorted-array-ii │ │ └── index.js │ ├── remove-duplicates-from-sorted-array │ │ └── index.js │ ├── remove-duplicates-from-sorted-list-ii │ │ └── index.js │ ├── remove-duplicates-from-sorted-list │ │ └── index.js │ ├── remove-element │ │ └── index.js │ ├── remove-interval │ │ └── index.js │ ├── remove-invalid-parentheses │ │ ├── README.md │ │ ├── bfs.js │ │ └── index.js │ ├── remove-linked-list-elements │ │ ├── index.js │ │ ├── recursive.js │ │ └── screencapture-leetcode-submissions-detail-192938904-2018-12-02-23_17_08.png │ ├── remove-nth-node-from-end-of-list │ │ └── index.js │ ├── remove-outermost-parentheses │ │ └── index.js │ ├── remove-sub-folders-from-the-filesystem │ │ └── index.js │ ├── reorder-data-in-log-files │ │ └── index.js │ ├── reorder-list │ │ └── index.js │ ├── reorganize-string │ │ └── index.js │ ├── repeated-substring-pattern │ │ └── index.js │ ├── replace-words │ │ └── index.js │ ├── restore-ip-addresses │ │ ├── 93. Restore IP Addresses.pdf │ │ └── index.js │ ├── reverse-integer │ │ └── index.js │ ├── reverse-linked-list-ii │ │ ├── README.md │ │ ├── index.js │ │ ├── submission-screenshot.png │ │ └── v2.js │ ├── reverse-linked-list │ │ ├── iterative.js │ │ └── recursive.js │ ├── reverse-nodes-in-k-group │ │ ├── index.js │ │ └── screencapture-leetcode-submissions-detail-192938162-2018-12-02-23_09_39.png │ ├── reverse-only-letters │ │ └── index.js │ ├── reverse-string │ │ └── index.js │ ├── reverse-substrings-between-each-pair-of-parentheses │ │ └── index.js │ ├── reverse-vowels-of-a-string │ │ └── index.js │ ├── reverse-words-in-a-string-ii │ │ └── index.js │ ├── reverse-words-in-a-string-iii │ │ └── index.js │ ├── reverse-words-in-a-string │ │ └── index.js │ ├── robot-room-cleaner │ │ ├── 489. Robot Room Cleaner.pdf │ │ └── index.js │ ├── roman-to-integer │ │ └── index.js │ ├── rotate-array │ │ └── index.js │ ├── rotate-image │ │ └── index.js │ ├── rotate-list │ │ ├── 61. Rotate List.pdf │ │ └── index.js │ ├── rotated-digits │ │ └── index.js │ ├── rotting-oranges │ │ └── index.js │ ├── russian-doll-envelopes │ │ ├── README.md │ │ └── index.js │ ├── scramble-string │ │ └── index.js │ ├── search-a-2d-matrix-ii │ │ ├── 240. Search a 2D Matrix II.pdf │ │ └── index.js │ ├── search-a-2d-matrix │ │ └── index.js │ ├── search-in-rotated-sorted-array-ii │ │ ├── 81. Search in Rotated Sorted Array II.pdf │ │ ├── README.md │ │ └── index.js │ ├── search-in-rotated-sorted-array │ │ ├── 33. Search in Rotated Sorted Array.pdf │ │ ├── README.md │ │ └── index.js │ ├── search-insert-position │ │ └── index.js │ ├── search-suggestions-system │ │ └── index.js │ ├── second-minimum-node-in-a-binary-tree │ │ └── index.js │ ├── sentence-similarity-ii │ │ └── index.js │ ├── sentence-similarity │ │ └── index.js │ ├── sequence-reconstruction │ │ ├── README.md │ │ └── index.js │ ├── sequential-digits │ │ ├── README.md │ │ └── index.js │ ├── serialize-and-deserialize-binary-tree │ │ ├── bfs.js │ │ ├── dfs.js │ │ └── index.js │ ├── serialize-and-deserialize-bst │ │ ├── README.md │ │ └── index.js │ ├── serialize-and-deserialize-n-ary-tree │ │ └── index.js │ ├── set-matrix-zeroes │ │ ├── 73. Set Matrix Zeroes.pdf │ │ └── index.js │ ├── shortest-distance-from-all-buildings │ │ ├── index.js │ │ └── v1.js │ ├── shortest-distance-to-a-character │ │ └── index.js │ ├── shortest-palindrome │ │ ├── README.md │ │ └── index.js │ ├── shortest-path-in-a-grid-with-obstacles-elimination │ │ └── index.js │ ├── shortest-path-in-binary-matrix │ │ ├── index.js │ │ └── v1.js │ ├── shortest-path-to-get-all-keys │ │ ├── README.md │ │ └── index.js │ ├── shortest-path-visiting-all-nodes │ │ ├── README.md │ │ ├── index.js │ │ └── tle.js │ ├── shortest-subarray-with-sum-at-least-k │ │ ├── README.md │ │ ├── algo.jpg │ │ └── index.js │ ├── shortest-way-to-form-string │ │ ├── README.md │ │ ├── binary-search.js │ │ ├── brute-force.js │ │ └── inedx.js │ ├── shortest-word-distance-ii │ │ └── index.js │ ├── shortest-word-distance │ │ └── index.js │ ├── simplify-path │ │ ├── 71. Simplify Path.pdf │ │ └── index.js │ ├── single-element-in-a-sorted-array │ │ ├── README.md │ │ ├── index.js │ │ └── submit.png │ ├── single-number-ii │ │ └── index.js │ ├── single-number-iii │ │ ├── 260. Single Number III.pdf │ │ └── index.js │ ├── single-number │ │ └── index.js │ ├── sliding-puzzle │ │ ├── README.md │ │ └── index.js │ ├── sliding-window-maximum │ │ └── index.js │ ├── sliding-window-median │ │ └── index.js │ ├── smallest-common-region │ │ ├── 1257. Smallest Common Region.pdf │ │ ├── README.md │ │ ├── index.js │ │ └── v1.js │ ├── smallest-range-covering-elements-from-k-lists │ │ ├── README.md │ │ ├── index.js │ │ └── iterator-priority-queue-and-sliding-window.js │ ├── smallest-range-i │ │ ├── index.js │ │ └── index.spec.js │ ├── smallest-range │ │ ├── index.js │ │ └── sliding-window.js │ ├── smallest-string-with-swaps │ │ ├── README.md │ │ └── index.js │ ├── smallest-subtree-with-all-the-deepest-nodes │ │ └── index.js │ ├── snapshot-array │ │ ├── README.md │ │ └── index.js │ ├── sort-array-by-parity-ii │ │ └── index.js │ ├── sort-array-by-parity │ │ └── index.js │ ├── sort-characters-by-frequency │ │ └── index.js │ ├── sort-colors │ │ └── index.js │ ├── sort-items-by-groups-respecting-dependencies │ │ └── index.js │ ├── sort-list │ │ └── index.js │ ├── sparse-matrix-multiplication │ │ └── index.js │ ├── spiral-matrix-ii │ │ └── index.js │ ├── spiral-matrix-iii │ │ └── index.js │ ├── spiral-matrix │ │ ├── 54. Spiral Matrix.pdf │ │ └── index.js │ ├── split-array-into-consecutive-subsequences │ │ ├── README.md │ │ └── index.js │ ├── split-array-into-fibonacci-sequence │ │ └── index.js │ ├── split-array-largest-sum │ │ ├── README.md │ │ ├── dp-space-n.js │ │ ├── dp.js │ │ └── index.js │ ├── split-array-with-equal-sum │ │ ├── README.md │ │ ├── dfs-lte.js │ │ └── index.js │ ├── split-array-with-same-average │ │ ├── README.md │ │ ├── dfs.js │ │ ├── index.js │ │ └── n**2.js │ ├── split-bst │ │ └── index.js │ ├── sqrtx │ │ ├── index.js │ │ └── index.spec.js │ ├── squares-of-a-sorted-array │ │ └── index.js │ ├── statistics-from-a-large-sample │ │ └── index.js │ ├── stepping-numbers │ │ └── index.js │ ├── stickers-to-spell-word │ │ ├── index.js │ │ └── submit.png │ ├── stream-of-characters │ │ ├── README.md │ │ └── index.js │ ├── string-to-integer-atoi │ │ └── index.js │ ├── string-transforms-into-another-string │ │ ├── README.md │ │ └── index.js │ ├── strobogrammatic-number-ii │ │ ├── index.js │ │ └── index.mle.js │ ├── strobogrammatic-number-iii │ │ └── index.js │ ├── strobogrammatic-number │ │ └── index.js │ ├── student-attendance-record-i │ │ └── index.js │ ├── student-attendance-record-ii │ │ ├── README.md │ │ ├── dfs.js │ │ ├── dp-n**2.js │ │ └── index.js │ ├── subarray-product-less-than-k │ │ ├── README.md │ │ └── index.js │ ├── subarray-sum-equals-k │ │ └── index.js │ ├── subarray-sums-divisible-by-k │ │ ├── README.md │ │ └── index.js │ ├── subarrays-with-k-different-integers │ │ └── index.js │ ├── subdomain-visit-count │ │ └── index.js │ ├── subsets-ii │ │ └── index.js │ ├── subsets │ │ └── index.js │ ├── substring-with-concatenation-of-all-words │ │ ├── index.js │ │ └── tle.js │ ├── subtract-the-product-and-sum-of-digits-of-an-integer │ │ └── index.js │ ├── subtree-of-another-tree │ │ └── index.js │ ├── sudoku-solver │ │ └── index.js │ ├── sum-of-distances-in-tree │ │ ├── 834. Sum of Distances in Tree.pdf │ │ └── index.js │ ├── sum-of-left-leaves │ │ └── index.js │ ├── sum-of-subarray-minimums │ │ └── index.js │ ├── sum-root-to-leaf-numbers │ │ └── index.js │ ├── summary-ranges │ │ └── index.js │ ├── surrounded-regions │ │ └── index.js │ ├── swap-nodes-in-pairs │ │ └── index.js │ ├── swim-in-rising-water │ │ ├── README.md │ │ └── index.js │ ├── symmetric-tree │ │ └── index.js │ ├── tag-validator │ │ └── index.js │ ├── target-sum │ │ ├── index.js │ │ ├── recursive.js │ │ └── v1.js │ ├── task-scheduler │ │ └── index.js │ ├── text-justification │ │ └── index.js │ ├── the-k-weakest-rows-in-a-matrix │ │ └── index.js │ ├── the-maze-ii │ │ └── index.js │ ├── the-maze-iii │ │ ├── index.js │ │ └── submit.png │ ├── the-maze │ │ └── index.js │ ├── the-skyline-problem │ │ ├── index.js │ │ └── readme.md │ ├── third-maximum-number │ │ └── index.js │ ├── tiling-a-rectangle-with-the-fewest-squares │ │ ├── README.md │ │ └── index.js │ ├── time-based-key-value-store │ │ └── index.js │ ├── toeplitz-matrix │ │ └── index.js │ ├── top-k-frequent-elements │ │ ├── index.js │ │ └── index.spec.js │ ├── top-k-frequent-words │ │ ├── README.md │ │ ├── index.js │ │ └── quick-select.js │ ├── toss-strange-coins │ │ ├── README.md │ │ ├── index.js │ │ └── space-n**2.js │ ├── total-hamming-distance │ │ ├── 477. Total Hamming Distance.pdf │ │ └── index.js │ ├── trapping-rain-water-ii │ │ ├── index.js │ │ └── index.wrong-answer.js │ ├── trapping-rain-water │ │ ├── dp.js │ │ └── index.js │ ├── tree-diameter │ │ ├── README.md │ │ └── index.js │ ├── triangle │ │ └── index.js │ ├── tweet-counts-per-frequency │ │ ├── README.md │ │ └── index.js │ ├── two-sum-bsts │ │ └── index.js │ ├── two-sum-ii-input-array-is-sorted │ │ ├── index.js │ │ └── index.spec.js │ ├── two-sum-iii-data-structure-design │ │ └── index.js │ ├── two-sum-iv-input-is-a-bst │ │ └── index.js │ ├── two-sum-less-than-k │ │ └── index.js │ ├── two-sum │ │ ├── index.js │ │ └── index.spec.js │ ├── ugly-number-ii │ │ └── index.js │ ├── ugly-number │ │ └── index.js │ ├── unique-binary-search-trees-ii │ │ └── index.js │ ├── unique-binary-search-trees │ │ └── index.js │ ├── unique-email-addresses │ │ └── index.js │ ├── unique-morse-code-words │ │ └── index.js │ ├── unique-number-of-occurrences │ │ └── index.js │ ├── unique-paths-ii │ │ └── index.js │ ├── unique-paths-iii │ │ └── index.js │ ├── unique-paths │ │ └── index.js │ ├── utf-8-validation │ │ └── index.js │ ├── valid-anagram │ │ └── index.js │ ├── valid-mountain-array │ │ └── index.js │ ├── valid-number │ │ └── index.js │ ├── valid-palindrome-ii │ │ └── index.js │ ├── valid-palindrome-iii │ │ └── index.js │ ├── valid-palindrome │ │ └── index.js │ ├── valid-parentheses │ │ ├── index.js │ │ └── index.spec.js │ ├── valid-parenthesis-string │ │ ├── README.md │ │ └── index.js │ ├── valid-square │ │ └── index.js │ ├── valid-sudoku │ │ ├── 36. Valid Sudoku.pdf │ │ └── index.js │ ├── valid-tic-tac-toe-state │ │ └── index.js │ ├── valid-word-abbreviation │ │ └── index.js │ ├── validate-binary-search-tree │ │ ├── index.js │ │ └── recursive.js │ ├── validate-binary-tree-nodes │ │ └── index.js │ ├── validate-ip-address │ │ ├── Validate IP address.pdf │ │ └── index.js │ ├── verify-preorder-sequence-in-binary-search-tree │ │ └── index.js │ ├── verifying-an-alien-dictionary │ │ ├── README.md │ │ └── index.js │ ├── vertical-order-traversal-of-a-binary-tree │ │ └── index.js │ ├── video-stitching │ │ ├── README.md │ │ └── index.js │ ├── walls-and-gates │ │ └── index.js │ ├── water-and-jug-problem │ │ └── index.js │ ├── wildcard-matching │ │ ├── README.md │ │ ├── dp.js │ │ ├── index.js │ │ └── screenshot.png │ ├── word-break-ii │ │ ├── README.md │ │ ├── index.js │ │ └── index.spec.js │ ├── word-break │ │ ├── README.md │ │ ├── index.js │ │ ├── index.spec.js │ │ └── screencapture-leetcode-submissions-detail-179481115-2018-09-30-19_28_02.png │ ├── word-ladder-ii │ │ └── index.js │ ├── word-ladder │ │ └── index.js │ ├── word-pattern-ii │ │ └── index.js │ ├── word-pattern │ │ └── index.js │ ├── word-search-ii │ │ └── index.js │ ├── word-search │ │ ├── dfs-extra-spaces.js │ │ └── index.js │ ├── xor-queries-of-a-subarray │ │ └── index.js │ └── zigzag-conversion │ │ ├── ZigZag Conversion2.pdf │ │ └── index.js ├── notes │ ├── README.md │ └── assets │ │ ├── boxmodel.gif │ │ ├── constructor-proto-chain.png │ │ ├── event-propagation.svg │ │ ├── lower-bound-upper-bound.png │ │ └── speed-metrics.png ├── practices │ ├── 2018-11-24 │ │ └── quick-sort │ │ │ ├── index.js │ │ │ └── index.spec.js │ ├── 2018-12-03 │ │ └── priority-queue │ │ │ ├── index.js │ │ │ └── index.spec.js │ ├── 2019-03-25 │ │ └── bst │ │ │ ├── index.js │ │ │ └── index.spec.js │ ├── 2019-06-18 │ │ └── quick-sort │ │ │ ├── index.js │ │ │ └── index.spec.js │ ├── 2019-08-05 │ │ ├── merge-sort │ │ │ └── index.js │ │ └── quick-sort │ │ │ └── index.js │ ├── 2019-11-06 │ │ └── bst │ │ │ └── index.js │ ├── Uber-or-Phone-Screen-or-Wildcard-Pattern-Matching │ │ ├── README.md │ │ └── index.js │ ├── add-hexadecimal │ │ ├── index.js │ │ └── index.spec.js │ ├── all-possible-full-binary-trees-with-n-leaves │ │ ├── README.md │ │ └── index.js │ ├── count-integer-partitions │ │ ├── README.md │ │ ├── index.js │ │ └── slow.js │ ├── count-number-of-squares-in-the-matrix │ │ ├── README.md │ │ ├── index.js │ │ └── index.spec.js │ ├── deep-filter │ │ ├── index.js │ │ └── index.spec.js │ ├── design-spreadsheet-with-adjustable-height-and-find-row │ │ ├── index.js │ │ └── index.spec.js │ ├── exclude-items │ │ ├── exclude items.pdf │ │ ├── index.js │ │ └── index.spec.js │ ├── get-dot-product │ │ ├── index.js │ │ └── index.spec.js │ ├── loading-bar │ │ ├── README.md │ │ ├── index.css │ │ ├── index.html │ │ ├── index.js │ │ └── screenshot.gif │ ├── movies-on-flight │ │ └── index.js │ ├── number-of-ways-staying-at-zero │ │ ├── Number of ways staying at zero.pdf │ │ ├── index.js │ │ └── index.spec.js │ ├── optimal-utilization │ │ ├── README.md │ │ └── index.js │ ├── overlapped-intervals │ │ ├── README.md │ │ ├── index.js │ │ └── index.spec.js │ ├── permutation-no-3-consecutive-same-color │ │ ├── index.js │ │ └── index.spec.js │ ├── range │ │ ├── index.js │ │ └── index.spec.js │ ├── react-timer │ │ └── index.js │ ├── render-template │ │ ├── index.js │ │ └── index.spec.js │ ├── sort-a-with-b │ │ └── index.js │ ├── top-n-buzzwords │ │ └── index.js │ └── zombies-in-matrix │ │ └── index.js ├── system-design │ └── rate-limiter.md └── utilities │ ├── bind │ ├── es5.js │ ├── es5.spec.js │ ├── es6.js │ ├── es6.spec.js │ ├── index.js │ └── index.spec.js │ ├── curried-5-sum │ ├── index.js │ └── index.spec.js │ ├── curry │ ├── index.js │ └── index.spec.js │ ├── curryN │ ├── index.js │ └── index.spec.js │ ├── debounce │ ├── index.js │ └── index.spec.js │ ├── event-emitter │ ├── index.js │ └── index.spec.js │ ├── promisify │ ├── index.js │ └── index.spec.js │ ├── pubsub │ ├── index.js │ └── index.spec.js │ ├── rate-limiter │ ├── index.js │ └── index.spec.js │ ├── reorder-array-with-given-order │ ├── index.js │ └── index.spec.js │ ├── runner │ ├── index.js │ └── index.spec.js │ ├── task-queue │ ├── es6.js │ ├── es6.spec.js │ ├── index.js │ └── index.spec.js │ ├── the-promise │ ├── index.js │ └── index.spec.js │ └── throttle │ ├── index.js │ └── index.spec.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"], 3 | "plugins": ["@babel/plugin-proposal-object-rest-spread", "@babel/transform-runtime"] 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .env 3 | lib/ 4 | *.dat 5 | logs/ 6 | ignored-scripts/ 7 | tmp/ 8 | dist/ 9 | .next/ 10 | out/ 11 | .vscode 12 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .env 3 | src/ 4 | 5 | examples 6 | scripts 7 | docs 8 | .babelrc 9 | .eslint* 10 | .idea 11 | .editorconfig 12 | .npmignore 13 | .nyc_output 14 | .travis.yml 15 | webpack.* 16 | coverage 17 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "semi": true, 4 | "singleQuote": true, 5 | "trailingComma": "all", 6 | "bracketSpacing": true, 7 | "arrowParens": "always" 8 | } 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Algorithms 2 | 3 | A study notes and solutions to algorithms using javascript. 4 | 5 | 👉 [Javascript Solutions](src/leetcode/) 6 | 7 | 8 | -------------------------------------------------------------------------------- /cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/cover.jpg -------------------------------------------------------------------------------- /src/algo/bfs/level-order-traversal.js: -------------------------------------------------------------------------------- 1 | function bfs(root) { 2 | let queue = [root]; 3 | while (queue.length) { 4 | const next = []; 5 | while (queue.length) { 6 | // add next level nodes to next queue 7 | } 8 | queue = next; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/algo/binary-search/v1/binary-search.js: -------------------------------------------------------------------------------- 1 | const fn = (arr, target) => { 2 | let left = 0; 3 | let right = arr.length; 4 | while (left < right) { 5 | const mid = Math.floor((left + right) / 2); 6 | if (target === arr[mid]) { 7 | return mid; 8 | } else if (target > arr[mid]) { 9 | left = mid + 1; 10 | } else { 11 | right = mid; 12 | } 13 | } 14 | return -1; 15 | }; 16 | 17 | export default fn; 18 | -------------------------------------------------------------------------------- /src/algo/binary-search/v1/binary-search.spec.js: -------------------------------------------------------------------------------- 1 | import binarySearch from './binary-search'; 2 | 3 | test('binarySearch', () => { 4 | expect(binarySearch([1, 2, 3, 4, 5], 3)).toEqual(2); 5 | expect(binarySearch([1, 2, 3, 4, 5], 2)).toEqual(1); 6 | expect(binarySearch([1, 2, 3, 4, 5], 1)).toEqual(0); 7 | expect(binarySearch([1, 2, 3, 4, 5], 5)).toEqual(4); 8 | expect(binarySearch([1, 2, 3, 4, 5], 13)).toEqual(-1); 9 | expect(binarySearch([], 3)).toEqual(-1); 10 | }); 11 | -------------------------------------------------------------------------------- /src/algo/binary-search/v1/ceil.js: -------------------------------------------------------------------------------- 1 | function lowerBound(arr, target) { 2 | let left = 0; 3 | let right = arr.length; 4 | while (left < right) { 5 | const mid = Math.floor((left + right) / 2); 6 | if (target > arr[mid]) { 7 | left = mid + 1; 8 | } else { 9 | right = mid; 10 | } 11 | } 12 | return left; 13 | } 14 | 15 | function ceil(arr, target) { 16 | return lowerBound(arr, target); 17 | } 18 | 19 | export default ceil; 20 | -------------------------------------------------------------------------------- /src/algo/binary-search/v1/ceil.spec.js: -------------------------------------------------------------------------------- 1 | import ceil from './ceil'; 2 | 3 | test('ceil', () => { 4 | expect(ceil([1, 3, 4, 6, 7, 8, 9], 5)).toEqual(3); 5 | expect(ceil([1, 3, 4, 6, 7, 8, 9], 4)).toEqual(2); 6 | }); 7 | -------------------------------------------------------------------------------- /src/algo/binary-search/v1/docs/lower-bound-upper-bound.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/algo/binary-search/v1/docs/lower-bound-upper-bound.png -------------------------------------------------------------------------------- /src/algo/binary-search/v1/floor.js: -------------------------------------------------------------------------------- 1 | function lowerBound(arr, target) { 2 | let left = 0; 3 | let right = arr.length; 4 | while (left < right) { 5 | const mid = Math.floor((left + right) / 2); 6 | if (target > arr[mid]) { 7 | left = mid + 1; 8 | } else { 9 | right = mid; 10 | } 11 | } 12 | return left; 13 | } 14 | 15 | function floor(arr, target) { 16 | const index = lowerBound(arr, target); 17 | return arr[index] === target ? index : index - 1; 18 | } 19 | 20 | export default floor; 21 | -------------------------------------------------------------------------------- /src/algo/binary-search/v1/floor.spec.js: -------------------------------------------------------------------------------- 1 | import floor from './floor'; 2 | 3 | test('floor', () => { 4 | expect(floor([1, 3, 4, 6, 7, 8, 9], 5)).toEqual(2); 5 | expect(floor([1, 3, 4, 6, 7, 8, 9], 2)).toEqual(0); 6 | expect(floor([1, 3, 4, 6, 7, 8, 9], 3)).toEqual(1); 7 | }); 8 | -------------------------------------------------------------------------------- /src/algo/binary-search/v1/lower-bound.js: -------------------------------------------------------------------------------- 1 | const fn = (arr, target) => { 2 | let left = 0; 3 | let right = arr.length; 4 | while (left < right) { 5 | const mid = Math.floor((left + right) / 2); 6 | if (target > arr[mid]) { 7 | left = mid + 1; 8 | } else { 9 | right = mid; 10 | } 11 | } 12 | return left; 13 | }; 14 | 15 | export default fn; 16 | -------------------------------------------------------------------------------- /src/algo/binary-search/v1/lower-bound.spec.js: -------------------------------------------------------------------------------- 1 | import lowerBound from './lower-bound'; 2 | 3 | test('lowerBound', () => { 4 | expect(lowerBound([1, 3, 5, 7, 9], 3)).toEqual(1); 5 | expect(lowerBound([1, 3, 5, 7, 9], 4)).toEqual(2); 6 | expect(lowerBound([], 4)).toEqual(0); 7 | }); 8 | -------------------------------------------------------------------------------- /src/algo/binary-search/v1/upper-bound.js: -------------------------------------------------------------------------------- 1 | const fn = (arr, target) => { 2 | let left = 0; 3 | let right = arr.length; 4 | while (left < right) { 5 | const mid = Math.floor((left + right) / 2); 6 | if (target >= arr[mid]) { 7 | left = mid + 1; 8 | } else { 9 | right = mid; 10 | } 11 | } 12 | return left; 13 | }; 14 | 15 | export default fn; 16 | -------------------------------------------------------------------------------- /src/algo/binary-search/v1/upper-bound.spec.js: -------------------------------------------------------------------------------- 1 | import upperBound from './upper-bound'; 2 | 3 | test('upperBound', () => { 4 | expect(upperBound([1, 3, 5, 7, 9], 3)).toEqual(2); 5 | expect(upperBound([1, 3, 5, 7, 9], 4)).toEqual(2); 6 | expect(upperBound([], 4)).toEqual(0); 7 | }); 8 | -------------------------------------------------------------------------------- /src/algo/gcd/index.js: -------------------------------------------------------------------------------- 1 | function gcd(a, b) { 2 | if (b === 0) { 3 | return a; 4 | } 5 | return gcd(b, a % b); 6 | } 7 | 8 | export default gcd; 9 | -------------------------------------------------------------------------------- /src/algo/graph/articulation-point/articulation-point.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/algo/graph/articulation-point/articulation-point.pdf -------------------------------------------------------------------------------- /src/algo/merge-sort/index.spec.js: -------------------------------------------------------------------------------- 1 | import sort from './index'; 2 | 3 | test('sort', () => { 4 | const data = [1, 3, 6, 6, 2, 5, 8, 0, 5]; 5 | const result = sort(data); 6 | const expectedResult = [0, 1, 2, 3, 5, 5, 6, 6, 8]; 7 | expect(result).toEqual(expectedResult); 8 | }); 9 | 10 | test('sort', () => { 11 | expect(sort([0])).toEqual([0]); 12 | expect(sort([1, 6, 3])).toEqual([1, 3, 6]); 13 | expect(sort([1, 6, 3, 4])).toEqual([1, 3, 4, 6]); 14 | expect(sort([1, 6, 0, 3])).toEqual([0, 1, 3, 6]); 15 | }); 16 | -------------------------------------------------------------------------------- /src/algo/numbers/to-binary.js: -------------------------------------------------------------------------------- 1 | const toBinary = (num, nBits = 32) => { 2 | let output = ''; 3 | for (let i = 0; i < nBits; i++) { 4 | output = ((num >> i) & 1) + output; 5 | } 6 | return output; 7 | }; 8 | 9 | export default toBinary; 10 | -------------------------------------------------------------------------------- /src/algo/numbers/to-binary.spec.js: -------------------------------------------------------------------------------- 1 | import toBinary from './to-binary'; 2 | 3 | test('to-binary', () => { 4 | expect(toBinary(7, 8)).toEqual('00000111'); 5 | expect(toBinary(-1, 8)).toEqual('11111111'); 6 | expect(toBinary(-7, 8)).toEqual('11111001'); 7 | }); 8 | -------------------------------------------------------------------------------- /src/algo/numbers/to-hex.js: -------------------------------------------------------------------------------- 1 | const fn = (num, nBits = 32) => { 2 | let output = ''; 3 | for (let i = 0; i < nBits / 4; i++) { 4 | output = ((num >> (i * 4)) & 15).toString(16) + output; 5 | } 6 | return '0x' + trimZero(output); 7 | }; 8 | 9 | function trimZero(str) { 10 | let i = 0; 11 | while (str[i] === '0') { 12 | i += 1; 13 | } 14 | return i < str.length ? str.substring(i) : '0'; 15 | } 16 | 17 | export default fn; 18 | -------------------------------------------------------------------------------- /src/algo/numbers/to-hex.spec.js: -------------------------------------------------------------------------------- 1 | import toHex from './to-hex'; 2 | 3 | test('to-hex', () => { 4 | expect(toHex(10)).toEqual('0xa'); 5 | expect(toHex(123)).toEqual('0x7b'); 6 | expect(toHex(456)).toEqual('0x1c8'); 7 | expect(toHex(0)).toEqual('0x0'); 8 | }); 9 | -------------------------------------------------------------------------------- /src/algo/quick-select/index.spec.js: -------------------------------------------------------------------------------- 1 | import quickSelect from './index'; 2 | 3 | test('quickSelect', () => { 4 | const arr = [3, 5, 9, 10, 100, 50, 6, 5]; 5 | expect(quickSelect(arr, 4)).toEqual([3, 5, 5, 6]); 6 | }); 7 | -------------------------------------------------------------------------------- /src/algo/quick-sort/index.spec.js: -------------------------------------------------------------------------------- 1 | import quicksort from './index'; 2 | 3 | test('quicksort', () => { 4 | const arr = [1, 3, 4, 2]; 5 | const result = quicksort(arr); 6 | expect(result).toEqual([1, 2, 3, 4]); 7 | }); 8 | 9 | test('quicksort', () => { 10 | const arr = [1, 3, 4, 2, 5, 9, 7, 5, 8]; 11 | const result = quicksort(arr); 12 | expect(result).toEqual([1, 2, 3, 4, 5, 5, 7, 8, 9]); 13 | }); 14 | -------------------------------------------------------------------------------- /src/algo/topological-sort/index.spec.js: -------------------------------------------------------------------------------- 1 | import sort from './index'; 2 | 3 | test('topological-sort', () => { 4 | const graph = [[], [], [3], [1], [0, 1], [0, 2]]; 5 | console.log(sort(graph)); 6 | }); 7 | 8 | test('topological-sort', () => { 9 | const graph = [[1], [], [1]]; 10 | console.log(sort(graph)); 11 | }); 12 | 13 | test('topological-sort', () => { 14 | const graph = [[1], [0]]; 15 | console.log(sort(graph)); 16 | }); 17 | -------------------------------------------------------------------------------- /src/data-structure/binary-indexed-tree/Binary Indexed Tree.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/data-structure/binary-indexed-tree/Binary Indexed Tree.pdf -------------------------------------------------------------------------------- /src/data-structure/binary-indexed-tree/README.md: -------------------------------------------------------------------------------- 1 | # Binary Indexed Tree 2 | 3 | ## References 4 | 5 | - (https://blog.csdn.net/Yaokai_AssultMaster/article/details/79492190)[https://blog.csdn.net/Yaokai_AssultMaster/article/details/79492190] 6 | - (https://www.geeksforgeeks.org/binary-indexed-tree-or-fenwick-tree-2/)[https://www.geeksforgeeks.org/binary-indexed-tree-or-fenwick-tree-2/] 7 | -------------------------------------------------------------------------------- /src/data-structure/binary-indexed-tree/index.spec.js: -------------------------------------------------------------------------------- 1 | import BinaryIndexedTree from './index'; 2 | 3 | test('BinaryIndexedTree', () => { 4 | const arr = [2, 1, 1, 3, 2, 3, 4, 5, 6, 7, 8, 9]; 5 | const bit = new BinaryIndexedTree(arr); 6 | expect(bit.getSum(6)).toEqual(arr.slice(0, 6 + 1).reduce((acc, cur) => acc + cur, 0)); 7 | expect(bit.getSum(3)).toEqual(arr.slice(0, 3 + 1).reduce((acc, cur) => acc + cur, 0)); 8 | expect(bit.getSum(9)).toEqual(arr.slice(0, 9 + 1).reduce((acc, cur) => acc + cur, 0)); 9 | }); 10 | -------------------------------------------------------------------------------- /src/data-structure/bst/index.spec.js: -------------------------------------------------------------------------------- 1 | import createBST, { insert, inOrder } from './index'; 2 | 3 | test('bst', () => { 4 | const data = [3, 2, 1, 3, 4, 5, 6]; 5 | const bst = createBST(); 6 | const result = data.reduce((acc, i) => bst.insert(i), bst).inOrder(); 7 | expect(result).toEqual([1, 2, 3, 3, 4, 5, 6]); 8 | const result2 = bst 9 | .remove(1) 10 | .remove(2) 11 | .remove(3) 12 | .remove(3) 13 | .inOrder(); 14 | expect(result2).toEqual([4, 5, 6]); 15 | }); 16 | -------------------------------------------------------------------------------- /src/data-structure/priority-queue/v1/__tests__/index.js: -------------------------------------------------------------------------------- 1 | import PriorityQueue from '../index'; 2 | 3 | test('PriorityQueue', () => { 4 | const queue = new PriorityQueue(); 5 | queue 6 | .enqueue(2, 2) 7 | .enqueue(1, 1) 8 | .enqueue(3, 3) 9 | .enqueue(4, 4) 10 | .enqueue(0, 0); 11 | expect([...queue]).toEqual([0, 1, 2, 3, 4]); 12 | }); 13 | -------------------------------------------------------------------------------- /src/data-structure/priority-queue/v1/bubbleDown.js: -------------------------------------------------------------------------------- 1 | import swap from './swap'; 2 | 3 | const fn = (arr, i, comparator) => { 4 | const left = 2 * i + 1; 5 | const right = 2 * i + 2; 6 | const isValid = 7 | (left >= arr.length || comparator(arr[i], arr[left]) <= 0) && 8 | (right >= arr.length || comparator(arr[i], arr[right]) <= 0); 9 | if (!isValid) { 10 | const next = right >= arr.length || comparator(arr[left], arr[right]) <= 0 ? left : right; 11 | swap(arr, i, next); 12 | fn(arr, next, comparator); 13 | } 14 | }; 15 | 16 | export default fn; 17 | -------------------------------------------------------------------------------- /src/data-structure/priority-queue/v1/bubbleUp.js: -------------------------------------------------------------------------------- 1 | import swap from './swap'; 2 | 3 | const fn = (arr, i, comparator) => { 4 | if (i <= 0) { 5 | return; 6 | } 7 | const p = Math.floor((i - 1) / 2); 8 | const isValid = comparator(arr[p], arr[i]) <= 0; 9 | if (!isValid) { 10 | swap(arr, i, p); 11 | fn(arr, p, comparator); 12 | } 13 | }; 14 | 15 | export default fn; 16 | -------------------------------------------------------------------------------- /src/data-structure/priority-queue/v1/defaultComparator.js: -------------------------------------------------------------------------------- 1 | const fn = (a, b) => a.priority - b.priority; 2 | 3 | export default fn; 4 | -------------------------------------------------------------------------------- /src/data-structure/priority-queue/v1/swap.js: -------------------------------------------------------------------------------- 1 | const fn = (arr, i, j) => { 2 | const tmp = arr[i]; 3 | arr[i] = arr[j]; 4 | arr[j] = tmp; 5 | }; 6 | 7 | export default fn; 8 | -------------------------------------------------------------------------------- /src/data-structure/priority-queue/v3/index.spec.js: -------------------------------------------------------------------------------- 1 | import PriorityQueue from './index'; 2 | 3 | test('PriorityQueue', () => { 4 | const pq = new PriorityQueue({ 5 | comparator: (a, b) => a <= b, 6 | isEqual: (a, b) => a === b, 7 | }); 8 | const data = [16, 49, 62, 58, 14, 72458777923, 3, 4, 1, 2]; 9 | data.forEach((el) => pq.enqueue(el)); 10 | const result = []; 11 | while (pq.length) { 12 | result.push(pq.dequeue()); 13 | } 14 | const expectedResult = [1, 2, 3, 4, 14, 16, 49, 58, 62, 72458777923]; 15 | expect(result).toEqual(expectedResult); 16 | }); 17 | -------------------------------------------------------------------------------- /src/data-structure/sorted-map/index.spec.js: -------------------------------------------------------------------------------- 1 | import SortedMap from './index'; 2 | 3 | test('SortedMap', () => { 4 | const map = new SortedMap(); 5 | expect(map.get('k1')).toEqual(null); 6 | map.set('k1', 'v1'); 7 | expect(map.get('k1')).toEqual('v1'); 8 | map.set('k3', 'v3'); 9 | map.set('k2', 'v2'); 10 | expect(map.keys()).toEqual(['k1', 'k2', 'k3']); 11 | }); 12 | -------------------------------------------------------------------------------- /src/data-structure/trie/index.spec.js: -------------------------------------------------------------------------------- 1 | import Trie from './index'; 2 | 3 | test('Trie', () => { 4 | const trie = new Trie(); 5 | const data = ['app', 'apple', 'applepen']; 6 | data.map((word) => trie.add(word)); 7 | expect(trie.dfs()).toEqual(data); 8 | expect(trie.startsWith('app')).toEqual(true); 9 | expect(trie.startsWith('appl')).toEqual(true); 10 | expect(trie.startsWith('apple')).toEqual(true); 11 | expect(trie.search('appl')).toEqual(false); 12 | expect(trie.search('applepen')).toEqual(true); 13 | }); 14 | -------------------------------------------------------------------------------- /src/data-structure/union-find/index.spec.js: -------------------------------------------------------------------------------- 1 | import DisjointSet from './index'; 2 | 3 | test('DisjointSet', () => { 4 | const set = new DisjointSet(6); 5 | set.union(0, 5); 6 | set.union(1, 2); 7 | set.union(3, 4); 8 | set.union(1, 4); 9 | expect(set.find(0)).toEqual(set.find(5)); 10 | expect(set.find(1)).toEqual(set.find(2)); 11 | expect(set.find(2)).toEqual(set.find(3)); 12 | expect(set.find(3)).toEqual(set.find(4)); 13 | }); 14 | -------------------------------------------------------------------------------- /src/leetcode/3sum-with-multiplicity/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} A 3 | * @param {number} target 4 | * @return {number} 5 | */ 6 | var threeSumMulti = function(A, target) { 7 | // number of combinations of 2 numbers of certain sum 8 | const counts = {}; 9 | let n = 0; 10 | for (let i = 0; i < A.length; i++) { 11 | n += counts[target - A[i]] || 0; 12 | for (let j = 0; j < i; j++) { 13 | const sum = A[i] + A[j]; 14 | counts[sum] = (counts[sum] || 0) + 1; 15 | } 16 | } 17 | return n % (10 ** 9 + 7); 18 | }; 19 | -------------------------------------------------------------------------------- /src/leetcode/4-keys-keyboard/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} N 3 | * @return {number} 4 | */ 5 | 6 | var maxA = function(N) { 7 | const dp = [...new Array(N + 1)].map((_, i) => i); 8 | for (let i = 4; i <= N; i++) { 9 | for (let j = 1; j <= i - 3; j++) { 10 | dp[i] = Math.max(dp[i], dp[j] * (i - j - 1)); 11 | } 12 | } 13 | return dp[N]; 14 | }; 15 | -------------------------------------------------------------------------------- /src/leetcode/4sum/index.spec.js: -------------------------------------------------------------------------------- 1 | import fn from './index'; 2 | 3 | test('4sum', () => { 4 | expect(fn([-4, -4, -1, -1, -1, -1, 0, 0, 0, 1, 2, 2, 2], 0)).toEqual([ 5 | [-4, 0, 2, 2], 6 | [-1, -1, 0, 2], 7 | [-1, 0, 0, 1], 8 | ]); 9 | }); 10 | -------------------------------------------------------------------------------- /src/leetcode/accounts-merge/721. Accounts Merge.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/accounts-merge/721. Accounts Merge.pdf -------------------------------------------------------------------------------- /src/leetcode/add-and-search-word-data-structure-design/Add and Search Word - Data structure design.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/add-and-search-word-data-structure-design/Add and Search Word - Data structure design.pdf -------------------------------------------------------------------------------- /src/leetcode/add-binary/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} a 3 | * @param {string} b 4 | * @return {string} 5 | */ 6 | var addBinary = function(a, b) { 7 | let i = a.length - 1; 8 | let j = b.length - 1; 9 | let c = 0; 10 | let output = ''; 11 | while (i >= 0 || j >= 0 || c > 0) { 12 | const sum = parseInt(a[i] || '0') + parseInt(b[j] || '0') + c; 13 | output = (sum % 2) + output; 14 | c = Math.floor(sum / 2); 15 | i -= 1; 16 | j -= 1; 17 | } 18 | return output; 19 | }; 20 | -------------------------------------------------------------------------------- /src/leetcode/add-digits/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} num 3 | * @return {number} 4 | */ 5 | var addDigits = function(num) { 6 | return 1 + ((num - 1) % 9); 7 | }; 8 | -------------------------------------------------------------------------------- /src/leetcode/add-strings/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} num1 3 | * @param {string} num2 4 | * @return {string} 5 | */ 6 | var addStrings = function(num1, num2) { 7 | let i = num1.length - 1; 8 | let j = num2.length - 1; 9 | let c = 0; 10 | let output = ''; 11 | while (i >= 0 || j >= 0 || c > 0) { 12 | const sum = parseInt(num1[i] || '0') + parseInt(num2[j] || '0') + c; 13 | output = (sum % 10) + output; 14 | c = Math.floor(sum / 10); 15 | i -= 1; 16 | j -= 1; 17 | } 18 | return output; 19 | }; 20 | -------------------------------------------------------------------------------- /src/leetcode/add-two-numbers/2. Add Two Numbers.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/add-two-numbers/2. Add Two Numbers.pdf -------------------------------------------------------------------------------- /src/leetcode/adding-two-negabinary-numbers/1073. Adding Two Negabinary Numbers 2019-08-04.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/adding-two-negabinary-numbers/1073. Adding Two Negabinary Numbers 2019-08-04.pdf -------------------------------------------------------------------------------- /src/leetcode/adding-two-negabinary-numbers/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | - For each digit 6 | - Calcute sum which is equal to `arr1[i] + arr2[j] + c` 7 | - Push `sum % 2` to output 8 | - Update carry. `c = -(sum >> 1)` 9 | - Finally, trim leading zeros. 10 | -------------------------------------------------------------------------------- /src/leetcode/alien-dictionary/Alien Dictionary.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/alien-dictionary/Alien Dictionary.pdf -------------------------------------------------------------------------------- /src/leetcode/all-oone-data-structure/IMG_3581.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/all-oone-data-structure/IMG_3581.JPG -------------------------------------------------------------------------------- /src/leetcode/all-paths-from-source-to-target/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[][]} graph 3 | * @return {number[][]} 4 | */ 5 | var allPathsSourceTarget = function(graph, u = 0, path = [u], output = []) { 6 | if (u === graph.length - 1) { 7 | output.push([...path]); 8 | return output; 9 | } 10 | for (const v of graph[u]) { 11 | path.push(v); 12 | allPathsSourceTarget(graph, v, path, output); 13 | path.pop(); 14 | } 15 | return output; 16 | }; 17 | -------------------------------------------------------------------------------- /src/leetcode/as-far-from-land-as-possible/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | To find a water cell with maximized nearest distance to any land, we need to know the nearest distance to any land for every water cell. Start from every land, do BFS to find out nearest distance to this land. In the maintime, we update the nearest distance to any land for every water cell. After traversing all lands, we know the nearest distance to any land for every water cell, we traverse all water cells to find out the maximized one. 6 | -------------------------------------------------------------------------------- /src/leetcode/basic-calculator-ii/227. Basic Calculator II.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/basic-calculator-ii/227. Basic Calculator II.pdf -------------------------------------------------------------------------------- /src/leetcode/basic-calculator-iii/submit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/basic-calculator-iii/submit.png -------------------------------------------------------------------------------- /src/leetcode/best-time-to-buy-and-sell-stock-ii/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} prices 3 | * @return {number} 4 | */ 5 | var maxProfit = function(prices) { 6 | let output = 0; 7 | for (let i = 1; i < prices.length; i++) { 8 | if (prices[i] > prices[i - 1]) { 9 | output += prices[i] - prices[i - 1]; 10 | } 11 | } 12 | return output; 13 | }; 14 | -------------------------------------------------------------------------------- /src/leetcode/best-time-to-buy-and-sell-stock-iii/123. Best Time to Buy and Sell Stock III.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/best-time-to-buy-and-sell-stock-iii/123. Best Time to Buy and Sell Stock III.pdf -------------------------------------------------------------------------------- /src/leetcode/best-time-to-buy-and-sell-stock-iv/188. Best Time to Buy and Sell Stock IV.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/best-time-to-buy-and-sell-stock-iv/188. Best Time to Buy and Sell Stock IV.pdf -------------------------------------------------------------------------------- /src/leetcode/best-time-to-buy-and-sell-stock/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} prices 3 | * @return {number} 4 | */ 5 | var maxProfit = function(prices) { 6 | let max = 0; 7 | let minSoFar = Infinity; 8 | for (const price of prices) { 9 | minSoFar = Math.min(minSoFar, price); 10 | max = Math.max(max, price - minSoFar); 11 | } 12 | return max; 13 | }; 14 | -------------------------------------------------------------------------------- /src/leetcode/binary-search/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @param {number} target 4 | * @return {number} 5 | */ 6 | const search = function(nums, target) { 7 | let i = 0; 8 | let j = nums.length - 1; 9 | while (i <= j) { 10 | let m = Math.floor((i + j) / 2); 11 | if (target === nums[m]) { 12 | return m; 13 | } else if (target > nums[m]) { 14 | i = m + 1; 15 | } else if (target < nums[m]) { 16 | j = m - 1; 17 | } 18 | } 19 | return -1; 20 | }; 21 | 22 | export default search; 23 | -------------------------------------------------------------------------------- /src/leetcode/binary-search/index.spec.js: -------------------------------------------------------------------------------- 1 | import fn from './index'; 2 | 3 | test('binary-search [-1, 0, 3, 5, 9, 12], 9', () => { 4 | expect(fn([-1, 0, 3, 5, 9, 12], 9)).toEqual(4); 5 | }); 6 | 7 | test('binary-search [-1, 0, 3, 5, 9, 12], 2', () => { 8 | expect(fn([-1, 0, 3, 5, 9, 12], 2)).toEqual(-1); 9 | }); 10 | -------------------------------------------------------------------------------- /src/leetcode/binary-subarrays-with-sum/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} A 3 | * @param {number} S 4 | * @return {number} 5 | */ 6 | var numSubarraysWithSum = function(A, S) { 7 | const freq = { 0: 1 }; 8 | let sum = 0; 9 | let nSubarrs = 0; 10 | for (const num of A) { 11 | sum += num; 12 | nSubarrs += freq[sum - S] || 0; 13 | freq[sum] = (freq[sum] || 0) + 1; 14 | } 15 | return nSubarrs; 16 | }; 17 | -------------------------------------------------------------------------------- /src/leetcode/binary-tree-inorder-traversal/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * function TreeNode(val) { 4 | * this.val = val; 5 | * this.left = this.right = null; 6 | * } 7 | */ 8 | /** 9 | * @param {TreeNode} root 10 | * @return {number[]} 11 | */ 12 | var inorderTraversal = function(root, output = []) { 13 | if (!root) { 14 | return output; 15 | } 16 | inorderTraversal(root.left, output); 17 | output.push(root.val); 18 | inorderTraversal(root.right, output); 19 | return output; 20 | }; 21 | -------------------------------------------------------------------------------- /src/leetcode/binary-tree-level-order-traversal-ii/Binary Tree Level Order Traversal II.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/binary-tree-level-order-traversal-ii/Binary Tree Level Order Traversal II.pdf -------------------------------------------------------------------------------- /src/leetcode/binary-tree-longest-consecutive-sequence-ii/submit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/binary-tree-longest-consecutive-sequence-ii/submit.png -------------------------------------------------------------------------------- /src/leetcode/binary-tree-maximum-path-sum/124. Binary Tree Maximum Path Sum.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/binary-tree-maximum-path-sum/124. Binary Tree Maximum Path Sum.pdf -------------------------------------------------------------------------------- /src/leetcode/binary-tree-maximum-path-sum/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | For every visited node, we calculate `localMax` and `globalMax`. 6 | 7 | `localMax`: Maximum value tnat can connect current node to its parent on the path. So it does not include this. 8 | 9 | left <- root -> right 10 | 11 | `globalMax`: Maximum value that can be formed within a tree rooted at current node. 12 | 13 | So for each node, we ask the information above from its left and right children and compute the result. 14 | -------------------------------------------------------------------------------- /src/leetcode/brace-expansion/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | First, create array from the given input. 6 | 7 | ```js 8 | '{a,b}c{d,e}f'; 9 | ``` 10 | 11 | ```js 12 | [['a', 'b'], ['c'], ['d', 'e'], ['f']]; 13 | ``` 14 | 15 | Then use DFS to list all combinations. 16 | -------------------------------------------------------------------------------- /src/leetcode/bulb-switcher-ii/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} n 3 | * @param {number} m 4 | * @return {number} 5 | */ 6 | var flipLights = function(n, m) { 7 | if (n <= 0 || m <= 0) { 8 | return 1; 9 | } 10 | if (n <= 1) { 11 | return 2; 12 | } 13 | if (n <= 2) { 14 | return m === 1 ? 3 : 4; 15 | } 16 | if (m === 1) { 17 | return 4; 18 | } 19 | return m === 2 ? 7 : 8; 20 | }; 21 | -------------------------------------------------------------------------------- /src/leetcode/bulb-switcher/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} n 3 | * @return {number} 4 | */ 5 | var bulbSwitch = function(n) { 6 | return Math.floor(Math.sqrt(n)); 7 | }; 8 | -------------------------------------------------------------------------------- /src/leetcode/campus-bikes-ii/submit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/campus-bikes-ii/submit.png -------------------------------------------------------------------------------- /src/leetcode/cheapest-flights-within-k-stops/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | Use BFS to traverse level by level. Keep going only if 6 | 7 | - `nStops + 1 <= K` 8 | - `price + prices[u][v] <= min` 9 | - If next price is going to be greater than min, no need to keep going. 10 | - Without this, it will result in Time Limit Exceeded. 11 | -------------------------------------------------------------------------------- /src/leetcode/check-completeness-of-a-binary-tree/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | Use BFS to iterate level by level from left to right. If there exists nodes after null node, it's not a complete tree. 6 | -------------------------------------------------------------------------------- /src/leetcode/check-if-it-is-a-good-array/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | If `a % x === 0` && `b % x === 0`, then `(a + b) % x === 0` and `(ap + bq) % x === 0`. 6 | 7 | `(ap + bq) % x === 0` 8 | 9 | If `x > 1`, then `ap + bq !== 1`. 10 | 11 | So to find `ap + bq === 1`, we need x to be 1. We are looking for if there exists some numbers that are coprime. 12 | -------------------------------------------------------------------------------- /src/leetcode/check-if-it-is-a-good-array/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {boolean} 4 | */ 5 | var isGoodArray = function(nums) { 6 | let gcd = nums[0]; 7 | for (const num of nums) { 8 | gcd = findGCD(num, gcd); 9 | if (gcd === 1) { 10 | return true; 11 | } 12 | } 13 | return false; 14 | }; 15 | 16 | function findGCD(a, b) { 17 | if (b === 0) { 18 | return a; 19 | } 20 | return findGCD(b, a % b); 21 | } 22 | -------------------------------------------------------------------------------- /src/leetcode/check-if-n-and-its-double-exist/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} arr 3 | * @return {boolean} 4 | */ 5 | var checkIfExist = function(arr) { 6 | const set = new Set(); 7 | for (const val of arr) { 8 | if (set.has(val / 2) || set.has(2 * val)) { 9 | return true; 10 | } 11 | set.add(val); 12 | } 13 | return false; 14 | }; 15 | -------------------------------------------------------------------------------- /src/leetcode/climbing-stairs/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} n 3 | * @return {number} 4 | */ 5 | var climbStairs = function(n) { 6 | if (n <= 2) { 7 | return n; 8 | } 9 | let x = 1; 10 | let y = 2; 11 | let dp = y; 12 | for (let i = 3; i <= n; i++) { 13 | dp = x + y; 14 | x = y; 15 | y = dp; 16 | } 17 | return dp; 18 | }; 19 | -------------------------------------------------------------------------------- /src/leetcode/closest-binary-search-tree-value-ii/272. Closest Binary Search Tree Value II.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/closest-binary-search-tree-value-ii/272. Closest Binary Search Tree Value II.pdf -------------------------------------------------------------------------------- /src/leetcode/closest-divisors/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} num 3 | * @return {number[]} 4 | */ 5 | var closestDivisors = function(num) { 6 | for (let i = Math.floor(Math.sqrt(num + 2)); i >= 1; i--) { 7 | if ((num + 1) % i === 0) { 8 | return [i, (num + 1) / i]; 9 | } 10 | if ((num + 2) % i === 0) { 11 | return [i, (num + 2) / i]; 12 | } 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /src/leetcode/coin-change-2/518. Coin Change 2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/coin-change-2/518. Coin Change 2.pdf -------------------------------------------------------------------------------- /src/leetcode/coin-change-2/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} amount 3 | * @param {number[]} coins 4 | * @return {number} 5 | */ 6 | var change = function(amount, coins) { 7 | const dp = new Array(amount + 1).fill(0); 8 | dp[0] = 1; 9 | for (const c of coins) { 10 | for (let i = 1; i <= amount; i++) { 11 | if (i - c >= 0) { 12 | dp[i] += dp[i - c]; 13 | } 14 | } 15 | } 16 | return dp[amount]; 17 | }; 18 | -------------------------------------------------------------------------------- /src/leetcode/coin-change/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | Define dp as minimum number of coins required to achieve `i` amount. 6 | 7 | ```js 8 | dp[i] = min { 1 + dp[i - coins[j]] } for j from 1 to coins.length - 1 9 | ``` 10 | -------------------------------------------------------------------------------- /src/leetcode/coin-change/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} coins 3 | * @param {number} amount 4 | * @return {number} 5 | */ 6 | var coinChange = function(coins, amount) { 7 | const dp = new Array(amount + 1).fill(Infinity); 8 | dp[0] = 0; 9 | for (let i = 1; i <= amount; i++) { 10 | for (const coin of coins) { 11 | const value = i - coin >= 0 ? dp[i - coin] + 1 : Infinity; 12 | dp[i] = Math.min(dp[i], value); 13 | } 14 | } 15 | return dp[amount] < Infinity ? dp[amount] : -1; 16 | }; 17 | -------------------------------------------------------------------------------- /src/leetcode/combinations/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} n 3 | * @param {number} k 4 | * @return {number[][]} 5 | */ 6 | const combine = function(n, k, start = 1, selected = [], output = []) { 7 | if (selected.length >= k) { 8 | output.push([...selected]); 9 | return output; 10 | } 11 | for (let i = start; i <= n; i++) { 12 | selected.push(i); 13 | combine(n, k, i + 1, selected, output); 14 | selected.pop(); 15 | } 16 | return output; 17 | }; 18 | 19 | export default combine; 20 | -------------------------------------------------------------------------------- /src/leetcode/combinations/index.spec.js: -------------------------------------------------------------------------------- 1 | import fn from './index'; 2 | 3 | test('combinations', () => { 4 | const result = [[1, 2], [1, 3], [1, 4], [1, 5], [2, 3], [2, 4], [2, 5], [3, 4], [3, 5], [4, 5]]; 5 | expect(fn(5, 2)).toEqual(result); 6 | }); 7 | 8 | test('combinations', () => { 9 | const result = [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]; 10 | expect(fn(4, 2)).toEqual(result); 11 | }); 12 | -------------------------------------------------------------------------------- /src/leetcode/confusing-number/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} N 3 | * @return {boolean} 4 | */ 5 | var confusingNumber = function(N) { 6 | const map = { 7 | '0': '0', 8 | '1': '1', 9 | '6': '9', 10 | '8': '8', 11 | '9': '6', 12 | }; 13 | const nStr = N + ''; 14 | let num = ''; 15 | for (const c of nStr) { 16 | if (!(c in map)) { 17 | return false; 18 | } 19 | num = map[c] + num; 20 | } 21 | return num !== nStr; 22 | }; 23 | -------------------------------------------------------------------------------- /src/leetcode/construct-binary-tree-from-preorder-and-postorder-traversal/submit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/construct-binary-tree-from-preorder-and-postorder-traversal/submit.png -------------------------------------------------------------------------------- /src/leetcode/container-with-most-water/11. Container With Most Water.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/container-with-most-water/11. Container With Most Water.pdf -------------------------------------------------------------------------------- /src/leetcode/container-with-most-water/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} height 3 | * @return {number} 4 | */ 5 | var maxArea = function(height) { 6 | let left = 0; 7 | let right = height.length - 1; 8 | let max = -Infinity; 9 | while (left < right) { 10 | const area = Math.min(height[left], height[right]) * (right - left); 11 | max = Math.max(max, area); 12 | if (height[left] <= height[right]) { 13 | left += 1; 14 | } else { 15 | right -= 1; 16 | } 17 | } 18 | return max; 19 | }; 20 | -------------------------------------------------------------------------------- /src/leetcode/container-with-most-water/index.spec.js: -------------------------------------------------------------------------------- 1 | import fn from './index'; 2 | 3 | test('container-with-most-water', () => { 4 | expect(fn([1, 8, 6, 2, 5, 4, 8, 3, 7])).toEqual(49); 5 | }); 6 | -------------------------------------------------------------------------------- /src/leetcode/contains-duplicate/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {boolean} 4 | */ 5 | var containsDuplicate = function(nums) { 6 | const cache = {}; 7 | for (let i = 0; i < nums.length; i++) { 8 | if (cache[nums[i]]) { 9 | return true; 10 | } 11 | cache[nums[i]] = true; 12 | } 13 | return false; 14 | }; 15 | -------------------------------------------------------------------------------- /src/leetcode/continuous-subarray-sum/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @param {number} k 4 | * @return {boolean} 5 | */ 6 | var checkSubarraySum = function(nums, k) { 7 | const map = { 0: -1 }; 8 | let sum = 0; 9 | for (let i = 0; i < nums.length; i++) { 10 | sum += nums[i]; 11 | const r = sum % k; 12 | if (r in map && i - map[r] >= 2) { 13 | return true; 14 | } 15 | if (!(r in map)) { 16 | map[r] = i; 17 | } 18 | } 19 | return false; 20 | }; 21 | -------------------------------------------------------------------------------- /src/leetcode/continuous-subarray-sum/note.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/continuous-subarray-sum/note.pdf -------------------------------------------------------------------------------- /src/leetcode/convert-a-number-to-hexadecimal/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | - For each iteration 6 | - Get reminder of `n % 16` by `&` with `15` 7 | - Divide n with 16 by right shifting without sign bits 8 | - `n = n >>> 4;` 9 | - https://stackoverflow.com/questions/10382122/what-is-operator-in-js 10 | 11 | ### Reminder of n % 16 12 | 13 | ``` 14 | 1011 1101 15 | & 0000 1111 16 | ----------- 17 | 0000 1101 18 | ``` 19 | 20 | ### Right shifting without sign bits 21 | 22 | ``` 23 | n = 1011 1101 24 | n >>> 4 = 0000 1011 25 | ``` 26 | -------------------------------------------------------------------------------- /src/leetcode/convert-a-number-to-hexadecimal/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} num 3 | * @return {string} 4 | */ 5 | 6 | // prettier-ignore 7 | const map = [ 8 | ...[...new Array(10)].map((_, i) => i), 9 | 'a', 10 | 'b', 11 | 'c', 12 | 'd', 13 | 'e', 14 | 'f', 15 | ]; 16 | 17 | var toHex = function(num) { 18 | if (!num) { 19 | return '0'; 20 | } 21 | let output = ''; 22 | let n = num; 23 | while (n) { 24 | const r = n & 15; 25 | output = map[r] + output; 26 | n = n >>> 4; 27 | } 28 | return output; 29 | }; 30 | -------------------------------------------------------------------------------- /src/leetcode/convert-binary-number-in-a-linked-list-to-integer/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * function ListNode(val) { 4 | * this.val = val; 5 | * this.next = null; 6 | * } 7 | */ 8 | /** 9 | * @param {ListNode} head 10 | * @return {number} 11 | */ 12 | var getDecimalValue = function(head) { 13 | let ptr = head; 14 | let sum = 0; 15 | while (ptr) { 16 | sum = sum * 2 + ptr.val; 17 | ptr = ptr.next; 18 | } 19 | return sum; 20 | }; 21 | -------------------------------------------------------------------------------- /src/leetcode/convert-to-base-2/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | -9 to base -2 6 | 7 | ``` 8 | -9 = -2 * 5 + 1 9 | 5 = -2 * -2 + 1 10 | -2 = -2 * 1 + 0 11 | 1 = -2 * 0 + 1 12 | ``` 13 | 14 | Every time we take reminder to the output. Then we shift right `num` for 1 time and take negative sign. Repeat this process until `num` is equal to zero. 15 | 16 | Noted that reminder is always positive. 17 | -------------------------------------------------------------------------------- /src/leetcode/convert-to-base-2/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} N 3 | * @return {string} 4 | */ 5 | var baseNeg2 = function(N) { 6 | if (N === 0) { 7 | return '0'; 8 | } 9 | let num = N; 10 | let output = ''; 11 | while (num) { 12 | output = (num & 1) + output; 13 | num = -(num >> 1); 14 | } 15 | return output; 16 | }; 17 | -------------------------------------------------------------------------------- /src/leetcode/convert-to-base-2/to base -2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/convert-to-base-2/to base -2.pdf -------------------------------------------------------------------------------- /src/leetcode/convert-to-base-2/to base -8.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/convert-to-base-2/to base -8.pdf -------------------------------------------------------------------------------- /src/leetcode/convert-to-base-2/what happens to 9 >> 1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/convert-to-base-2/what happens to 9 >> 1.pdf -------------------------------------------------------------------------------- /src/leetcode/copy-list-with-random-pointer/138. Copy List with Random Pointer.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/copy-list-with-random-pointer/138. Copy List with Random Pointer.pdf -------------------------------------------------------------------------------- /src/leetcode/count-negative-numbers-in-a-sorted-matrix/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[][]} grid 3 | * @return {number} 4 | */ 5 | var countNegatives = function(grid) { 6 | const m = grid.length; 7 | const n = grid[0].length; 8 | let i = 0; 9 | let j = n; 10 | let nNegatives = 0; 11 | while (i < m && j >= 0) { 12 | while (grid[i][j - 1] < 0) { 13 | j -= 1; 14 | } 15 | nNegatives += n - j; 16 | i += 1; 17 | } 18 | return nNegatives; 19 | }; 20 | -------------------------------------------------------------------------------- /src/leetcode/count-of-range-sum/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | ``` 6 | S(i, j) = sum[i] - sum[j - 1] 7 | lower <= sum[i] - sum[j - 1] <= upper 8 | 9 | looking for some `sum` in the interval of [sum[i] - upper, sum[i] - lower] 10 | sum[i] - upper <= sum[j - 1] <= sum[i] - lower 11 | 12 | example prefixSum: 13 | 14 | const prefixSum = [1,2,2,3,3,4] 15 | assume: 16 | sum[i] - upper = 2 17 | sum[i] - lower = 3 18 | count of range sum = upperBound(prefixSum, 3) - lowerBound(prefixSum, 2) = 5 - 1 = 4 19 | ``` 20 | -------------------------------------------------------------------------------- /src/leetcode/count-primes/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} n 3 | * @return {number} 4 | */ 5 | var countPrimes = function(n) { 6 | if (n < 3) { 7 | return 0; 8 | } 9 | const isPrime = new Array(n).fill(false); 10 | let count = 0; 11 | for (let i = 2; i < n; i++) { 12 | if (!isPrime[i]) { 13 | count += 1; 14 | for (let j = 2; i * j < n; j++) { 15 | isPrime[i * j] = true; 16 | } 17 | } 18 | } 19 | return count; 20 | }; 21 | -------------------------------------------------------------------------------- /src/leetcode/count-primes/index.spec.js: -------------------------------------------------------------------------------- 1 | import fn from './index'; 2 | 3 | test('count-primes', () => { 4 | expect(fn(100)).toEqual(25); 5 | }); 6 | 7 | test('count-primes', () => { 8 | expect(fn(1)).toEqual(0); 9 | }); 10 | -------------------------------------------------------------------------------- /src/leetcode/cracking-the-safe/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} n 3 | * @param {number} k 4 | * @return {string} 5 | */ 6 | var crackSafe = function(n, k) { 7 | let pwd = '0'.repeat(n); 8 | const visited = new Set([pwd]); 9 | const nTotal = k ** n; 10 | while (visited.size < nTotal) { 11 | for (let i = k - 1; i >= 0; i--) { 12 | const word = pwd.substring(pwd.length - (n - 1)) + i; 13 | if (!visited.has(word)) { 14 | visited.add(word); 15 | pwd += i; 16 | break; 17 | } 18 | } 19 | } 20 | return pwd; 21 | }; 22 | -------------------------------------------------------------------------------- /src/leetcode/critical-connections-in-a-network/1192. Critical Connections in a Network.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/critical-connections-in-a-network/1192. Critical Connections in a Network.pdf -------------------------------------------------------------------------------- /src/leetcode/daily-temperatures/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} T 3 | * @return {number[]} 4 | */ 5 | var dailyTemperatures = function(T) { 6 | const output = new Array(T.length).fill(0); 7 | const stack = []; 8 | for (let i = 0; i < T.length; i++) { 9 | while (stack.length && T[i] > T[stack[stack.length - 1]]) { 10 | const j = stack.pop(); 11 | output[j] = i - j; 12 | } 13 | stack.push(i); 14 | } 15 | return output; 16 | }; 17 | -------------------------------------------------------------------------------- /src/leetcode/decode-string/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | Use a stack to store `[nRepeats, str]`. 6 | 7 | Iterate over str. 8 | 9 | - if encounter a number, update `nRepeats` in the top of stack. 10 | - if encounter `[`, continue. 11 | - if encounter `]`, compute the result of top of stack and append result to top of remaining stack. 12 | - otherwise, append character to top of stack. 13 | -------------------------------------------------------------------------------- /src/leetcode/decode-ways/Decode ways.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/decode-ways/Decode ways.pdf -------------------------------------------------------------------------------- /src/leetcode/decode-ways/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | ```js 6 | dp(n) = (if last two characters is decodable ? dp(n - 2) : 0) + 7 | (if last characters is decodable ? dp(n - 1) : 0) 8 | ``` 9 | 10 | ```js 11 | dp = x + y; 12 | // x = dp[n - 2] 13 | // y = dp[n - 1] 14 | ``` 15 | -------------------------------------------------------------------------------- /src/leetcode/defanging-an-ip-address/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} address 3 | * @return {string} 4 | */ 5 | var defangIPaddr = function(address) { 6 | return address.replace(/\./g, '[.]'); 7 | }; 8 | -------------------------------------------------------------------------------- /src/leetcode/delete-and-earn/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | It's similar to house robber question. Because delete `n`, it will delete both `n - 1` and `n + 1`. It means `n` and `n - 1` can't be selected at the same time. 6 | 7 | Define `dp[i]` as maximum value at `i`. 8 | 9 | ```js 10 | dp[i] = Math.max(dp[i - 1], freq[i] * i + dp[i - 2]); 11 | ``` 12 | -------------------------------------------------------------------------------- /src/leetcode/delete-operation-for-two-strings/README.md: -------------------------------------------------------------------------------- 1 | ## README 2 | 3 | ## Algorithm 4 | 5 | Find out the LCS of two words. To minimize delete operations, we just delete words that are not LCS. So our goal becomes finding LCS of two words. 6 | 7 | ```js 8 | // dp[i][j] represents LCS of word1 with string length i and word2 with string length j. 9 | dp[i][j] = (() => { 10 | if (word1[i - 1] === word2[j - 1]) { 11 | return dp[i - 1][j - 1] + 1; 12 | } 13 | return Math.max(dp[i][j - 1], dp[i - 1][j]); 14 | })(); 15 | ``` 16 | -------------------------------------------------------------------------------- /src/leetcode/diagonal-traverse/498. Diagonal Traverse.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/diagonal-traverse/498. Diagonal Traverse.pdf -------------------------------------------------------------------------------- /src/leetcode/distribute-coins-in-binary-tree/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | For each subtree, 6 | 7 | ``` 8 | number of moves required = Math.abs(number of coins - number of nodes) 9 | ``` 10 | 11 | It means number of moves required to make this subtree balanced. So the total number of moves is equal to `number of moves required` for each subtree. 12 | 13 | So given a root, we ask its children recursively for number of nodes, number of coins and number of moves, then we can compose result for the given root. 14 | -------------------------------------------------------------------------------- /src/leetcode/divide-two-integers/29. Divide Two Integers.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/divide-two-integers/29. Divide Two Integers.pdf -------------------------------------------------------------------------------- /src/leetcode/divide-two-integers/index.spec.js: -------------------------------------------------------------------------------- 1 | import fn from './index'; 2 | 3 | test('divide-two-integers', () => { 4 | expect(fn(-2147483648, 2)).toEqual(-1073741824); 5 | }); 6 | 7 | test('divide-two-integers', () => { 8 | expect(fn(-2147483648, -1)).toEqual(2147483647); 9 | }); 10 | 11 | test('divide-two-integers', () => { 12 | expect(fn(-2147483648, 1)).toEqual(-2147483648); 13 | }); 14 | 15 | test('divide-two-integers', () => { 16 | expect(fn(30, 5)).toEqual(6); 17 | }); 18 | 19 | test('divide-two-integers', () => { 20 | expect(fn(10, 3)).toEqual(3); 21 | }); 22 | -------------------------------------------------------------------------------- /src/leetcode/divide-two-integers/screencapture-leetcode-submissions-detail-179251987-2018-09-29-20_31_17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/divide-two-integers/screencapture-leetcode-submissions-detail-179251987-2018-09-29-20_31_17.png -------------------------------------------------------------------------------- /src/leetcode/duplicate-zeros/v2.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} arr 3 | * @return {void} Do not return anything, modify arr in-place instead. 4 | */ 5 | var duplicateZeros = function(arr) { 6 | const m = arr.length; 7 | for (let i = 0; i < arr.length; i++) { 8 | if (arr[i] === 0) { 9 | arr.splice(i, 0, 0); 10 | i += 1; 11 | } 12 | } 13 | arr.splice(m, arr.length - m); 14 | }; 15 | -------------------------------------------------------------------------------- /src/leetcode/evaluate-division/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | - Create a graph with given equations. So that given a number, we can know which numbers are linked to this number and the value of A / B. 6 | - Then we use this graph with DFS to create all possible relations. 7 | - Finally we can map each query to the result of all possible relations. 8 | -------------------------------------------------------------------------------- /src/leetcode/excel-sheet-column-number/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} s 3 | * @return {number} 4 | */ 5 | var titleToNumber = function(s) { 6 | const m = s.length; 7 | let sum = 0; 8 | for (let i = 0; i < m; i++) { 9 | sum += getCode(s[i]) * 26 ** (m - i - 1); 10 | } 11 | return sum; 12 | }; 13 | 14 | function getCode(c) { 15 | return c.charCodeAt(0) - 'A'.charCodeAt(0) + 1; 16 | } 17 | -------------------------------------------------------------------------------- /src/leetcode/excel-sheet-column-title/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} n 3 | * @return {string} 4 | */ 5 | var convertToTitle = function(n) { 6 | const m = 26; 7 | let output = ''; 8 | let num = n; 9 | while (num >= 1) { 10 | // prettier-ignore 11 | const r = num % m > 0 12 | ? num % m 13 | : 26; 14 | output = getChar(r - 1) + output; 15 | num = Math.floor((num - r) / m); 16 | } 17 | return output; 18 | }; 19 | 20 | function getChar(i) { 21 | const base = 'A'.charCodeAt(0); 22 | return String.fromCharCode(base + i); 23 | } 24 | -------------------------------------------------------------------------------- /src/leetcode/exclusive-time-of-functions/636. Exclusive Time of Functions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/exclusive-time-of-functions/636. Exclusive Time of Functions.pdf -------------------------------------------------------------------------------- /src/leetcode/fibonacci-number/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} N 3 | * @return {number} 4 | */ 5 | var fib = function(N) { 6 | if (N <= 1) { 7 | return N; 8 | } 9 | let x = 0; 10 | let y = 1; 11 | let dp; 12 | for (let i = 2; i <= N; i++) { 13 | dp = x + y; 14 | x = y; 15 | y = dp; 16 | } 17 | return dp; 18 | }; 19 | -------------------------------------------------------------------------------- /src/leetcode/find-all-duplicates-in-an-array/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number[]} 4 | */ 5 | var findDuplicates = function(nums) { 6 | const output = []; 7 | for (let i = 0; i < nums.length; i++) { 8 | const index = Math.abs(nums[i]); 9 | if (nums[index - 1] < 0) { 10 | output.push(index); 11 | } else { 12 | nums[index - 1] *= -1; 13 | } 14 | } 15 | return output; 16 | }; 17 | -------------------------------------------------------------------------------- /src/leetcode/find-k-pairs-with-smallest-sums/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | - Use a priority queue to get the pair with smallest sum from pairs 6 | - We start from the first element of each array. `[0, 0]` 7 | - For each iteration, 8 | - Dequeue from the queue to get the smallest one. 9 | - Next smallest could be either `[i + 1, j]` or `[i, j + 1]`. 10 | - So push those candidates to the queue. 11 | - To prevent visiting duplicated pairs, we have `visited` set to check duplication. 12 | -------------------------------------------------------------------------------- /src/leetcode/find-leaves-of-binary-tree/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | Use DFS to find out the maximum depth to leaves for each node. And put the value of this node to its corresponding maximum depth. 6 | -------------------------------------------------------------------------------- /src/leetcode/find-median-from-data-stream/295. Find Median from Data Stream 2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/find-median-from-data-stream/295. Find Median from Data Stream 2.pdf -------------------------------------------------------------------------------- /src/leetcode/find-median-from-data-stream/295. Find Median from Data Stream.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/find-median-from-data-stream/295. Find Median from Data Stream.pdf -------------------------------------------------------------------------------- /src/leetcode/find-minimum-in-rotated-sorted-array/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number} 4 | */ 5 | 6 | var findMin = function(nums) { 7 | let left = 0; 8 | let right = nums.length - 1; 9 | while (left < right) { 10 | const mid = Math.floor((left + right) / 2); 11 | if (nums[right] >= nums[left]) { 12 | right = left; 13 | } else if (nums[mid] >= nums[left]) { 14 | left = mid + 1; 15 | } else { 16 | right = mid; 17 | } 18 | } 19 | return nums[left]; 20 | }; 21 | -------------------------------------------------------------------------------- /src/leetcode/find-peak-element/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | Peak element is defined as the element that is greater than its neighbors. And also define that element is greater than boundary. 6 | 7 | `[1,3,1]` 8 | `[1,2,3]` 9 | 10 | `3` in both arrays are defined as a peak element. 11 | 12 | So we can use binary search to always search in the range that contains a greater element than `arr[mid]`. 13 | -------------------------------------------------------------------------------- /src/leetcode/find-pivot-index/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number} 4 | */ 5 | var pivotIndex = function(nums) { 6 | let right = nums.reduce((a, b) => a + b, 0); 7 | let left = 0; 8 | for (let i = 0; i < nums.length; i++) { 9 | right -= nums[i]; 10 | if (left === right) { 11 | return i; 12 | } 13 | left += nums[i]; 14 | } 15 | return -1; 16 | }; 17 | -------------------------------------------------------------------------------- /src/leetcode/find-the-duplicate-number/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number} 4 | */ 5 | var findDuplicate = function(nums) { 6 | const head = nums[0]; 7 | let slow = nums[head]; 8 | let fast = nums[nums[head]]; 9 | while (slow !== fast) { 10 | slow = nums[slow]; 11 | fast = nums[nums[fast]]; 12 | } 13 | fast = head; 14 | while (slow !== fast) { 15 | slow = nums[slow]; 16 | fast = nums[fast]; 17 | } 18 | return slow || -1; 19 | }; 20 | -------------------------------------------------------------------------------- /src/leetcode/first-bad-version/278. First Bad Version.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/first-bad-version/278. First Bad Version.pdf -------------------------------------------------------------------------------- /src/leetcode/first-unique-character-in-a-string/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} s 3 | * @return {number} 4 | */ 5 | var firstUniqChar = function(s) { 6 | const freq = {}; 7 | for (const c of s) { 8 | freq[c] = (freq[c] || 0) + 1; 9 | } 10 | for (let i = 0; i < s.length; i++) { 11 | if (freq[s[i]] === 1) { 12 | return i; 13 | } 14 | } 15 | return -1; 16 | }; 17 | -------------------------------------------------------------------------------- /src/leetcode/fixed-point/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} A 3 | * @return {number} 4 | */ 5 | var fixedPoint = function(A) { 6 | let left = 0; 7 | let right = A.length; 8 | while (left < right) { 9 | const mid = Math.floor((left + right) / 2); 10 | if (mid > A[mid]) { 11 | left = mid + 1; 12 | } else { 13 | right = mid; 14 | } 15 | } 16 | const mid = Math.floor((left + right) / 2); 17 | return mid === A[mid] ? left : -1; 18 | }; 19 | -------------------------------------------------------------------------------- /src/leetcode/fraction-to-recurring-decimal/submit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/fraction-to-recurring-decimal/submit.png -------------------------------------------------------------------------------- /src/leetcode/friends-of-appropriate-ages/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | - Count number of people for each age. 6 | - Pair each ages to see if they should send request to each other. 7 | - People don't send request to themselves. `If A === B, n += freq[A] * (freq[B] - 1)` 8 | - For javascript, every key in object will be transform to string. To store key with its original type, we should use `Map`. 9 | -------------------------------------------------------------------------------- /src/leetcode/gas-station/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} gas 3 | * @param {number[]} cost 4 | * @return {number} 5 | */ 6 | var canCompleteCircuit = function(gas, cost) { 7 | const n = gas.length; 8 | let total = 0; 9 | let sum = 0; 10 | let start = 0; 11 | for (let i = 0; i < n; i++) { 12 | total += gas[i] - cost[i]; 13 | sum += gas[i] - cost[i]; 14 | if (sum < 0) { 15 | start = i + 1; 16 | sum = 0; 17 | } 18 | } 19 | return total >= 0 ? start : -1; 20 | }; 21 | -------------------------------------------------------------------------------- /src/leetcode/generate-parentheses/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | - Backtracking 6 | - For each run, push left '(' first then push right ')' 7 | - It's faster to use string concatenation in javascript than joining string. 8 | -------------------------------------------------------------------------------- /src/leetcode/generate-parentheses/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} n 3 | * @return {string[]} 4 | */ 5 | var generateParenthesis = function(n, left = 0, right = 0, selected = '', output = []) { 6 | if (selected.length >= n * 2) { 7 | output.push(selected); 8 | return output; 9 | } 10 | if (left < n) { 11 | generateParenthesis(n, left + 1, right, selected + '(', output); 12 | } 13 | if (left > right) { 14 | generateParenthesis(n, left, right + 1, selected + ')', output); 15 | } 16 | return output; 17 | }; 18 | -------------------------------------------------------------------------------- /src/leetcode/goat-latin/Goat Latin.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/goat-latin/Goat Latin.pdf -------------------------------------------------------------------------------- /src/leetcode/goat-latin/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} S 3 | * @return {string} 4 | */ 5 | var toGoatLatin = function(S) { 6 | return S.split(' ') 7 | .map(mapper) 8 | .join(' '); 9 | }; 10 | 11 | function mapper(word, i) { 12 | if (isVowel(word[0])) { 13 | return word + 'ma' + 'a'.repeat(i + 1); 14 | } 15 | const [first, ...rest] = word; 16 | return rest.join('') + first + 'ma' + 'a'.repeat(i + 1); 17 | } 18 | 19 | function isVowel(c) { 20 | const set = new Set(['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U']); 21 | return set.has(c); 22 | } 23 | -------------------------------------------------------------------------------- /src/leetcode/graph-valid-tree/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | A graph is a tree if: 6 | 7 | - No cycle 8 | - Connected 9 | 10 | So we are going to check no cycle and all nodes have been visited. 11 | 12 | We can test `hasCycle` from any node since any node in a tree can be the root. So we can start from any node. 13 | -------------------------------------------------------------------------------- /src/leetcode/gray-code/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | ``` 6 | n = 2 | 00,01,11,10 7 | n = 3 | 000,001,011,010,110,111,101,100 8 | ``` 9 | 10 | to get gray code for n = 3, just copy the array, reverse it and add 2 \*\* i to the array for each value. 11 | -------------------------------------------------------------------------------- /src/leetcode/gray-code/idnex.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} n 3 | * @return {number[]} 4 | */ 5 | var grayCode = function(n) { 6 | const dp = [0]; 7 | for (let i = 0; i < n; i++) { 8 | const next = dp.slice().reverse(); 9 | for (let j = 0; j < next.length; j++) { 10 | next[j] += 2 ** i; 11 | } 12 | dp.push(...next); 13 | } 14 | return dp; 15 | }; 16 | -------------------------------------------------------------------------------- /src/leetcode/greatest-common-divisor-of-strings/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} str1 3 | * @param {string} str2 4 | * @return {string} 5 | */ 6 | var gcdOfStrings = function(str1, str2) { 7 | if (str1 + str2 !== str2 + str1) { 8 | return ''; 9 | } 10 | const length = gcd(str1.length, str2.length); 11 | return str1.substring(0, length); 12 | }; 13 | 14 | function gcd(a, b) { 15 | if (b === 0) { 16 | return a; 17 | } 18 | return gcd(b, a % b); 19 | } 20 | -------------------------------------------------------------------------------- /src/leetcode/greatest-sum-divisible-by-three/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | Define `dp[i][r]` as maximum sum with reminder r and with array ending at i 6 | 7 | ```js 8 | const r = (nums[i] + dp[i - 1][j]) % m; 9 | dp[i][r] = Math.max(dp[i][r], nums[i] + dp[i - 1][j]); 10 | ``` 11 | 12 | ```js 13 | next[r] = Math.max(next[r], nums[i] + dp[j]); 14 | ``` 15 | -------------------------------------------------------------------------------- /src/leetcode/greatest-sum-divisible-by-three/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number} 4 | */ 5 | var maxSumDivThree = function(nums) { 6 | const m = 3; 7 | let dp = new Array(m).fill(0); 8 | for (let i = 0; i < nums.length; i++) { 9 | const next = [...dp]; 10 | for (let j = 0; j < m; j++) { 11 | const r = (nums[i] + dp[j]) % m; 12 | next[r] = Math.max(next[r], nums[i] + dp[j]); 13 | } 14 | dp = next; 15 | } 16 | return dp[0]; 17 | }; 18 | -------------------------------------------------------------------------------- /src/leetcode/group-anagrams/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string[]} strs 3 | * @return {string[][]} 4 | */ 5 | var groupAnagrams = function(strs) { 6 | const map = {}; 7 | for (const str of strs) { 8 | // prettier-ignore 9 | const key = str.split('').sort().join(''); 10 | if (!(key in map)) map[key] = []; 11 | map[key].push(str); 12 | } 13 | return Object.values(map); 14 | }; 15 | -------------------------------------------------------------------------------- /src/leetcode/group-the-people-given-the-group-size-they-belong-to/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} groupSizes 3 | * @return {number[][]} 4 | */ 5 | var groupThePeople = function(groupSizes) { 6 | const map = {}; 7 | const output = []; 8 | for (let i = 0; i < groupSizes.length; i++) { 9 | const size = groupSizes[i]; 10 | if (!(size in map)) map[size] = []; 11 | map[size].push(i); 12 | if (map[size].length >= size) { 13 | output.push(map[size].splice(0, size)); 14 | } 15 | } 16 | return output; 17 | }; 18 | -------------------------------------------------------------------------------- /src/leetcode/h-index-ii/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} citations 3 | * @return {number} 4 | */ 5 | var hIndex = function(citations) { 6 | const n = citations.length; 7 | let left = 0; 8 | let right = n + 1; 9 | let max = 0; 10 | while (left < right) { 11 | const mid = Math.floor((left + right) / 2); 12 | if (citations[n - mid] >= mid) { 13 | max = Math.max(max, mid); 14 | left = mid + 1; 15 | } else { 16 | right = mid; 17 | } 18 | } 19 | return max; 20 | }; 21 | -------------------------------------------------------------------------------- /src/leetcode/hamming-distance/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} x 3 | * @param {number} y 4 | * @return {number} 5 | */ 6 | var hammingDistance = function(x, y) { 7 | let n = x ^ y; 8 | let output = 0; 9 | while (n) { 10 | output += n % 2; 11 | n >>= 1; 12 | } 13 | return output; 14 | }; 15 | -------------------------------------------------------------------------------- /src/leetcode/happy-number/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Example 4 | 5 | ```js 6 | 20 7 | 2 ** 2 + 0 ** 2 = 4 8 | 4 ** 2 = 16 9 | 1 ** 2 + 6 ** 2 = 37 10 | 3 ** 2 + 7 ** 2 = 58 11 | 5 ** 2 + 8 ** 2 = 89 12 | 8 ** 2 + 9 ** 2 = 145 13 | 1 ** 2 + 4 ** 2 + 5 ** 2 = 42 14 | 4 ** 2 + 2 ** 2 = 20 15 | ``` 16 | -------------------------------------------------------------------------------- /src/leetcode/happy-number/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} n 3 | * @return {boolean} 4 | */ 5 | var isHappy = function(n) { 6 | let slow = next(n); 7 | let fast = next(slow); 8 | while (slow !== fast) { 9 | slow = next(slow); 10 | fast = next(next(fast)); 11 | } 12 | if (slow === 1) { 13 | return true; 14 | } 15 | return false; 16 | }; 17 | 18 | function next(n) { 19 | let num = n; 20 | let output = 0; 21 | while (num > 0) { 22 | output += (num % 10) ** 2; 23 | num = Math.floor(num / 10); 24 | } 25 | return output; 26 | } 27 | -------------------------------------------------------------------------------- /src/leetcode/house-robber-iii/FireShot_Capture_2_-__1__House_Robber_III_-_Su__-_https___leetcode_com_submissions_detail_174593214_.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/house-robber-iii/FireShot_Capture_2_-__1__House_Robber_III_-_Su__-_https___leetcode_com_submissions_detail_174593214_.png -------------------------------------------------------------------------------- /src/leetcode/house-robber/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number} 4 | */ 5 | var rob = function(nums) { 6 | if (nums.length <= 2) { 7 | return Math.max(...nums, 0); 8 | } 9 | let x = nums[0]; 10 | let y = Math.max(x, nums[1]); 11 | let dp = y; 12 | for (let i = 2; i < nums.length; i++) { 13 | dp = Math.max(y, x + nums[i]); 14 | x = y; 15 | y = dp; 16 | } 17 | return dp; 18 | }; 19 | -------------------------------------------------------------------------------- /src/leetcode/implement-strstr/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} haystack 3 | * @param {string} needle 4 | * @return {number} 5 | */ 6 | var strStr = function(haystack, needle) { 7 | if (!needle.length) { 8 | return 0; 9 | } 10 | for (let i = 0; i < haystack.length; i++) { 11 | let j = 0; 12 | while (i + j < haystack.length && haystack[i + j] === needle[j]) { 13 | j += 1; 14 | } 15 | if (j === needle.length) return i; 16 | } 17 | return -1; 18 | }; 19 | -------------------------------------------------------------------------------- /src/leetcode/increasing-subsequences/submit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/increasing-subsequences/submit.png -------------------------------------------------------------------------------- /src/leetcode/increasing-triplet-subsequence/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | Similar to longest increasing subsequence. Maintain an array during iteration. 6 | 7 | If num is greater than the last element, push it to last. 8 | If num is smaller or equal to the first element, replace the first. 9 | If num is smaller or equal to the second element, replace the second. 10 | -------------------------------------------------------------------------------- /src/leetcode/increasing-triplet-subsequence/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {boolean} 4 | */ 5 | var increasingTriplet = function(nums) { 6 | const arr = []; 7 | for (const num of nums) { 8 | if (!arr.length || num > arr[arr.length - 1]) { 9 | arr.push(num); 10 | } else if (num <= arr[0]) { 11 | arr[0] = num; 12 | } else if (num <= arr[1]) { 13 | arr[1] = num; 14 | } 15 | if (arr.length >= 3) { 16 | return true; 17 | } 18 | } 19 | return false; 20 | }; 21 | -------------------------------------------------------------------------------- /src/leetcode/insert-delete-getrandom-o1-duplicates-allowed/381. Insert Delete GetRandom O(1) - Duplicates allowed.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/insert-delete-getrandom-o1-duplicates-allowed/381. Insert Delete GetRandom O(1) - Duplicates allowed.pdf -------------------------------------------------------------------------------- /src/leetcode/insert-interval/57. Insert Interval.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/insert-interval/57. Insert Interval.pdf -------------------------------------------------------------------------------- /src/leetcode/insertion-sort-list/147. Insertion Sort List.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/insertion-sort-list/147. Insertion Sort List.pdf -------------------------------------------------------------------------------- /src/leetcode/integer-to-roman/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | Create a map sorted from greatest to least. Also need to include edge cases. 6 | 7 | ex: 8 | 9 | ``` 10 | I can be placed before V (5) and X (10) to make 4 and 9. 11 | ``` 12 | 13 | ```js 14 | ['IX', 9]; 15 | ``` 16 | 17 | ```js 18 | ['IV', 4], 19 | ``` 20 | 21 | Iterate over map. For each iteration, we try to use the current value as much as possible. For each usage, we append the corresponding symbol to the output. 22 | -------------------------------------------------------------------------------- /src/leetcode/interleaving-string/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ``` 4 | aa bc c 5 | d bbc a 6 | aad bbc bc a c 7 | ``` 8 | 9 | ```js 10 | dp[i][j] = 11 | (s1[i - 1] === s3[i + j - 1] && dp[i - 1][j]) || (s2[j - 1] === s3[i + j - 1] && dp[i][j - 1]); 12 | dp[0][j] = s2.substring(0, j) === s3.substring(0, j); 13 | dp[i][0] = s1.substring(0, i) === s3.substring(0, i); 14 | ``` 15 | -------------------------------------------------------------------------------- /src/leetcode/intersection-of-two-linked-lists/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * function ListNode(val) { 4 | * this.val = val; 5 | * this.next = null; 6 | * } 7 | */ 8 | 9 | /** 10 | * @param {ListNode} headA 11 | * @param {ListNode} headB 12 | * @return {ListNode} 13 | */ 14 | var getIntersectionNode = function(headA, headB) { 15 | let ptr1 = headA; 16 | let ptr2 = headB; 17 | while (ptr1 !== ptr2) { 18 | ptr1 = ptr1 ? ptr1.next : headB; 19 | ptr2 = ptr2 ? ptr2.next : headA; 20 | } 21 | return ptr1; 22 | }; 23 | -------------------------------------------------------------------------------- /src/leetcode/invert-binary-tree/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * function TreeNode(val) { 4 | * this.val = val; 5 | * this.left = this.right = null; 6 | * } 7 | */ 8 | /** 9 | * @param {TreeNode} root 10 | * @return {TreeNode} 11 | */ 12 | var invertTree = function(root) { 13 | if (!root) { 14 | return root; 15 | } 16 | [root.left, root.right] = [root.right, root.left]; 17 | invertTree(root.left); 18 | invertTree(root.right); 19 | return root; 20 | }; 21 | -------------------------------------------------------------------------------- /src/leetcode/is-graph-bipartite/Is graph bipartite.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/is-graph-bipartite/Is graph bipartite.pdf -------------------------------------------------------------------------------- /src/leetcode/is-subsequence/recursive.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} s 3 | * @param {string} t 4 | * @return {boolean} 5 | */ 6 | var isSubsequence = function(s, t, sStart = 0, tStart = 0) { 7 | for (let i = tStart; i < t.length; i++) { 8 | if (s[sStart] === t[i]) { 9 | return isSubsequence(s, t, sStart + 1, i + 1); 10 | } 11 | } 12 | return sStart >= s.length; 13 | }; 14 | -------------------------------------------------------------------------------- /src/leetcode/is-subsequence/two-ptrs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} s 3 | * @param {string} t 4 | * @return {boolean} 5 | */ 6 | var isSubsequence = function(s, t) { 7 | let i = 0; 8 | for (let j = 0; j < t.length; j++) { 9 | if (s[i] === t[j]) { 10 | i += 1; 11 | } 12 | } 13 | return i >= s.length; 14 | }; 15 | -------------------------------------------------------------------------------- /src/leetcode/isomorphic-strings/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} s 3 | * @param {string} t 4 | * @return {boolean} 5 | */ 6 | var isIsomorphic = function(s, t) { 7 | const map = {}; 8 | const visited = new Set(); 9 | for (let i = 0; i < s.length; i++) { 10 | if ((!(s[i] in map) && visited.has(t[i])) || (s[i] in map && map[s[i]] !== t[i])) { 11 | return false; 12 | } 13 | map[s[i]] = t[i]; 14 | visited.add(t[i]); 15 | } 16 | return true; 17 | }; 18 | -------------------------------------------------------------------------------- /src/leetcode/jewels-and-stones/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} J 3 | * @param {string} S 4 | * @return {number} 5 | */ 6 | var numJewelsInStones = function(J, S) { 7 | if (!J.length || !S.length) return 0; 8 | const hash = {}; 9 | for (let i = 0; i < J.length; i++) { 10 | hash[J[i]] = true; 11 | } 12 | let count = 0; 13 | for (let i = 0; i < S.length; i++) { 14 | if (hash[S[i]]) { 15 | count += 1; 16 | } 17 | } 18 | return count; 19 | }; 20 | -------------------------------------------------------------------------------- /src/leetcode/jump-game-ii/45. Jump Game II.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/jump-game-ii/45. Jump Game II.pdf -------------------------------------------------------------------------------- /src/leetcode/jump-game-ii/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number} 4 | */ 5 | var jump = function(nums) { 6 | let end = 0; 7 | let fartest = 0; 8 | let nSteps = 0; 9 | for (let i = 0; i < nums.length - 1; i++) { 10 | fartest = Math.max(fartest, i + nums[i]); 11 | if (i === end) { 12 | end = fartest; 13 | nSteps += 1; 14 | } 15 | } 16 | return nSteps; 17 | }; 18 | -------------------------------------------------------------------------------- /src/leetcode/jump-game/55. Jump Game.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/jump-game/55. Jump Game.pdf -------------------------------------------------------------------------------- /src/leetcode/jump-game/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {boolean} 4 | */ 5 | var canJump = function(nums) { 6 | let f = 0; 7 | for (let i = 0; i < nums.length; i++) { 8 | if (f >= i) { 9 | f = Math.max(f, i + nums[i]); 10 | } 11 | } 12 | return f >= nums.length - 1; 13 | }; 14 | -------------------------------------------------------------------------------- /src/leetcode/k-closest-points-to-origin/973. K Closest Points to Origin.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/k-closest-points-to-origin/973. K Closest Points to Origin.pdf -------------------------------------------------------------------------------- /src/leetcode/k-closest-points-to-origin/topk.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/k-closest-points-to-origin/topk.pdf -------------------------------------------------------------------------------- /src/leetcode/knight-dialer/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | Dynamic Programming 6 | 7 | dp stands for number of combinations with N digits at i 8 | 9 | recursion: 10 | 11 | ``` 12 | dp[N][i] = dp[N - 1][j], for j in neighbors 13 | ``` 14 | 15 | optimize with O(N) of space complexity 16 | 17 | ``` 18 | next[i] += pre[neighbor] for neighbor in neighbors 19 | ``` 20 | -------------------------------------------------------------------------------- /src/leetcode/knight-probability-in-chessboard/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | The probability of `k` steps at `(i, j)` is equal to the sum of `k - 1` steps at `(x, y)` where `(x, y)` is the position around `(i, j)`. 6 | 7 | ```js 8 | dp[k][i][j] = (() => { 9 | let p = 0; 10 | for (const [di, dj] of dirs) { 11 | const x = i + di; 12 | const y = j + dj; 13 | p += (dp[k - 1][x][y] * 1) / 8; 14 | } 15 | return p; 16 | })(); 17 | ``` 18 | -------------------------------------------------------------------------------- /src/leetcode/koko-eating-bananas/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} piles 3 | * @param {number} H 4 | * @return {number} 5 | */ 6 | var minEatingSpeed = function(piles, H) { 7 | let left = 0; 8 | let right = Math.max(...piles); 9 | while (left < right) { 10 | const mid = Math.floor((left + right) / 2); 11 | const sum = piles.reduce((acc, cur) => acc + Math.ceil(cur / mid), 0); 12 | if (sum > H) { 13 | left = mid + 1; 14 | } else { 15 | right = mid; 16 | } 17 | } 18 | return left; 19 | }; 20 | -------------------------------------------------------------------------------- /src/leetcode/kth-largest-element-in-an-array/README.md: -------------------------------------------------------------------------------- 1 | ## README 2 | 3 | ### Test Cases 4 | 5 | ``` 6 | [1,2,5,3,4], k = 3 7 | [5,(4),1,2,3] 8 | 9 | [1,4,5,3,2], k = 3 10 | [4,5,3,(2),1] 11 | 12 | [1,1,3,4,5,2] 13 | [3,4,5,1,1,2] 14 | [3,4,5,2,1,1] 15 | ``` 16 | -------------------------------------------------------------------------------- /src/leetcode/kth-largest-element-in-an-array/index.spec.js: -------------------------------------------------------------------------------- 1 | import fn from './index'; 2 | 3 | test('kth-largest-element-in-an-array', () => { 4 | const arr = [1, 2, 3, 8, 4, 9, 7, 5]; 5 | const sortedArr = arr.slice().sort((a, b) => b - a); 6 | const k = 3; 7 | const result = fn(arr, 3); 8 | expect(result).toEqual(sortedArr[k - 1]); 9 | }); 10 | -------------------------------------------------------------------------------- /src/leetcode/kth-smallest-element-in-a-sorted-matrix/378. Kth Smallest Element in a Sorted Matrix.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/kth-smallest-element-in-a-sorted-matrix/378. Kth Smallest Element in a Sorted Matrix.pdf -------------------------------------------------------------------------------- /src/leetcode/largest-rectangle-in-histogram/Largest Rectangle in Histogram 3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/largest-rectangle-in-histogram/Largest Rectangle in Histogram 3.pdf -------------------------------------------------------------------------------- /src/leetcode/last-substring-in-lexicographical-order/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} s 3 | * @return {string} 4 | */ 5 | var lastSubstring = function(s) { 6 | let max = ''; 7 | for (let i = 0; i < s.length; i++) { 8 | if (s.substring(i) > max) { 9 | max = s.substring(i); 10 | } 11 | } 12 | return max; 13 | }; 14 | -------------------------------------------------------------------------------- /src/leetcode/length-of-last-word/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} s 3 | * @return {number} 4 | */ 5 | var lengthOfLastWord = function(s) { 6 | let lastWord = ''; 7 | for (const word of s.split(' ')) { 8 | if (word.length) { 9 | lastWord = word; 10 | } 11 | } 12 | return lastWord.length; 13 | }; 14 | -------------------------------------------------------------------------------- /src/leetcode/license-key-formatting/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} S 3 | * @param {number} K 4 | * @return {string} 5 | */ 6 | var licenseKeyFormatting = function(S, K) { 7 | const s = S.replace(/-/g, '').toUpperCase(); 8 | const output = []; 9 | const mod = s.length % K; 10 | for (let i = s.length - 1; i >= mod; i -= K) { 11 | output.push(s.slice(i - K + 1, i + 1)); 12 | } 13 | if (mod !== 0) { 14 | output.push(s.slice(0, mod)); 15 | } 16 | return output.reverse().join('-'); 17 | }; 18 | -------------------------------------------------------------------------------- /src/leetcode/linked-list-cycle/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * function ListNode(val) { 4 | * this.val = val; 5 | * this.next = null; 6 | * } 7 | */ 8 | 9 | /** 10 | * @param {ListNode} head 11 | * @return {boolean} 12 | */ 13 | var hasCycle = function(head) { 14 | let slow = head; 15 | let fast = head; 16 | while (slow && fast && fast.next) { 17 | slow = slow.next; 18 | fast = fast.next.next; 19 | if (slow === fast) { 20 | return true; 21 | } 22 | } 23 | return false; 24 | }; 25 | -------------------------------------------------------------------------------- /src/leetcode/longest-absolute-file-path/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | Iterate over string. Each time, keep going until `\n` is met. In the process of iteration, we need to know the depth and name of that directory or file. And then keep popping out stack if `depth < stack.length`. Then put `name` into stack. Then we check if name is a file name. If so, we compute and update max value. 6 | -------------------------------------------------------------------------------- /src/leetcode/longest-arithmetic-sequence/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | - `dp[i][diff]` stands for length of longest arithmetic sequence ending at `i` with `diff`. Similar to LIS, we scan each elements before `i` to see if `diff` exists ending at `j`. If exists, extends `dp[j][diff]` by 1. 6 | - Since `diff` can be a very large number, we use an array of object to store diff as key. 7 | -------------------------------------------------------------------------------- /src/leetcode/longest-arithmetic-sequence/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} A 3 | * @return {number} 4 | */ 5 | var longestArithSeqLength = function(A) { 6 | const m = A.length; 7 | const dp = [...new Array(m)].map(() => ({})); 8 | let max = 2; 9 | for (let i = 0; i < m; i++) { 10 | for (let j = 0; j < i; j++) { 11 | const diff = A[i] - A[j]; 12 | dp[i][diff] = (dp[j][diff] || 1) + 1; 13 | max = Math.max(max, dp[i][diff]); 14 | } 15 | } 16 | return max; 17 | }; 18 | -------------------------------------------------------------------------------- /src/leetcode/longest-common-prefix/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string[]} strs 3 | * @return {string} 4 | */ 5 | var longestCommonPrefix = function(strs) { 6 | if (!strs.length) { 7 | return ''; 8 | } 9 | let prefix = strs[0]; 10 | for (const str of strs) { 11 | while (prefix !== str.substring(0, prefix.length)) { 12 | prefix = prefix.substring(0, prefix.length - 1); 13 | } 14 | } 15 | return prefix; 16 | }; 17 | -------------------------------------------------------------------------------- /src/leetcode/longest-common-subsequence/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | ```js 6 | dp[i][j] = (() => { 7 | if (text1[i - 1] === text2[j - 1]) { 8 | return dp[i - 1][j - 1] + 1; 9 | } 10 | return Math.max(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]); 11 | })(); 12 | ``` 13 | -------------------------------------------------------------------------------- /src/leetcode/longest-continuous-increasing-subsequence/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number} 4 | */ 5 | var findLengthOfLCIS = function(nums) { 6 | if (!nums.length) { 7 | return 0; 8 | } 9 | let n = 1; 10 | let max = n; 11 | for (let i = 1; i < nums.length; i++) { 12 | if (nums[i] > nums[i - 1]) { 13 | n += 1; 14 | } else { 15 | n = 1; 16 | } 17 | max = Math.max(max, n); 18 | } 19 | return max; 20 | }; 21 | -------------------------------------------------------------------------------- /src/leetcode/longest-palindrome/index.spec.js: -------------------------------------------------------------------------------- 1 | import fn from './index'; 2 | 3 | test('longest-palindrome', () => { 4 | expect(fn('ccc')).toEqual(3); 5 | }); 6 | 7 | test('longest-palindrome', () => { 8 | expect(fn('abccccdd')).toEqual(7); 9 | }); 10 | -------------------------------------------------------------------------------- /src/leetcode/longest-palindromic-subsequence/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | `dp[i][j]` stands for longest palindromic subsequence within substring `s[i:j]` 6 | 7 | ```js 8 | // prettier-ignore 9 | dp[i][j] = s[i] === s[j] 10 | ? dp[i + 1][j - 1] + 2 11 | : Math.max(dp[i][j - 1], dp[i + 1][j]); 12 | ``` 13 | -------------------------------------------------------------------------------- /src/leetcode/longest-repeating-character-replacement/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | ```js 6 | const window = 'AAABC'; 7 | ``` 8 | 9 | If a sliding window with `total length` = 5 and `max freq` = 3, then number of required operations to transform to repeating string is `total length - max freq`. 10 | 11 | So we can use a sliding window to keep tracking total length in sliding window and maximum frequency. 12 | -------------------------------------------------------------------------------- /src/leetcode/longest-string-chain/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | ``` 6 | dp[i] = max { 7 | dp[j] if words[i] is a predecessor of words[j] 8 | } 9 | ``` 10 | -------------------------------------------------------------------------------- /src/leetcode/longest-string-chain/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string[]} words 3 | * @return {number} 4 | */ 5 | var longestStrChain = function(words) { 6 | words.sort((a, b) => a.length - b.length); 7 | const dp = {}; 8 | let max = 1; 9 | for (const word of words) { 10 | dp[word] = 1; 11 | for (let i = 0; i < word.length; i++) { 12 | const predecessor = word.substring(0, i) + word.substring(i + 1); 13 | dp[word] = Math.max(dp[word], (dp[predecessor] || 0) + 1); 14 | } 15 | max = Math.max(max, dp[word]); 16 | } 17 | return max; 18 | }; 19 | -------------------------------------------------------------------------------- /src/leetcode/longest-substring-without-repeating-characters/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} s 3 | * @return {number} 4 | */ 5 | var lengthOfLongestSubstring = function(s) { 6 | const visited = new Set(); 7 | let start = 0; 8 | let max = 0; 9 | for (let i = 0; i < s.length; i++) { 10 | while (visited.has(s[i])) { 11 | visited.delete(s[start]); 12 | start += 1; 13 | } 14 | visited.add(s[i]); 15 | max = Math.max(max, i - start + 1); 16 | } 17 | return max; 18 | }; 19 | -------------------------------------------------------------------------------- /src/leetcode/longest-valid-parentheses/32. Longest Valid Parentheses.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/longest-valid-parentheses/32. Longest Valid Parentheses.pdf -------------------------------------------------------------------------------- /src/leetcode/majority-element/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number} 4 | */ 5 | var majorityElement = function(nums) { 6 | let el = nums[0]; 7 | let count = 1; 8 | for (let i = 1; i < nums.length; i++) { 9 | count += nums[i] === el ? 1 : -1; 10 | if (count === 0) { 11 | el = nums[i]; 12 | count = 1; 13 | } 14 | } 15 | return el; 16 | }; 17 | -------------------------------------------------------------------------------- /src/leetcode/majority-element/v1.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number} 4 | */ 5 | var majorityElement = function(nums) { 6 | const n = nums.length; 7 | let output = 0; 8 | for (let i = 0; i < 32; i++) { 9 | // prettier-ignore 10 | const nOnes = nums 11 | .map(num => (num >> i) & 1) 12 | .reduce((acc, cur) => acc + cur, 0) 13 | const isMajority = nOnes > n / 2; 14 | if (isMajority) { 15 | output = output | (2 ** i); 16 | } 17 | } 18 | return output; 19 | }; 20 | -------------------------------------------------------------------------------- /src/leetcode/max-chunks-to-make-sorted/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} arr 3 | * @return {number} 4 | */ 5 | var maxChunksToSorted = function(arr) { 6 | let nChunks = 0; 7 | for (let i = 0; i < arr.length; i++) { 8 | let max = arr[i]; 9 | while (max !== i && i < arr.length) { 10 | i += 1; 11 | max = Math.max(max, arr[i]); 12 | } 13 | nChunks += 1; 14 | } 15 | return nChunks; 16 | }; 17 | -------------------------------------------------------------------------------- /src/leetcode/max-consecutive-ones-ii/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | When flipping a zero, we connect previous and current consecutive one's. So to know the max consecutive one's, we only need to know previous and current one. So we use `pre` and `cur` to store the length of previous and current consecutive one's. We update pre and cur depending on `nums[i]`. And at the same time, we also update `max` value. 6 | 7 | - Note 8 | - We initialize `pre` with `-1`. So that if we never encounter `0`, `-1 + 1` will always be zero without affecting `max`. 9 | -------------------------------------------------------------------------------- /src/leetcode/max-consecutive-ones-ii/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number} 4 | */ 5 | var findMaxConsecutiveOnes = function(nums) { 6 | let pre = -1; 7 | let cur = 0; 8 | let max = 1; 9 | for (let i = 0; i < nums.length; i++) { 10 | if (nums[i] === 1) { 11 | cur += 1; 12 | } else { 13 | pre = cur; 14 | cur = 0; 15 | } 16 | max = Math.max(max, pre + 1 + cur); 17 | } 18 | return max; 19 | }; 20 | -------------------------------------------------------------------------------- /src/leetcode/max-consecutive-ones/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number} 4 | */ 5 | var findMaxConsecutiveOnes = function(nums) { 6 | let nConsecutiveOnes = nums[0]; 7 | let max = nConsecutiveOnes; 8 | for (let i = 1; i < nums.length; i++) { 9 | nConsecutiveOnes = nums[i] + (nums[i] === 1 && nums[i - 1] === 1 ? nConsecutiveOnes : 0); 10 | max = Math.max(max, nConsecutiveOnes); 11 | } 12 | return max; 13 | }; 14 | -------------------------------------------------------------------------------- /src/leetcode/max-points-on-a-line/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | - Iterate over combinations of any two points. Each iteration, we do followings: 6 | - Count nEquals 7 | - Count frequency of each slope 8 | - Summarize frequency and nEquals 9 | - `max = Math.max(max, 1 + maxFreq + nEquals)` 10 | - Note 11 | - For javascript, there is a division precision issue 12 | - http://adripofjavascript.com/blog/drips/avoiding-problems-with-decimal-math-in-javascript.html 13 | - To prevent the precision issue, multiply slope with a very large number 14 | -------------------------------------------------------------------------------- /src/leetcode/max-points-on-a-line/submit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/max-points-on-a-line/submit.png -------------------------------------------------------------------------------- /src/leetcode/maximum-69-number/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} num 3 | * @return {number} 4 | */ 5 | var maximum69Number = function(num) { 6 | const str = num + ''; 7 | for (let i = 0; i < str.length; i++) { 8 | if (str[i] === '6') { 9 | return parseInt(str.substring(0, i) + '9' + str.substring(i + 1)); 10 | } 11 | } 12 | return num; 13 | }; 14 | -------------------------------------------------------------------------------- /src/leetcode/maximum-length-of-repeated-subarray/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | ```js 6 | dp[i][j] = A[i - 1] === B[j - 1] ? dp[i - 1][j - 1] + 1 : 0; 7 | ``` 8 | 9 | Define `dp[i][j]` as repeated length containing last element with length `i, j`. 10 | 11 | So if `A[i - 1] === B[j - 1]`, extends length by 1, otherwise set to zero. 12 | 13 | It can be reduced to O(n) as: 14 | 15 | ```js 16 | next[j] = A[i - 1] === B[j - 1] ? dp[j - 1] + 1 : 0; 17 | ``` 18 | 19 | Time Complexity: O(mn) 20 | Space Complexity: O(n) 21 | -------------------------------------------------------------------------------- /src/leetcode/maximum-number-of-events-that-can-be-attended/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[][]} events 3 | * @return {number} 4 | */ 5 | var maxEvents = function(events) { 6 | events.sort((a, b) => (a[1] !== b[1] ? a[1] - b[1] : a[0] - b[0])); 7 | const visited = new Set(); 8 | let nEvents = 0; 9 | for (const [s, e] of events) { 10 | for (let i = s; i <= e; i++) { 11 | if (!visited.has(i)) { 12 | visited.add(i); 13 | nEvents += 1; 14 | break; 15 | } 16 | } 17 | } 18 | return nEvents; 19 | }; 20 | -------------------------------------------------------------------------------- /src/leetcode/maximum-product-subarray/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number} 4 | */ 5 | 6 | var maxProduct = function(nums) { 7 | let maxSoFar = 1; 8 | let minSoFar = 1; 9 | let max = -Infinity; 10 | for (const n of nums) { 11 | [maxSoFar, minSoFar] = [ 12 | Math.max(n, n * maxSoFar, n * minSoFar), 13 | Math.min(n, n * maxSoFar, n * minSoFar), 14 | ]; 15 | max = Math.max(max, maxSoFar); 16 | } 17 | return max; 18 | }; 19 | -------------------------------------------------------------------------------- /src/leetcode/maximum-product-subarray/index.spec.js: -------------------------------------------------------------------------------- 1 | import fn from './index'; 2 | 3 | test('maximum-product-subarray', () => { 4 | expect(fn([2, 3, -2, 4])).toEqual(6); 5 | }); 6 | -------------------------------------------------------------------------------- /src/leetcode/maximum-size-subarray-sum-equals-k/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @param {number} k 4 | * @return {number} 5 | */ 6 | var maxSubArrayLen = function(nums, k) { 7 | const map = { 0: -1 }; 8 | let max = 0; 9 | let sum = 0; 10 | for (let i = 0; i < nums.length; i++) { 11 | sum += nums[i]; 12 | if (sum - k in map) { 13 | max = Math.max(max, i - map[sum - k]); 14 | } 15 | if (!(sum in map)) { 16 | map[sum] = i; 17 | } 18 | } 19 | return max; 20 | }; 21 | -------------------------------------------------------------------------------- /src/leetcode/maximum-subarray-sum-with-one-deletion/1186. Maximum Subarray Sum with One Deletion.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/maximum-subarray-sum-with-one-deletion/1186. Maximum Subarray Sum with One Deletion.pdf -------------------------------------------------------------------------------- /src/leetcode/maximum-subarray-sum-with-one-deletion/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} arr 3 | * @return {number} 4 | */ 5 | var maximumSum = function(arr) { 6 | const m = arr.length; 7 | let dp = [-Infinity, -Infinity]; 8 | let max = -Infinity; 9 | for (let i = 1; i <= m; i++) { 10 | const next = [0, 0]; 11 | next[0] = Math.max(arr[i - 1] + dp[0], arr[i - 1]); 12 | next[1] = Math.max(arr[i - 1] + dp[1], arr[i - 1], dp[0]); 13 | dp = next; 14 | max = Math.max(max, ...dp); 15 | } 16 | return max; 17 | }; 18 | -------------------------------------------------------------------------------- /src/leetcode/maximum-subarray/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number} 4 | */ 5 | var maxSubArray = function(nums) { 6 | let max = -Infinity; 7 | let maxSoFar = max; 8 | for (const n of nums) { 9 | maxSoFar = Math.max(maxSoFar + n, n); 10 | max = Math.max(max, maxSoFar); 11 | } 12 | return max; 13 | }; 14 | -------------------------------------------------------------------------------- /src/leetcode/maximum-subarray/index.spec.js: -------------------------------------------------------------------------------- 1 | import fn from './index'; 2 | 3 | test('maximum-subarray', () => { 4 | expect(fn([-2, 1, -3, 4, -1, 2, 1, -5, 4])).toEqual(6); 5 | }); 6 | -------------------------------------------------------------------------------- /src/leetcode/maximum-sum-circular-subarray/918. Maximum Sum Circular Subarray.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/maximum-sum-circular-subarray/918. Maximum Sum Circular Subarray.pdf -------------------------------------------------------------------------------- /src/leetcode/maximum-sum-of-3-non-overlapping-subarrays/689. Maximum Sum of 3 Non-Overlapping Subarrays.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/maximum-sum-of-3-non-overlapping-subarrays/689. Maximum Sum of 3 Non-Overlapping Subarrays.pdf -------------------------------------------------------------------------------- /src/leetcode/maximum-swap/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | # Algorithm 4 | 5 | Starting from the beginning, search for the element that is: 6 | 7 | - Greater than `num[i]` 8 | - Existing in `map` 9 | - `j` > `i` 10 | 11 | And then swap `num[i]` with `num[j]`. 12 | -------------------------------------------------------------------------------- /src/leetcode/maximum-vacation-days/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | Define `dp[i][p]` as maximum value at `ith` day at `pth` city. 6 | 7 | ```js 8 | dp[i][p] = Math.max( 9 | dp[i][p], 10 | dp[i - 1][q] + days[p][i] if (be able to stay at p) 11 | ) 12 | ``` 13 | 14 | So `dp[i][p]` is `dp[i - 1][q] + days[p][i]` if `p` is reachable from `q` for all `q`. 15 | -------------------------------------------------------------------------------- /src/leetcode/median-of-two-sorted-arrays/IMG_1777.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/median-of-two-sorted-arrays/IMG_1777.JPG -------------------------------------------------------------------------------- /src/leetcode/meeting-rooms-ii/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[][]} intervals 3 | * @return {number} 4 | */ 5 | var minMeetingRooms = function(intervals) { 6 | const timeline = []; 7 | for (const [s, e] of intervals) { 8 | timeline.push([s, 1]); 9 | timeline.push([e, -1]); 10 | } 11 | timeline.sort((a, b) => (a[0] !== b[0] ? a[0] - b[0] : a[1] - b[1])); 12 | let count = 0; 13 | let max = 0; 14 | for (const [t, delta] of timeline) { 15 | count += delta; 16 | max = Math.max(max, count); 17 | } 18 | return max; 19 | }; 20 | -------------------------------------------------------------------------------- /src/leetcode/merge-k-sorted-lists/screencapture-leetcode-submissions-detail-191108256-2018-11-23-01_51_44.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/merge-k-sorted-lists/screencapture-leetcode-submissions-detail-191108256-2018-11-23-01_51_44.png -------------------------------------------------------------------------------- /src/leetcode/min-cost-climbing-stairs/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} cost 3 | * @return {number} 4 | */ 5 | 6 | /* 7 | f(i) = Math.min( 8 | f(i - 2) + cost[i], 9 | f(i - 1) + cost[i], 10 | ) 11 | */ 12 | 13 | var minCostClimbingStairs = function(cost) { 14 | let x = cost[0]; 15 | let y = cost[1]; 16 | let output; 17 | cost.push(0); 18 | for (let i = 2; i < cost.length; i++) { 19 | output = Math.min(x, y) + cost[i]; 20 | x = y; 21 | y = output; 22 | } 23 | return output; 24 | }; 25 | -------------------------------------------------------------------------------- /src/leetcode/minimize-malware-spread/924. Minimize Malware Spread.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/minimize-malware-spread/924. Minimize Malware Spread.pdf -------------------------------------------------------------------------------- /src/leetcode/minimum-add-to-make-parentheses-valid/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} S 3 | * @return {number} 4 | */ 5 | var minAddToMakeValid = function(S) { 6 | let stack = 0; 7 | let nSteps = 0; 8 | for (let i = 0; i < S.length; i++) { 9 | if (S[i] === '(') { 10 | stack += 1; 11 | } else if (S[i] === ')') { 12 | if (!stack) { 13 | nSteps += 1; 14 | } else { 15 | stack -= 1; 16 | } 17 | } 18 | } 19 | return nSteps + stack; 20 | }; 21 | -------------------------------------------------------------------------------- /src/leetcode/minimum-area-rectangle/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | - Create a set to store all points. So that given (x, y), we can know if this point exists or not. 6 | - Iterate over combinations of two points representing diagonal points of the rectangle. 7 | - If rest of the two points exists in the set, we have found a rectangle. Then update min value. 8 | - Finally return min value. 9 | -------------------------------------------------------------------------------- /src/leetcode/minimum-depth-of-binary-tree/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * function TreeNode(val) { 4 | * this.val = val; 5 | * this.left = this.right = null; 6 | * } 7 | */ 8 | /** 9 | * @param {TreeNode} root 10 | * @return {number} 11 | */ 12 | var minDepth = function(root) { 13 | if (!root) { 14 | return 0; 15 | } 16 | const left = minDepth(root.left); 17 | const right = minDepth(root.right); 18 | if (left && right) { 19 | return Math.min(left, right) + 1; 20 | } 21 | return (left || right) + 1; 22 | }; 23 | -------------------------------------------------------------------------------- /src/leetcode/minimum-domino-rotations-for-equal-row/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | In the rotated result, all values must either be `A[0]` or `B[0]`. 6 | 7 | There are 4 possible combinations. So we compute all 4 combinations and take the minimum. 8 | 9 | - All `A` is equal to `A[0]` 10 | - All `A` is equal to `B[0]` 11 | - All `B` is equal to `A[0]` 12 | - All `B` is equal to `B[0]` 13 | 14 | `count` This function counts how many swaps are required to make all elements in first array equal to target. 15 | -------------------------------------------------------------------------------- /src/leetcode/minimum-falling-path-sum/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | Define `dp[i][j]` as path sum from first row sum up to `(i, j)`. So at `(i, j)`, the path can come from left, middle or right. 6 | 7 | ```js 8 | dp[i][j] = A[i][j] + Math.min(dp[i - 1][j - 1], dp[i - 1][j], dp[i - 1][j + 1]); 9 | ``` 10 | 11 | This formula takes `O(MN)` space. We can optimize it to use `O(N)` space. 12 | 13 | ```js 14 | next[j] = A[i][j] + Math.min(dp[j - 1], dp[j], dp[j + 1]); 15 | ``` 16 | -------------------------------------------------------------------------------- /src/leetcode/minimum-path-sum/index.spec.js: -------------------------------------------------------------------------------- 1 | import fn from './index'; 2 | 3 | test('minimum-path-sum', () => { 4 | expect(fn([[1, 3, 1], [1, 5, 1], [4, 2, 1]])).toEqual(7); 5 | }); 6 | -------------------------------------------------------------------------------- /src/leetcode/minimum-size-subarray-sum/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} s 3 | * @param {number[]} nums 4 | * @return {number} 5 | */ 6 | var minSubArrayLen = function(s, nums) { 7 | let sum = 0; 8 | let start = 0; 9 | let min = Infinity; 10 | for (let i = 0; i < nums.length; i++) { 11 | sum += nums[i]; 12 | while (sum >= s) { 13 | min = Math.min(min, i - start + 1); 14 | sum -= nums[start]; 15 | start += 1; 16 | } 17 | } 18 | return min < Infinity ? min : 0; 19 | }; 20 | -------------------------------------------------------------------------------- /src/leetcode/minimum-time-visiting-all-points/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[][]} points 3 | * @return {number} 4 | */ 5 | var minTimeToVisitAllPoints = function(points) { 6 | let sum = 0; 7 | for (let i = 1; i < points.length; i++) { 8 | sum += getTime(points[i - 1], points[i]); 9 | } 10 | return sum; 11 | }; 12 | 13 | function getTime([x1, y1], [x2, y2]) { 14 | return Math.max(Math.abs(x1 - x2), Math.abs(y1 - y2)); 15 | } 16 | -------------------------------------------------------------------------------- /src/leetcode/minimum-window-subsequence/727. Minimum Window Subsequence.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/minimum-window-subsequence/727. Minimum Window Subsequence.pdf -------------------------------------------------------------------------------- /src/leetcode/missing-number/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number} 4 | */ 5 | 6 | const swap = (arr, i, j) => { 7 | const tmp = arr[i]; 8 | arr[i] = arr[j]; 9 | arr[j] = tmp; 10 | }; 11 | 12 | var missingNumber = function(nums) { 13 | for (let i = 0; i < nums.length; i++) { 14 | while (nums[i] !== i && nums[i] !== undefined) { 15 | swap(nums, i, nums[i]); 16 | } 17 | } 18 | for (let i = 0; i < nums.length; i++) { 19 | if (nums[i] !== i) { 20 | return i; 21 | } 22 | } 23 | return nums.length; 24 | }; 25 | -------------------------------------------------------------------------------- /src/leetcode/monotonic-array/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} A 3 | * @return {boolean} 4 | */ 5 | var isMonotonic = function(A) { 6 | let delta = 0; 7 | for (let i = 0; i < A.length - 1; i++) { 8 | if ((delta > 0) & (A[i + 1] < A[i]) || (delta < 0 && A[i + 1] > A[i])) { 9 | return false; 10 | } 11 | if (delta === 0) { 12 | delta = A[i + 1] - A[i]; 13 | } 14 | } 15 | return true; 16 | }; 17 | -------------------------------------------------------------------------------- /src/leetcode/most-stones-removed-with-same-row-or-column/947. Most Stones Removed with Same Row or Column.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/most-stones-removed-with-same-row-or-column/947. Most Stones Removed with Same Row or Column.pdf -------------------------------------------------------------------------------- /src/leetcode/move-zeroes/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {void} Do not return anything, modify nums in-place instead. 4 | */ 5 | 6 | var moveZeroes = function(nums) { 7 | let j = 0; 8 | for (let i = 0; i < nums.length; i++) { 9 | if (nums[i] !== 0) { 10 | [nums[i], nums[j]] = [nums[j], nums[i]]; 11 | j++; 12 | } 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /src/leetcode/multiply-strings/index.spec.js: -------------------------------------------------------------------------------- 1 | import fn from './index'; 2 | 3 | test('multiply-strings', () => { 4 | expect(fn('111111', '11')).toEqual('1222221'); 5 | }); 6 | 7 | test('multiply-strings', () => { 8 | expect(fn('111111', '0')).toEqual('0'); 9 | }); 10 | 11 | test('multiply-strings', () => { 12 | expect(fn('999999999', '999999999')).toEqual('999999998000000001'); 13 | }); 14 | -------------------------------------------------------------------------------- /src/leetcode/my-calendar-i/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | Use an array to store sorted intervals. For each booking, use `upperBound` to search for interval with minimum start that is greater than input start time. Then we check if it's overlapped with any of `events[i - 1]` or `event[i]`. If it's overlapped, it's not bookable. Otherwise, it's bookable and insert interval at the index. 6 | -------------------------------------------------------------------------------- /src/leetcode/n-queens/N-Queens.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/n-queens/N-Queens.pdf -------------------------------------------------------------------------------- /src/leetcode/next-greater-element-i/496. Next Greater Element I.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/next-greater-element-i/496. Next Greater Element I.pdf -------------------------------------------------------------------------------- /src/leetcode/next-greater-element-i/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums1 3 | * @param {number[]} nums2 4 | * @return {number[]} 5 | */ 6 | var nextGreaterElement = function(nums1, nums2) { 7 | const stack = []; 8 | const map = {}; 9 | for (const i of nums2) { 10 | while (stack.length && i > stack[stack.length - 1]) { 11 | map[stack[stack.length - 1]] = i; 12 | stack.pop(); 13 | } 14 | stack.push(i); 15 | } 16 | return nums1.map((i) => (i in map ? map[i] : -1)); 17 | }; 18 | -------------------------------------------------------------------------------- /src/leetcode/next-greater-element-ii/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number[]} 4 | */ 5 | var nextGreaterElements = function(nums) { 6 | const stack = []; 7 | const map = {}; 8 | const m = nums.length; 9 | for (let i = 0; i < 2 * m; i++) { 10 | const num = nums[i % m]; 11 | while (stack.length && nums[stack[stack.length - 1]] < num) { 12 | map[stack.pop()] = num; 13 | } 14 | if (i < m) { 15 | stack.push(i); 16 | } 17 | } 18 | return nums.map((_, i) => (i in map ? map[i] : -1)); 19 | }; 20 | -------------------------------------------------------------------------------- /src/leetcode/next-permutation/Next Permutation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/next-permutation/Next Permutation.pdf -------------------------------------------------------------------------------- /src/leetcode/non-overlapping-intervals/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | First of all, sort intervals by start time. 6 | 7 | `pre` points to the previous interval that is not removed. 8 | `nRemoved` stores number of intervals to remove 9 | 10 | Iterate over intervals. 11 | 12 | If previous interval is overlapped with current one, increment `nRemoved` by one and preserve the one with earlier end time. That is, set `pre` to the one with earlier end time. 13 | 14 | Otherwise, set `pre` to current one. 15 | -------------------------------------------------------------------------------- /src/leetcode/number-of-burgers-with-no-waste-of-ingredients/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | ``` 6 | 4x + 2y = A 7 | x + y = B 8 | x = (A - 2B) / 2 9 | y = (4B - A) / 2 10 | ``` 11 | -------------------------------------------------------------------------------- /src/leetcode/number-of-burgers-with-no-waste-of-ingredients/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} tomatoSlices 3 | * @param {number} cheeseSlices 4 | * @return {number[]} 5 | */ 6 | var numOfBurgers = function(tomatoSlices, cheeseSlices) { 7 | const x = (tomatoSlices - 2 * cheeseSlices) / 2; 8 | const y = (4 * cheeseSlices - tomatoSlices) / 2; 9 | if (Number.isInteger(x) && x >= 0 && Number.isInteger(y) && y >= 0) { 10 | return [x, y]; 11 | } 12 | return []; 13 | }; 14 | -------------------------------------------------------------------------------- /src/leetcode/number-of-days-between-two-dates/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} date1 3 | * @param {string} date2 4 | * @return {number} 5 | */ 6 | var daysBetweenDates = function(date1, date2) { 7 | const t1 = new Date(date1).getTime(); 8 | const t2 = new Date(date2).getTime(); 9 | return Math.abs(t2 - t1) / (24 * 60 * 60 * 1000); 10 | }; 11 | -------------------------------------------------------------------------------- /src/leetcode/number-of-islands-ii/submit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/number-of-islands-ii/submit.png -------------------------------------------------------------------------------- /src/leetcode/number-of-operations-to-make-network-connected/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | If there are n computers, it only requires n - 1 edges to make it connected. So if there are more than n - 1 edges, it must be able to make it connected. 6 | 7 | Use DFS to find number of groups. To connect those disconnected groups, it requires (number of groups - 1) moves. 8 | -------------------------------------------------------------------------------- /src/leetcode/number-of-subarrays-with-bounded-maximum/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | Number of subarrays between [L, R] is equal to `number of subarrays less than R` - `number of subarrays less than L`. 6 | -------------------------------------------------------------------------------- /src/leetcode/number-of-subarrays-with-bounded-maximum/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} A 3 | * @param {number} L 4 | * @param {number} R 5 | * @return {number} 6 | */ 7 | var numSubarrayBoundedMax = function(A, L, R) { 8 | return count(A, R) - count(A, L - 1); 9 | }; 10 | 11 | function count(arr, max) { 12 | let output = 0; 13 | let nTarget = 0; 14 | for (const num of arr) { 15 | nTarget = num <= max ? nTarget + 1 : 0; 16 | output += nTarget; 17 | } 18 | return output; 19 | } 20 | -------------------------------------------------------------------------------- /src/leetcode/number-of-submatrices-that-sum-to-target/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | Use `left` and `right` to find all combinations of columns. That is, `left` starts from `0 ~ n`. `right` starts from `left ~ n`. So that it will start from any position and with any width. For each fixed width, we store the sum in each row between column `left` and `right` to `arr[i]`. Then we can use 1-D subarray sum equals to target technique to count how many submatrix sum equals to target. 6 | 7 | Time Complexity: O(n\*\*3) 8 | Space Complexity: O(n) 9 | -------------------------------------------------------------------------------- /src/leetcode/number-of-valid-subarrays/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number} 4 | */ 5 | var validSubarrays = function(nums) { 6 | const stack = []; 7 | let count = 0; 8 | for (const num of nums) { 9 | while (stack.length && num < stack[stack.length - 1]) { 10 | count += stack.length; 11 | stack.pop(); 12 | } 13 | stack.push(num); 14 | } 15 | while (stack.length) { 16 | count += stack.length; 17 | stack.pop(); 18 | } 19 | return count; 20 | }; 21 | -------------------------------------------------------------------------------- /src/leetcode/one-edit-distance/README.md: -------------------------------------------------------------------------------- 1 | ## README 2 | 3 | ### Algorithm 4 | 5 | ``` 6 | s | t 7 | insert: ab acb 8 | delete: acb ab 9 | replace: abc adc 10 | ``` 11 | 12 | - If difference in length is greater than 1, return false. 13 | - Iterate over s and t, find out the first different character. 14 | - If `t.length > s.length`, insert a character to s at `i` and compare with t. 15 | - If `s.length > t.length`, delete a character from s at `i` and compare with t. 16 | - If `s.length === t.length`, replace a character in s at `i` and compare with t. 17 | -------------------------------------------------------------------------------- /src/leetcode/paint-fence/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} n 3 | * @param {number} k 4 | * @return {number} 5 | */ 6 | var numWays = function(n, k) { 7 | const dp = [0, k, k * k]; 8 | if (n <= 2) { 9 | return dp[n]; 10 | } 11 | for (let i = 3; i <= n; i++) { 12 | const result = dp[1] * (k - 1) + dp[2] * (k - 1); 13 | [dp[0], dp[1], dp[2]] = [dp[1], dp[2], result]; 14 | } 15 | return dp[2]; 16 | }; 17 | -------------------------------------------------------------------------------- /src/leetcode/palindrome-linked-list/README.md: -------------------------------------------------------------------------------- 1 | ## README 2 | 3 | ### Algorithm 4 | 5 | - Split the list into two with equal length 6 | - Reverse the left of the list during the process 7 | - Compare the two lists for equality. They should be equal if it's a palindrome. 8 | -------------------------------------------------------------------------------- /src/leetcode/palindrome-number/9. Palindrome Number.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/palindrome-number/9. Palindrome Number.pdf -------------------------------------------------------------------------------- /src/leetcode/palindrome-number/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} x 3 | * @return {boolean} 4 | */ 5 | var isPalindrome = function(x) { 6 | if (x < 0) return false; 7 | let y = x; 8 | let n = 0; 9 | while (y) { 10 | n = n * 10 + (y % 10); 11 | y = Math.floor(y / 10); 12 | } 13 | return n === x; 14 | }; 15 | -------------------------------------------------------------------------------- /src/leetcode/palindrome-permutation/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} s 3 | * @return {boolean} 4 | */ 5 | var canPermutePalindrome = function(s) { 6 | const freq = {}; 7 | for (const c of s) { 8 | freq[c] = (freq[c] || 0) + 1; 9 | } 10 | let nOdds = 0; 11 | for (const c in freq) { 12 | if (freq[c] % 2 === 1) { 13 | nOdds += 1; 14 | } 15 | if (nOdds > 1) { 16 | return false; 17 | } 18 | } 19 | return true; 20 | }; 21 | -------------------------------------------------------------------------------- /src/leetcode/pancake-sorting/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | ``` 6 | A[i] is a permutation of [1, 2, ..., A.length] 7 | ``` 8 | 9 | We iterate starting from A.length to 1. For each time, if i is not on its position, we reverse array to make i to A[0], then reverse array to make it to its corresponding position. 10 | -------------------------------------------------------------------------------- /src/leetcode/partition-array-into-disjoint-intervals/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} A 3 | * @return {number} 4 | */ 5 | var partitionDisjoint = function(A) { 6 | const partition = { max: A[0], index: 0 }; 7 | let max = A[0]; 8 | for (let i = 1; i < A.length; i++) { 9 | max = Math.max(max, A[i]); 10 | if (A[i] < partition.max) { 11 | partition.max = max; 12 | partition.index = i; 13 | } 14 | } 15 | return partition.index + 1; 16 | }; 17 | -------------------------------------------------------------------------------- /src/leetcode/partition-labels/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} S 3 | * @return {number[]} 4 | */ 5 | var partitionLabels = function(S) { 6 | const map = {}; 7 | for (let i = 0; i < S.length; i++) { 8 | map[S[i]] = i; 9 | } 10 | const output = []; 11 | let start = 0; 12 | let end = 0; 13 | for (let i = 0; i < S.length; i++) { 14 | end = Math.max(end, map[S[i]]); 15 | if (i === end) { 16 | output.push(i - start + 1); 17 | start = i + 1; 18 | } 19 | } 20 | return output; 21 | }; 22 | -------------------------------------------------------------------------------- /src/leetcode/pascals-triangle-ii/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} rowIndex 3 | * @return {number[]} 4 | */ 5 | /* 6 | f(i, j) = f(i - 1, j - 1) + f(i - 1, j) 7 | */ 8 | const getRow = function(rowIndex) { 9 | const output = new Array(rowIndex + 1).fill(0); 10 | output[0] = 1; 11 | for (let i = 1; i <= rowIndex; i++) { 12 | for (let j = i; j > 0; j--) { 13 | output[j] = (output[j - 1] || 0) + (output[j] || 0); 14 | } 15 | } 16 | return output; 17 | }; 18 | 19 | export default getRow; 20 | -------------------------------------------------------------------------------- /src/leetcode/pascals-triangle-ii/index.spec.js: -------------------------------------------------------------------------------- 1 | import fn from './index'; 2 | 3 | test('pascals-triangle-ii', () => { 4 | expect(fn(3)).toEqual([1, 3, 3, 1]); 5 | }); 6 | -------------------------------------------------------------------------------- /src/leetcode/pascals-triangle/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} numRows 3 | * @return {number[][]} 4 | */ 5 | const generate = function(numRows) { 6 | if (!numRows) { 7 | return []; 8 | } 9 | const output = new Array(numRows); 10 | output[0] = [1]; 11 | for (let i = 1; i < numRows; i++) { 12 | output[i] = new Array(i + 1).fill(0); 13 | for (let j = 0; j < i + 1; j++) { 14 | output[i][j] = (output[i - 1][j - 1] || 0) + (output[i - 1][j] || 0); 15 | } 16 | } 17 | return output; 18 | }; 19 | 20 | export default generate; 21 | -------------------------------------------------------------------------------- /src/leetcode/pascals-triangle/index.spec.js: -------------------------------------------------------------------------------- 1 | import fn from './index'; 2 | 3 | test('pascals-triangle', () => { 4 | expect(fn(5)).toEqual([ 5 | [1], 6 | [1, 1], 7 | [1, 2, 1], 8 | [1, 3, 3, 1], 9 | [1, 4, 6, 4, 1], 10 | ]); 11 | }); 12 | -------------------------------------------------------------------------------- /src/leetcode/peak-index-in-a-mountain-array/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} A 3 | * @return {number} 4 | */ 5 | var peakIndexInMountainArray = function(A) { 6 | let left = 0; 7 | let right = A.length; 8 | while (left < right) { 9 | const mid = Math.floor((left + right) / 2); 10 | if (A[mid] < A[mid + 1]) { 11 | left = mid + 1; 12 | } else { 13 | right = mid; 14 | } 15 | } 16 | return left; 17 | }; 18 | -------------------------------------------------------------------------------- /src/leetcode/perfect-squares/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} n 3 | * @return {number} 4 | */ 5 | var numSquares = function(n) { 6 | const dp = new Array(n + 1).fill(0); 7 | dp[1] = 1; 8 | for (let i = 2; i <= n; i++) { 9 | dp[i] = helper(i, dp); 10 | } 11 | return dp[n]; 12 | }; 13 | 14 | function helper(i, dp) { 15 | let min = Infinity; 16 | let j = 1; 17 | while (i - j ** 2 >= 0) { 18 | min = Math.min(min, 1 + dp[i - j ** 2]); 19 | j += 1; 20 | } 21 | return min; 22 | } 23 | -------------------------------------------------------------------------------- /src/leetcode/perfect-squares/index.spec.js: -------------------------------------------------------------------------------- 1 | import fn from './index'; 2 | 3 | test('perfect-squares', () => { 4 | expect(fn(0)).toEqual(0); 5 | }); 6 | 7 | test('perfect-squares', () => { 8 | expect(fn(12)).toEqual(3); 9 | }); 10 | 11 | test('perfect-squares', () => { 12 | expect(fn(111)).toEqual(4); 13 | }); 14 | -------------------------------------------------------------------------------- /src/leetcode/permutations/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number[][]} 4 | */ 5 | var permute = function(nums, selected = new Set(), output = []) { 6 | if (selected.size === nums.length) { 7 | output.push([...selected].map((i) => nums[i])); 8 | return output; 9 | } 10 | for (let i = 0; i < nums.length; i++) { 11 | if (!selected.has(i)) { 12 | selected.add(i); 13 | permute(nums, selected, output); 14 | selected.delete(i); 15 | } 16 | } 17 | return output; 18 | }; 19 | -------------------------------------------------------------------------------- /src/leetcode/permutations/index.spec.js: -------------------------------------------------------------------------------- 1 | import fn from './index'; 2 | 3 | test('permutations', () => { 4 | expect(fn([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 | -------------------------------------------------------------------------------- /src/leetcode/plus-one/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} digits 3 | * @return {number[]} 4 | */ 5 | var plusOne = function(digits) { 6 | const output = []; 7 | let c = 1; 8 | let i = digits.length - 1; 9 | while (c || i >= 0) { 10 | const sum = (digits[i] || 0) + c; 11 | output.unshift(sum % 10); 12 | c = Math.floor(sum / 10); 13 | i -= 1; 14 | } 15 | return output; 16 | }; 17 | -------------------------------------------------------------------------------- /src/leetcode/populating-next-right-pointers-in-each-node-ii/117. Populating Next Right Pointers in Each Node II.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/populating-next-right-pointers-in-each-node-ii/117. Populating Next Right Pointers in Each Node II.pdf -------------------------------------------------------------------------------- /src/leetcode/populating-next-right-pointers-in-each-node/116. Populating Next Right Pointers in Each Node.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/populating-next-right-pointers-in-each-node/116. Populating Next Right Pointers in Each Node.pdf -------------------------------------------------------------------------------- /src/leetcode/power-of-two/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} n 3 | * @return {boolean} 4 | */ 5 | var isPowerOfTwo = function(n) { 6 | if (!n) { 7 | return false; 8 | } 9 | let nOnes = 0; 10 | let num = n; 11 | while (num) { 12 | nOnes += num & 1; 13 | num = num >> 1; 14 | if (nOnes >= 2) { 15 | return false; 16 | } 17 | } 18 | return true; 19 | }; 20 | -------------------------------------------------------------------------------- /src/leetcode/powx-n/50. Pow(x, n).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/powx-n/50. Pow(x, n).pdf -------------------------------------------------------------------------------- /src/leetcode/powx-n/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} x 3 | * @param {number} n 4 | * @return {number} 5 | */ 6 | const MIN = -(2 ** 31); 7 | 8 | var myPow = function(x, n) { 9 | if (x > 1 && n <= MIN) { 10 | return 0; 11 | } 12 | let p = x; 13 | let q = Math.abs(n); 14 | let output = 1; 15 | while (q > 0) { 16 | output = (q & 1) === 1 ? output * p : output; 17 | p = p * p; 18 | q = q >> 1; 19 | } 20 | return n >= 0 ? output : 1 / output; 21 | }; 22 | -------------------------------------------------------------------------------- /src/leetcode/powx-n/recursive.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} x 3 | * @param {number} n 4 | * @return {number} 5 | */ 6 | var myPow = function(x, n) { 7 | if (n === 0) { 8 | return 1; 9 | } 10 | if (n === 1) { 11 | return x; 12 | } 13 | const m = Math.abs(n); 14 | const p = Math.floor(m / 2); 15 | const val = myPow(x, p); 16 | const result = m % 2 === 1 ? x * val * val : val * val; 17 | return n > 0 ? result : 1 / result; 18 | }; 19 | -------------------------------------------------------------------------------- /src/leetcode/prison-cells-after-n-days/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} cells 3 | * @param {number} N 4 | * @return {number[]} 5 | */ 6 | var prisonAfterNDays = function(cells, N) { 7 | N = N % 14 > 0 ? N % 14 : 14; 8 | const m = cells.length; 9 | let arr = [...cells]; 10 | for (let i = 0; i < N; i++) { 11 | const next = new Array(m).fill(0); 12 | for (let j = 1; j < m - 1; j++) { 13 | next[j] = arr[j - 1] === arr[j + 1] ? 1 : 0; 14 | } 15 | arr = next; 16 | } 17 | return arr; 18 | }; 19 | -------------------------------------------------------------------------------- /src/leetcode/product-of-array-except-self/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number[]} 4 | */ 5 | var productExceptSelf = function(nums) { 6 | const output = new Array(nums.length).fill(1); 7 | let p = nums[0]; 8 | for (let i = 1; i < nums.length; i++) { 9 | output[i] *= p; 10 | p *= nums[i]; 11 | } 12 | p = nums[nums.length - 1]; 13 | for (let i = nums.length - 2; i >= 0; i--) { 14 | output[i] *= p; 15 | p *= nums[i]; 16 | } 17 | return output; 18 | }; 19 | -------------------------------------------------------------------------------- /src/leetcode/product-of-array-except-self/index.spec.js: -------------------------------------------------------------------------------- 1 | import fn from './index'; 2 | 3 | test('product-of-array-except-self', () => { 4 | expect(fn([1, 2, 3, 4])).toEqual([24, 12, 8, 6]); 5 | }); 6 | -------------------------------------------------------------------------------- /src/leetcode/queens-that-can-attack-the-king/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | Use BFS to search for the position of queens. There are 8 directions going out from king. For every direction, keep going until position is no longer valid or there exists a queen on the path. 6 | -------------------------------------------------------------------------------- /src/leetcode/random-pick-index/reservoir_sampling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/random-pick-index/reservoir_sampling.png -------------------------------------------------------------------------------- /src/leetcode/random-pick-with-weight/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | 1. Transform weights to accumulate sum. 4 | 2. Use lower bound to search for index. 5 | 6 | ex: 7 | 8 | ```js 9 | const weights = [3, 3, 3, 4]; 10 | const arr = [3, 6, 9, 13]; 11 | ``` 12 | 13 | So if `r = 12`, index will be 3. 14 | if `r = 7`, index will be 2. 15 | -------------------------------------------------------------------------------- /src/leetcode/range-sum-query-2d-immutable/304. Range Sum Query 2D - Immutable.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/range-sum-query-2d-immutable/304. Range Sum Query 2D - Immutable.pdf -------------------------------------------------------------------------------- /src/leetcode/range-sum-query-2d-mutable/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## References 4 | 5 | - http://bgmeow.xyz/2017/03/25/LeetCode-308/ 6 | -------------------------------------------------------------------------------- /src/leetcode/reaching-points/780. Reaching Points.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/reaching-points/780. Reaching Points.pdf -------------------------------------------------------------------------------- /src/leetcode/reconstruct-itinerary/332. Reconstruct Itinerary.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/reconstruct-itinerary/332. Reconstruct Itinerary.pdf -------------------------------------------------------------------------------- /src/leetcode/rectangle-overlap/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} rec1 3 | * @param {number[]} rec2 4 | * @return {boolean} 5 | */ 6 | var isRectangleOverlap = function(rec1, rec2) { 7 | const xOverlap = [Math.max(rec1[0], rec2[0]), Math.min(rec1[2], rec2[2])]; 8 | const yOverlap = [Math.max(rec1[1], rec2[1]), Math.min(rec1[3], rec2[3])]; 9 | return isValid(xOverlap) && isValid(yOverlap); 10 | }; 11 | 12 | function isValid([start, end]) { 13 | if (start >= end) { 14 | return false; 15 | } 16 | return true; 17 | } 18 | -------------------------------------------------------------------------------- /src/leetcode/regular-expression-matching/10. Regular Expression Matching.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/regular-expression-matching/10. Regular Expression Matching.pdf -------------------------------------------------------------------------------- /src/leetcode/remove-duplicates-from-sorted-array/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number} 4 | */ 5 | 6 | var removeDuplicates = function(nums) { 7 | let j = 1; 8 | for (let i = 1; i < nums.length; i++) { 9 | if (nums[i] !== nums[j - 1]) { 10 | [nums[i], nums[j]] = [nums[j], nums[i]]; 11 | j += 1; 12 | } 13 | } 14 | return j; 15 | }; 16 | -------------------------------------------------------------------------------- /src/leetcode/remove-duplicates-from-sorted-list/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * function ListNode(val) { 4 | * this.val = val; 5 | * this.next = null; 6 | * } 7 | */ 8 | /** 9 | * @param {ListNode} head 10 | * @return {ListNode} 11 | */ 12 | var deleteDuplicates = function(head) { 13 | if (!head) { 14 | return head; 15 | } 16 | let ptr = head.next; 17 | while (ptr && ptr.val === head.val) { 18 | ptr = ptr.next; 19 | } 20 | head.next = ptr; 21 | deleteDuplicates(ptr); 22 | return head; 23 | }; 24 | -------------------------------------------------------------------------------- /src/leetcode/remove-element/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @param {number} val 4 | * @return {number} 5 | */ 6 | var removeElement = function(nums, val) { 7 | let j = 0; 8 | for (let i = 0; i < nums.length; i++) { 9 | if (nums[i] !== val) { 10 | [nums[i], nums[j]] = [nums[j], nums[i]]; 11 | j += 1; 12 | } 13 | } 14 | return j; 15 | }; 16 | -------------------------------------------------------------------------------- /src/leetcode/remove-interval/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[][]} intervals 3 | * @param {number[]} toBeRemoved 4 | * @return {number[][]} 5 | */ 6 | var removeInterval = function(intervals, toBeRemoved) { 7 | const [rs, re] = toBeRemoved; 8 | const arr = []; 9 | for (const [s, e] of intervals) { 10 | if (e <= rs || s >= re) { 11 | arr.push([s, e]); 12 | } else { 13 | if (s < rs) { 14 | arr.push([s, rs]); 15 | } 16 | if (e > re) { 17 | arr.push([re, e]); 18 | } 19 | } 20 | } 21 | return arr; 22 | }; 23 | -------------------------------------------------------------------------------- /src/leetcode/remove-linked-list-elements/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * function ListNode(val) { 4 | * this.val = val; 5 | * this.next = null; 6 | * } 7 | */ 8 | /** 9 | * @param {ListNode} head 10 | * @param {number} val 11 | * @return {ListNode} 12 | */ 13 | var removeElements = function(head, val) { 14 | if (!head) { 15 | return head; 16 | } 17 | head.next = removeElements(head.next, val); 18 | return head.val !== val ? head : head.next; 19 | }; 20 | -------------------------------------------------------------------------------- /src/leetcode/remove-linked-list-elements/screencapture-leetcode-submissions-detail-192938904-2018-12-02-23_17_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/remove-linked-list-elements/screencapture-leetcode-submissions-detail-192938904-2018-12-02-23_17_08.png -------------------------------------------------------------------------------- /src/leetcode/remove-outermost-parentheses/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} S 3 | * @return {string} 4 | */ 5 | var removeOuterParentheses = function(S) { 6 | const stack = []; 7 | let output = ''; 8 | for (let i = 0; i < S.length; i++) { 9 | if (S[i] === '(') { 10 | stack.push(i); 11 | } else if (S[i] === ')') { 12 | const left = stack.pop(); 13 | if (!stack.length) { 14 | output += S.substring(left + 1, i); 15 | } 16 | } 17 | } 18 | return output; 19 | }; 20 | -------------------------------------------------------------------------------- /src/leetcode/remove-sub-folders-from-the-filesystem/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string[]} folder 3 | * @return {string[]} 4 | */ 5 | var removeSubfolders = function(folder) { 6 | folder.sort(); 7 | const output = []; 8 | let parent = null; 9 | for (const path of folder) { 10 | if (!path.startsWith(parent)) { 11 | output.push(path); 12 | parent = path + '/'; 13 | } 14 | } 15 | return output; 16 | }; 17 | -------------------------------------------------------------------------------- /src/leetcode/repeated-substring-pattern/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} s 3 | * @return {boolean} 4 | */ 5 | var repeatedSubstringPattern = function(s) { 6 | const m = s.length; 7 | for (let length = 1; length < m; length++) { 8 | const isDivisible = m % length === 0; 9 | const repeated = s.substring(0, length).repeat(m / length); 10 | if (isDivisible && repeated === s) { 11 | return true; 12 | } 13 | } 14 | return false; 15 | }; 16 | -------------------------------------------------------------------------------- /src/leetcode/restore-ip-addresses/93. Restore IP Addresses.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/restore-ip-addresses/93. Restore IP Addresses.pdf -------------------------------------------------------------------------------- /src/leetcode/reverse-integer/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} x 3 | * @return {number} 4 | */ 5 | 6 | const MAX = 2 ** 31 - 1; 7 | const MIN = -(2 ** 31); 8 | 9 | var reverse = function(x) { 10 | const sign = x < 0 ? -1 : 1; 11 | x = Math.abs(x); 12 | let output = 0; 13 | while (x > 0) { 14 | output = 10 * output + (x % 10); 15 | x = Math.floor(x / 10); 16 | const isOverflowed = output > MAX || output < MIN; 17 | if (isOverflowed) { 18 | return 0; 19 | } 20 | } 21 | return sign * output; 22 | }; 23 | -------------------------------------------------------------------------------- /src/leetcode/reverse-linked-list-ii/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | - find m - 1, n + 1 6 | - reverse m for n - m + 1 times 7 | - connect m - 1, reversed and n + 1 8 | -------------------------------------------------------------------------------- /src/leetcode/reverse-linked-list-ii/submission-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/reverse-linked-list-ii/submission-screenshot.png -------------------------------------------------------------------------------- /src/leetcode/reverse-linked-list/iterative.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * function ListNode(val) { 4 | * this.val = val; 5 | * this.next = null; 6 | * } 7 | */ 8 | /** 9 | * @param {ListNode} head 10 | * @return {ListNode} 11 | */ 12 | var reverseList = function(head) { 13 | let pre = null; 14 | let ptr = head; 15 | let next; 16 | while (ptr) { 17 | next = ptr.next; 18 | ptr.next = pre; 19 | pre = ptr; 20 | ptr = next; 21 | } 22 | return pre; 23 | }; 24 | -------------------------------------------------------------------------------- /src/leetcode/reverse-linked-list/recursive.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * function ListNode(val) { 4 | * this.val = val; 5 | * this.next = null; 6 | * } 7 | */ 8 | /** 9 | * @param {ListNode} head 10 | * @return {ListNode} 11 | */ 12 | var reverseList = function(head) { 13 | if (!head || !head.next) { 14 | return head; 15 | } 16 | const root = reverseList(head.next); 17 | head.next.next = head; 18 | head.next = null; 19 | return root; 20 | }; 21 | -------------------------------------------------------------------------------- /src/leetcode/reverse-nodes-in-k-group/screencapture-leetcode-submissions-detail-192938162-2018-12-02-23_09_39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/reverse-nodes-in-k-group/screencapture-leetcode-submissions-detail-192938162-2018-12-02-23_09_39.png -------------------------------------------------------------------------------- /src/leetcode/reverse-only-letters/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} S 3 | * @return {string} 4 | */ 5 | var reverseOnlyLetters = function(S) { 6 | let output = ''; 7 | let j = S.length - 1; 8 | for (let i = 0; i < S.length; i++) { 9 | if (!isLetter(S[i])) { 10 | output += S[i]; 11 | } else { 12 | while (!isLetter(S[j])) { 13 | j -= 1; 14 | } 15 | output += S[j]; 16 | j -= 1; 17 | } 18 | } 19 | return output; 20 | }; 21 | 22 | function isLetter(c) { 23 | return /[a-zA-Z]/.test(c); 24 | } 25 | -------------------------------------------------------------------------------- /src/leetcode/reverse-string/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} s 3 | * @return {string} 4 | */ 5 | var reverseString = function(s) { 6 | const output = []; 7 | for (let i = s.length - 1; i >= 0; i--) { 8 | output.push(s[i]); 9 | } 10 | return output.join(''); 11 | }; 12 | -------------------------------------------------------------------------------- /src/leetcode/robot-room-cleaner/489. Robot Room Cleaner.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/robot-room-cleaner/489. Robot Room Cleaner.pdf -------------------------------------------------------------------------------- /src/leetcode/roman-to-integer/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} s 3 | * @return {number} 4 | */ 5 | 6 | const map = { 7 | I: 1, 8 | V: 5, 9 | X: 10, 10 | L: 50, 11 | C: 100, 12 | D: 500, 13 | M: 1000, 14 | }; 15 | 16 | var romanToInt = function(s) { 17 | let output = 0; 18 | for (let i = 0; i < s.length; i++) { 19 | output += (() => { 20 | if (map[s[i]] >= (map[s[i + 1]] || 0)) { 21 | return map[s[i]]; 22 | } 23 | return -1 * map[s[i]]; 24 | })(); 25 | } 26 | return output; 27 | }; 28 | -------------------------------------------------------------------------------- /src/leetcode/rotate-image/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[][]} matrix 3 | * @return {void} Do not return anything, modify matrix in-place instead. 4 | */ 5 | var rotate = function(matrix) { 6 | matrix.reverse(); 7 | const n = matrix.length; 8 | for (let i = 0; i < n; i++) { 9 | for (let j = i + 1; j < n; j++) { 10 | [matrix[i][j], matrix[j][i]] = [matrix[j][i], matrix[i][j]]; 11 | } 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/leetcode/rotate-list/61. Rotate List.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/rotate-list/61. Rotate List.pdf -------------------------------------------------------------------------------- /src/leetcode/search-a-2d-matrix-ii/240. Search a 2D Matrix II.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/search-a-2d-matrix-ii/240. Search a 2D Matrix II.pdf -------------------------------------------------------------------------------- /src/leetcode/search-in-rotated-sorted-array-ii/81. Search in Rotated Sorted Array II.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/search-in-rotated-sorted-array-ii/81. Search in Rotated Sorted Array II.pdf -------------------------------------------------------------------------------- /src/leetcode/search-in-rotated-sorted-array/33. Search in Rotated Sorted Array.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/search-in-rotated-sorted-array/33. Search in Rotated Sorted Array.pdf -------------------------------------------------------------------------------- /src/leetcode/search-in-rotated-sorted-array/README.md: -------------------------------------------------------------------------------- 1 | ## README 2 | 3 | ### Test Cases 4 | 5 | ``` 6 | [4,5,6,7,0,1,2] // (4, 7) is sorted 7 | [6,7,0,1,2,4,5] // (1, 5) is sorted 8 | [0,1,2,4,5,6,7] // (0, 4) (4, 7) is sorted 9 | ``` 10 | 11 | There will always be one side sorted. So we can check if given target is in the range to include or exclude the range. 12 | 13 | ### Analysis 14 | 15 | Time Complexity: `O(log(N))` 16 | -------------------------------------------------------------------------------- /src/leetcode/search-insert-position/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @param {number} target 4 | * @return {number} 5 | */ 6 | var searchInsert = function(nums, target) { 7 | return lowerBound(nums, target); 8 | }; 9 | 10 | function lowerBound(arr, target) { 11 | let left = 0; 12 | let right = arr.length; 13 | while (left < right) { 14 | const mid = Math.floor((left + right) / 2); 15 | if (target > arr[mid]) { 16 | left = mid + 1; 17 | } else { 18 | right = mid; 19 | } 20 | } 21 | return left; 22 | } 23 | -------------------------------------------------------------------------------- /src/leetcode/sequential-digits/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | Use DFS to create numbers starting from the same digit until value is greater than high. 6 | 7 | ex: `1`, `12`, `123` 8 | -------------------------------------------------------------------------------- /src/leetcode/serialize-and-deserialize-bst/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | Comparing to serializing Binary Tree, we can ignore `null` value in serializing Binary Search Tree by giving boundary. 6 | 7 | ex: 8 | 9 | ```js 10 | const serializedStr = [4, 2, 1, 6, 5, 7]; 11 | ``` 12 | 13 | This is the serialized data of binary search tree. When constructing tree rooted at value 2, we give it boundary `min = -Infinity` and `max = 4`. So that we know value 6 does not belong to it. We can return null. 14 | -------------------------------------------------------------------------------- /src/leetcode/set-matrix-zeroes/73. Set Matrix Zeroes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/set-matrix-zeroes/73. Set Matrix Zeroes.pdf -------------------------------------------------------------------------------- /src/leetcode/shortest-path-to-get-all-keys/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | Similar to `shortest-path-in-a-grid-with-obstacles-elimination`. 6 | 7 | Main idea is to model state as (set of acquired keys, current position). Then, we can run a standard BFS. 8 | 9 | `dist[k][i][j]` means shortest path from some origin to `(i, j)` with keys selected encoded as k. 10 | -------------------------------------------------------------------------------- /src/leetcode/shortest-subarray-with-sum-at-least-k/README.md: -------------------------------------------------------------------------------- 1 | ## README 2 | 3 | ### Algorithm 4 | 5 |

 6 | 7 |

8 | 9 | ### Ref 10 | 11 | - Others include: 12 | 13 | ``` 14 | 496. Next Greater Element I 15 | 503. Next Greater Element II 16 | 84. Largest Rectangle in Histogram 17 | 122. Best Time to Buy and Sell Stock II 18 | 862. Shortest Subarray with Sum at Least K 19 | ``` 20 | -------------------------------------------------------------------------------- /src/leetcode/shortest-subarray-with-sum-at-least-k/algo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/shortest-subarray-with-sum-at-least-k/algo.jpg -------------------------------------------------------------------------------- /src/leetcode/shortest-way-to-form-string/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | ```js 6 | s = 'adcb'; 7 | t = 'abcdbca'; 8 | ('ab c db c a'); 9 | ``` 10 | 11 | - Iterate over target string. 12 | - For each time, we search for longest subsequence in source. 13 | -------------------------------------------------------------------------------- /src/leetcode/simplify-path/71. Simplify Path.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/simplify-path/71. Simplify Path.pdf -------------------------------------------------------------------------------- /src/leetcode/simplify-path/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} path 3 | * @return {string} 4 | */ 5 | var simplifyPath = function(path) { 6 | const paths = path.split('/'); 7 | const output = []; 8 | for (const p of paths) { 9 | if (p === '.' || p === '') { 10 | continue; 11 | } else if (p === '..') { 12 | output.pop(); 13 | } else { 14 | output.push(p); 15 | } 16 | } 17 | return '/' + output.join('/'); 18 | }; 19 | -------------------------------------------------------------------------------- /src/leetcode/single-element-in-a-sorted-array/submit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/single-element-in-a-sorted-array/submit.png -------------------------------------------------------------------------------- /src/leetcode/single-number-ii/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number} 4 | */ 5 | var singleNumber = function(nums) { 6 | let output = 0; 7 | for (let i = 0; i < 32; i++) { 8 | const sum = nums.reduce((acc, cur, j) => acc + ((cur >> i) & 1), 0); 9 | output = output | (sum % 3 << i); 10 | } 11 | return output; 12 | }; 13 | -------------------------------------------------------------------------------- /src/leetcode/single-number-iii/260. Single Number III.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/single-number-iii/260. Single Number III.pdf -------------------------------------------------------------------------------- /src/leetcode/single-number/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number} 4 | */ 5 | var singleNumber = function(nums) { 6 | return nums.reduce((acc, cur) => acc ^ cur, 0); 7 | }; 8 | -------------------------------------------------------------------------------- /src/leetcode/smallest-common-region/1257. Smallest Common Region.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/smallest-common-region/1257. Smallest Common Region.pdf -------------------------------------------------------------------------------- /src/leetcode/smallest-common-region/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | First of all, model the problem as a graph. So create a graph with each node point to its parent. 6 | 7 | ```js 8 | const graph = { 9 | 'North America': 'Earch', 10 | 'South America': 'Earch', 11 | // ...so on 12 | }; 13 | ``` 14 | 15 | Then we find lowest common ancestor of r1 and r2. 16 | 17 | 1. Start from r1 or r2 and record the path. 18 | 2. Start from r2 or r1. If intersection is found, it is the common ancestor. 19 | -------------------------------------------------------------------------------- /src/leetcode/smallest-range-i/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} A 3 | * @param {number} K 4 | * @return {number} 5 | */ 6 | const smallestRangeI = function(A, K) { 7 | A.sort((a, b) => a - b); 8 | const first = A[0]; 9 | const last = A[A.length - 1]; 10 | const diff = last - first; 11 | const diffWith2K = diff - 2 * K; 12 | return diffWith2K <= 0 ? 0 : diffWith2K; 13 | }; 14 | 15 | export default smallestRangeI; 16 | -------------------------------------------------------------------------------- /src/leetcode/smallest-range-i/index.spec.js: -------------------------------------------------------------------------------- 1 | import fn from './index'; 2 | 3 | test('smallest-range-i', () => { 4 | expect(fn([1, 3, 6], 3)).toEqual(0); 5 | }); 6 | -------------------------------------------------------------------------------- /src/leetcode/snapshot-array/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | ```js 6 | // prettier-ignore 7 | const arr = [ 8 | [[0, 0], [3, 2], [5, 0]], 9 | [[0, 0], [2, 1], [6, 10]], 10 | [[0, 0]], 11 | ] 12 | ``` 13 | 14 | For each position in the array, we store an array of `[snapId, val]`. 15 | 16 | set: 17 | Use `lowerBound` to find that at position `index`, is `snapId` exists ? 18 | If not, push `[snapId, val]` to that position. 19 | Else set `val` to it. 20 | 21 | get: 22 | Use `lowerBound` to find `snapId` that is equal to or greater than `snap_id`. 23 | -------------------------------------------------------------------------------- /src/leetcode/sort-array-by-parity/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} A 3 | * @return {number[]} 4 | */ 5 | 6 | const swap = (arr, i, j) => { 7 | const tmp = arr[i]; 8 | arr[i] = arr[j]; 9 | arr[j] = tmp; 10 | }; 11 | 12 | var sortArrayByParity = function(A) { 13 | let i = 0; 14 | let j = 0; 15 | while (i < A.length) { 16 | if (A[i] % 2 === 0) { 17 | swap(A, i, j); 18 | i += 1; 19 | j += 1; 20 | } else if (A[i] % 2 === 1) { 21 | i += 1; 22 | } 23 | } 24 | return A; 25 | }; 26 | -------------------------------------------------------------------------------- /src/leetcode/sparse-matrix-multiplication/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[][]} A 3 | * @param {number[][]} B 4 | * @return {number[][]} 5 | */ 6 | var multiply = function(A, B) { 7 | const m = A.length; 8 | const n = B[0].length; 9 | const output = [...new Array(m)].map(() => new Array(n).fill(0)); 10 | for (let i = 0; i < m; i++) { 11 | for (let j = 0; j < n; j++) { 12 | for (let k = 0; k < A[i].length; k++) { 13 | output[i][j] += A[i][k] * B[k][j]; 14 | } 15 | } 16 | } 17 | return output; 18 | }; 19 | -------------------------------------------------------------------------------- /src/leetcode/spiral-matrix/54. Spiral Matrix.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/spiral-matrix/54. Spiral Matrix.pdf -------------------------------------------------------------------------------- /src/leetcode/split-array-into-consecutive-subsequences/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ### Reference 4 | 5 | - [https://blog.csdn.net/sunday0904/article/details/78174122](https://blog.csdn.net/sunday0904/article/details/78174122) 6 | -------------------------------------------------------------------------------- /src/leetcode/split-array-largest-sum/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Reference 4 | 5 | - [https://blog.csdn.net/u014688145/article/details/69525838](https://blog.csdn.net/u014688145/article/details/69525838) 6 | -------------------------------------------------------------------------------- /src/leetcode/sqrtx/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} x 3 | * @return {number} 4 | */ 5 | var mySqrt = function(x) { 6 | let left = 1; 7 | let right = x; 8 | while (left <= right) { 9 | const mid = Math.floor((left + right) / 2); 10 | const sq = mid ** 2; 11 | if (sq === x) { 12 | return mid; 13 | } else if (sq > x) { 14 | right = mid - 1; 15 | } else if (sq < x) { 16 | left = mid + 1; 17 | } 18 | } 19 | return right; 20 | }; 21 | -------------------------------------------------------------------------------- /src/leetcode/sqrtx/index.spec.js: -------------------------------------------------------------------------------- 1 | import fn from './index'; 2 | 3 | test('sqrtx', () => { 4 | expect(fn(10)).toEqual(3); 5 | }); 6 | 7 | test('sqrtx', () => { 8 | expect(fn(9)).toEqual(3); 9 | }); 10 | 11 | test('sqrtx', () => { 12 | expect(fn(8)).toEqual(2); 13 | }); 14 | -------------------------------------------------------------------------------- /src/leetcode/squares-of-a-sorted-array/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} A 3 | * @return {number[]} 4 | */ 5 | var sortedSquares = function(A) { 6 | const output = []; 7 | let left = 0; 8 | let right = A.length - 1; 9 | while (left <= right) { 10 | const sLeft = A[left] ** 2; 11 | const sRight = A[right] ** 2; 12 | if (sLeft >= sRight) { 13 | output.push(sLeft); 14 | left += 1; 15 | } else { 16 | output.push(sRight); 17 | right -= 1; 18 | } 19 | } 20 | output.reverse(); 21 | return output; 22 | }; 23 | -------------------------------------------------------------------------------- /src/leetcode/stickers-to-spell-word/submit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/stickers-to-spell-word/submit.png -------------------------------------------------------------------------------- /src/leetcode/stream-of-characters/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | Create a trie containing reversed word of input words. Also maintain an input string containing all inputs. For each query, start from the last character of input, keep decreasing i if str[i:end] is a prefix. Finally return true if a word is found. 6 | -------------------------------------------------------------------------------- /src/leetcode/string-transforms-into-another-string/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} str1 3 | * @param {string} str2 4 | * @return {boolean} 5 | */ 6 | var canConvert = function(str1, str2) { 7 | if (str1 === str2) { 8 | return true; 9 | } 10 | const map = {}; 11 | for (let i = 0; i < str1.length; i++) { 12 | if (!(str1[i] in map)) { 13 | map[str1[i]] = str2[i]; 14 | } else if (map[str1[i]] !== str2[i]) { 15 | return false; 16 | } 17 | } 18 | return new Set(str2).size < 26; 19 | }; 20 | -------------------------------------------------------------------------------- /src/leetcode/student-attendance-record-i/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} s 3 | * @return {boolean} 4 | */ 5 | var checkRecord = function(s) { 6 | let nA = 0; 7 | for (let i = 0; i < s.length; i++) { 8 | if (s[i] === 'A') { 9 | nA += 1; 10 | } 11 | if ((i >= 2 && s[i - 2] === 'L' && s[i - 1] === 'L' && s[i] === 'L') || nA > 1) { 12 | return false; 13 | } 14 | } 15 | return true; 16 | }; 17 | -------------------------------------------------------------------------------- /src/leetcode/subarray-product-less-than-k/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @param {number} k 4 | * @return {number} 5 | */ 6 | var numSubarrayProductLessThanK = function(nums, k) { 7 | if (k <= 1) { 8 | return 0; 9 | } 10 | let start = 0; 11 | let product = 1; 12 | let count = 0; 13 | for (let i = 0; i < nums.length; i++) { 14 | product *= nums[i]; 15 | while (product >= k) { 16 | product /= nums[start]; 17 | start += 1; 18 | } 19 | count += i - start + 1; 20 | } 21 | return count; 22 | }; 23 | -------------------------------------------------------------------------------- /src/leetcode/subarray-sum-equals-k/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @param {number} k 4 | * @return {number} 5 | */ 6 | var subarraySum = function(nums, k) { 7 | const freq = { 0: 1 }; 8 | let output = 0; 9 | let sum = 0; 10 | for (const num of nums) { 11 | sum += num; 12 | output += freq[sum - k] || 0; 13 | freq[sum] = (freq[sum] || 0) + 1; 14 | } 15 | return output; 16 | }; 17 | -------------------------------------------------------------------------------- /src/leetcode/subarray-sums-divisible-by-k/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | `prefixSum(i, j) = sum[j] - sum[i - 1]` 6 | 7 | If `prefixSum(i, j)` is divisible by k, then `sum[j]` and `sum[i - 1]` should have the same reminder. So that reminder can be removed. `sum[j]` is the prefix sum so far. So in the process of iteration, we keep a map of how many prefix sums have the same reminder. So for the current position, we calculate reminder and increment n by how many prefix sum prior to `i` have the same reminder. 8 | -------------------------------------------------------------------------------- /src/leetcode/subarray-sums-divisible-by-k/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} A 3 | * @param {number} K 4 | * @return {number} 5 | */ 6 | var subarraysDivByK = function(A, K) { 7 | let n = 0; 8 | let sum = 0; 9 | const map = { 0: 1 }; 10 | for (const num of A) { 11 | sum += num; 12 | const r = sum % K >= 0 ? sum % K : (sum % K) + K; 13 | n += map[r] || 0; 14 | map[r] = (map[r] || 0) + 1; 15 | } 16 | return n; 17 | }; 18 | -------------------------------------------------------------------------------- /src/leetcode/subsets/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {number[][]} 4 | */ 5 | var subsets = function(nums, start = 0, selected = [], output = []) { 6 | output.push([...selected]); 7 | if (start >= nums.length) { 8 | return output; 9 | } 10 | for (let i = start; i < nums.length; i++) { 11 | if (nums[i] === nums[i - 1] && i !== start) { 12 | continue; 13 | } 14 | selected.push(nums[i]); 15 | subsets(nums, i + 1, selected, output); 16 | selected.pop(); 17 | } 18 | return output; 19 | }; 20 | -------------------------------------------------------------------------------- /src/leetcode/subtract-the-product-and-sum-of-digits-of-an-integer/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} n 3 | * @return {number} 4 | */ 5 | var subtractProductAndSum = function(n) { 6 | if (n === 0) { 7 | return 0; 8 | } 9 | let num = n; 10 | let product = 1; 11 | let sum = 0; 12 | while (num > 0) { 13 | const r = num % 10; 14 | product *= r; 15 | sum += r; 16 | num = Math.floor(num / 10); 17 | } 18 | return product - sum; 19 | }; 20 | -------------------------------------------------------------------------------- /src/leetcode/sum-of-distances-in-tree/834. Sum of Distances in Tree.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/sum-of-distances-in-tree/834. Sum of Distances in Tree.pdf -------------------------------------------------------------------------------- /src/leetcode/sum-root-to-leaf-numbers/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for a binary tree node. 3 | * function TreeNode(val) { 4 | * this.val = val; 5 | * this.left = this.right = null; 6 | * } 7 | */ 8 | /** 9 | * @param {TreeNode} root 10 | * @return {number} 11 | */ 12 | var sumNumbers = function(root, sum = 0) { 13 | if (!root) { 14 | return 0; 15 | } 16 | if (!root.left && !root.right) { 17 | return sum * 10 + root.val; 18 | } 19 | return sumNumbers(root.left, sum * 10 + root.val) + sumNumbers(root.right, sum * 10 + root.val); 20 | }; 21 | -------------------------------------------------------------------------------- /src/leetcode/summary-ranges/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {string[]} 4 | */ 5 | var summaryRanges = function(nums) { 6 | const output = []; 7 | for (let i = 0; i < nums.length; i++) { 8 | let j = i; 9 | while (j < nums.length && nums[j + 1] === nums[j] + 1) { 10 | j += 1; 11 | } 12 | const str = j > i ? nums[i] + '->' + nums[j] : nums[i] + ''; 13 | output.push(str); 14 | i = j; 15 | } 16 | return output; 17 | }; 18 | -------------------------------------------------------------------------------- /src/leetcode/swap-nodes-in-pairs/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Definition for singly-linked list. 3 | * function ListNode(val) { 4 | * this.val = val; 5 | * this.next = null; 6 | * } 7 | */ 8 | /** 9 | * @param {ListNode} head 10 | * @return {ListNode} 11 | */ 12 | var swapPairs = function(head) { 13 | if (!head || !head.next) { 14 | return head; 15 | } 16 | const newHead = head.next; 17 | const next = head.next.next; 18 | head.next.next = head; 19 | head.next = swapPairs(next); 20 | return newHead; 21 | }; 22 | -------------------------------------------------------------------------------- /src/leetcode/swim-in-rising-water/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | We maintain a `times` matrix representing minimum time required to visit `(i, j)`. And also maintaining a priority queue to always visiting the position with minimum time required first. 6 | 7 | So we start BFS from `(0, 0)` and follow positions with minimum time required. After breaking the loop, we check the minimum time of `times[m - 1][n - 1]`. 8 | -------------------------------------------------------------------------------- /src/leetcode/target-sum/recursive.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @param {number} S 4 | * @return {number} 5 | */ 6 | var findTargetSumWays = function(nums, S, i = 0, sum = 0) { 7 | if (i >= nums.length) { 8 | return sum === S ? 1 : 0; 9 | } 10 | return ( 11 | findTargetSumWays(nums, S, i + 1, sum + nums[i]) + 12 | findTargetSumWays(nums, S, i + 1, sum - nums[i]) 13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /src/leetcode/target-sum/v1.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @param {number} S 4 | * @return {number} 5 | */ 6 | var findTargetSumWays = function(nums, S) { 7 | const m = nums.length; 8 | const n = 1000; 9 | let dp = {}; 10 | dp[nums[0]] = (dp[nums[0]] || 0) + 1; 11 | dp[-nums[0]] = (dp[-nums[0]] || 0) + 1; 12 | for (let i = 1; i < m; i++) { 13 | const next = {}; 14 | for (let j = -n; j <= n; j++) { 15 | next[j] = (dp[j - nums[i]] || 0) + (dp[j + nums[i]] || 0); 16 | } 17 | dp = next; 18 | } 19 | return dp[S] || 0; 20 | }; 21 | -------------------------------------------------------------------------------- /src/leetcode/the-maze-iii/submit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/the-maze-iii/submit.png -------------------------------------------------------------------------------- /src/leetcode/the-skyline-problem/readme.md: -------------------------------------------------------------------------------- 1 | ## Idea 2 | 3 | 主要解題思想在於找到高度變化的地方。首先遍歷 `buildings`,將其轉換成 `x`, `y` 座標,並依 `x` 及 `y` 方向排序。接著從左向右遍歷各端點,在遍歷同時,會用到 `PriorityQueue` 來紀錄當前最高點。如果遇到左頂點,將其高度加入 `pq`,如果遇到右頂點,將其高度移除。每次操作完 `pq` 之後,可得其當下最高點,用當下最高點與前次最高點比較,若有出現高度變化,則找到 `key point`。 4 | -------------------------------------------------------------------------------- /src/leetcode/top-k-frequent-elements/index.spec.js: -------------------------------------------------------------------------------- 1 | import fn from './index'; 2 | 3 | test('top-k-frequent-elements', () => { 4 | const data = [[1, 1, 1, 2, 2, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5], 2]; 5 | const result = fn(...data); 6 | const expectedResult = [5, 4]; 7 | expect(result).toEqual(expectedResult); 8 | }); 9 | 10 | test('top-k-frequent-elements', () => { 11 | const data = [[-1, -1], 1]; 12 | const result = fn(...data); 13 | const expectedResult = [-1]; 14 | expect(result).toEqual(expectedResult); 15 | }); 16 | -------------------------------------------------------------------------------- /src/leetcode/top-k-frequent-words/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Approaches 4 | 5 | | Approach | Time Complexity | Space Complexity | 6 | | -------------- | --------------- | ---------------- | 7 | | quick select | O(n \* log(n)) | O(n) | 8 | | sort | O(n \* log(n)) | O(n) | 9 | | priority queue | O(n \* log(n)) | O(n) | 10 | | bucket sort | O(n) | O(n) | 11 | -------------------------------------------------------------------------------- /src/leetcode/total-hamming-distance/477. Total Hamming Distance.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/total-hamming-distance/477. Total Hamming Distance.pdf -------------------------------------------------------------------------------- /src/leetcode/tree-diameter/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Algorithm 4 | 5 | Do BFS starting from any node and we will reach a fartest node. Let's call it x. X is one of the end of the longest path. [Proof](https://stackoverflow.com/questions/20010472/proof-of-correctness-algorithm-for-diameter-of-a-tree-in-graph-theory) 6 | 7 | So we do BFS to find one end and do another BFS to find the other end and length. 8 | -------------------------------------------------------------------------------- /src/leetcode/two-sum-ii-input-array-is-sorted/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} numbers 3 | * @param {number} target 4 | * @return {number[]} 5 | */ 6 | var twoSum = function(nums, target) { 7 | let left = 0; 8 | let right = nums.length - 1; 9 | while (left < right) { 10 | const sum = nums[left] + nums[right]; 11 | if (sum === target) { 12 | return [left + 1, right + 1]; 13 | } else if (sum < target) { 14 | left += 1; 15 | } else if (sum > target) { 16 | right -= 1; 17 | } 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /src/leetcode/two-sum-ii-input-array-is-sorted/index.spec.js: -------------------------------------------------------------------------------- 1 | import fn from './index'; 2 | 3 | test('two-sum', () => { 4 | expect(fn([2, 7, 11, 15], 9)).toEqual([1, 2]); 5 | }); 6 | -------------------------------------------------------------------------------- /src/leetcode/two-sum/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @param {number} target 4 | * @return {number[]} 5 | */ 6 | var twoSum = function(nums, target) { 7 | const map = {}; 8 | for (let i = 0; i < nums.length; i++) { 9 | const num = nums[i]; 10 | if (target - num in map) { 11 | return [map[target - num], i]; 12 | } 13 | map[num] = i; 14 | } 15 | return []; 16 | }; 17 | -------------------------------------------------------------------------------- /src/leetcode/two-sum/index.spec.js: -------------------------------------------------------------------------------- 1 | import fn from './index'; 2 | 3 | test('two-sum', () => { 4 | expect(fn([2, 7, 11, 15], 9)).toEqual([0, 1]); 5 | }); 6 | -------------------------------------------------------------------------------- /src/leetcode/ugly-number/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} num 3 | * @return {boolean} 4 | */ 5 | var isUgly = function(num) { 6 | const factors = [2, 3, 5]; 7 | let n = num; 8 | for (const factor of factors) { 9 | while (n && n % factor === 0) { 10 | n /= factor; 11 | } 12 | } 13 | return n === 1; 14 | }; 15 | -------------------------------------------------------------------------------- /src/leetcode/unique-binary-search-trees/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} n 3 | * @return {number} 4 | */ 5 | var numTrees = function(n) { 6 | const dp = new Array(n + 1).fill(0); 7 | dp[0] = 1; 8 | dp[1] = 1; 9 | for (let i = 2; i <= n; i++) { 10 | for (let j = 0; j < i; j++) { 11 | dp[i] += dp[j] * dp[i - 1 - j]; 12 | } 13 | } 14 | return dp[n]; 15 | }; 16 | -------------------------------------------------------------------------------- /src/leetcode/unique-email-addresses/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string[]} emails 3 | * @return {number} 4 | */ 5 | var numUniqueEmails = function(emails) { 6 | const normalizedEmails = emails.map((email) => { 7 | const [local, domain] = email.split('@'); 8 | const normalizedLocal = local.split('+')[0].replace(/\./g, ''); 9 | return normalizedLocal + '@' + domain; 10 | }); 11 | return new Set(normalizedEmails).size; 12 | }; 13 | -------------------------------------------------------------------------------- /src/leetcode/unique-number-of-occurrences/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} arr 3 | * @return {boolean} 4 | */ 5 | var uniqueOccurrences = function(arr) { 6 | const freq = {}; 7 | for (const val of arr) { 8 | freq[val] = (freq[val] || 0) + 1; 9 | } 10 | return Object.keys(freq).length === new Set(Object.values(freq)).size; 11 | }; 12 | -------------------------------------------------------------------------------- /src/leetcode/unique-paths/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} m 3 | * @param {number} n 4 | * @return {number} 5 | */ 6 | var uniquePaths = function(m, n) { 7 | let dp = new Array(m).fill(1); 8 | for (let i = 1; i < n; i++) { 9 | const next = new Array(m).fill(1); 10 | for (let j = 0; j < m; j++) { 11 | next[j] = dp[j] + (j - 1 >= 0 ? next[j - 1] : 0); 12 | } 13 | dp = next; 14 | } 15 | return dp[m - 1]; 16 | }; 17 | -------------------------------------------------------------------------------- /src/leetcode/valid-palindrome-ii/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} s 3 | * @return {boolean} 4 | */ 5 | var validPalindrome = function(s, start = 0, end = s.length - 1, nDeletes = 1) { 6 | let i = start; 7 | let j = end; 8 | while (i < j) { 9 | if (s[i] !== s[j]) { 10 | return ( 11 | nDeletes > 0 && 12 | (validPalindrome(s, i + 1, j, nDeletes - 1) || validPalindrome(s, i, j - 1, nDeletes - 1)) 13 | ); 14 | } 15 | i += 1; 16 | j -= 1; 17 | } 18 | return true; 19 | }; 20 | -------------------------------------------------------------------------------- /src/leetcode/valid-parentheses/index.spec.js: -------------------------------------------------------------------------------- 1 | import fn from './index'; 2 | 3 | test('valid-parentheses', () => { 4 | expect(fn('{[]}')).toEqual(true); 5 | }); 6 | 7 | test('valid-parentheses', () => { 8 | expect(fn(')')).toEqual(false); 9 | }); 10 | 11 | test('valid-parentheses', () => { 12 | expect(fn('{')).toEqual(false); 13 | }); 14 | 15 | test('valid-parentheses', () => { 16 | expect(fn('(){}xxx{}')).toEqual(true); 17 | }); 18 | 19 | test('valid-parentheses', () => { 20 | expect(fn('')).toEqual(true); 21 | }); 22 | -------------------------------------------------------------------------------- /src/leetcode/valid-sudoku/36. Valid Sudoku.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/valid-sudoku/36. Valid Sudoku.pdf -------------------------------------------------------------------------------- /src/leetcode/validate-ip-address/Validate IP address.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/validate-ip-address/Validate IP address.pdf -------------------------------------------------------------------------------- /src/leetcode/verifying-an-alien-dictionary/README.md: -------------------------------------------------------------------------------- 1 | ## README 2 | 3 | ### Algorithm 4 | 5 | - Iterate over words. For each sibiling pairs, they should be sorted. So we can verify each pair. 6 | - Iterate over characters of the pair, find out the first character that is different. 7 | - If `words[i]` is shorter, it's valid. 8 | - If `words[i + 1]` is shorter, it's invalid. 9 | - If `words[i][j]` comes after words`[i + 1][j]`, it's invalid. 10 | -------------------------------------------------------------------------------- /src/leetcode/water-and-jug-problem/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} x 3 | * @param {number} y 4 | * @param {number} z 5 | * @return {boolean} 6 | */ 7 | var canMeasureWater = function(x, y, z) { 8 | if (x + y < z) { 9 | return false; 10 | } 11 | if (z === 0) { 12 | return true; 13 | } 14 | return z % gcd(x, y) === 0; 15 | }; 16 | 17 | function gcd(x, y) { 18 | if (y === 0) { 19 | return x; 20 | } 21 | return gcd(y, x % y); 22 | } 23 | -------------------------------------------------------------------------------- /src/leetcode/wildcard-matching/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/wildcard-matching/screenshot.png -------------------------------------------------------------------------------- /src/leetcode/word-break-ii/README.md: -------------------------------------------------------------------------------- 1 | ## README 2 | 3 | ### Algorithm 4 | 5 | ``` 6 | dp(i): is word breakable of s.slice(0, i) 7 | dp(i) = dp(i) || 8 | dp(i - wordDict[j].length) if wordDict[j] is a postfix of s.slice(0, i) for j in wordDict 9 | ``` 10 | -------------------------------------------------------------------------------- /src/leetcode/word-break-ii/index.spec.js: -------------------------------------------------------------------------------- 1 | import fn from './index'; 2 | 3 | test('word-break-ii', () => { 4 | expect(fn('aaaaaaa', ['aaa', 'aaaa'])).toEqual(['aaaa aaa', 'aaa aaaa']); 5 | }); 6 | 7 | test('word-break-ii', () => { 8 | expect(fn('pineapplepenapple', ['apple', 'pen', 'applepen', 'pine', 'pineapple'])).toEqual([ 9 | 'pine apple pen apple', 10 | 'pineapple pen apple', 11 | 'pine applepen apple', 12 | ]); 13 | }); 14 | -------------------------------------------------------------------------------- /src/leetcode/word-break/README.md: -------------------------------------------------------------------------------- 1 | ## README 2 | 3 | ### Algorithm 4 | 5 | ``` 6 | dp(i): is word breakable of s.slice(0, i) 7 | dp(i) = dp(i) || 8 | dp(i - wordDict[j].length) if wordDict[j] is a postfix of s.slice(0, i) for j in wordDict 9 | ``` 10 | 11 | ### Notes 12 | 13 | ```js 14 | if (dp[i]) break; // if dp[i] is already true, no need to try further 15 | ``` 16 | -------------------------------------------------------------------------------- /src/leetcode/word-break/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} s 3 | * @param {string[]} wordDict 4 | * @return {boolean} 5 | */ 6 | var wordBreak = function(s, wordDict) { 7 | const dp = new Array(s.length + 1).fill(false); 8 | dp[0] = true; 9 | for (let i = 1; i <= s.length; i++) { 10 | for (const word of wordDict) { 11 | if (s.substring(i - word.length, i) === word) { 12 | dp[i] |= dp[i - word.length]; 13 | } 14 | if (dp[i]) { 15 | break; 16 | } 17 | } 18 | } 19 | return dp[s.length]; 20 | }; 21 | -------------------------------------------------------------------------------- /src/leetcode/word-break/index.spec.js: -------------------------------------------------------------------------------- 1 | import fn from './index'; 2 | 3 | test('word-break', () => { 4 | expect(fn('dogs', ['dog', 's', 'gs'])).toEqual(true); 5 | }); 6 | 7 | test('word-break', () => { 8 | expect(fn('leetcode', ['leet', 'code'])).toEqual(true); 9 | }); 10 | 11 | test('word-break', () => { 12 | expect(fn('ab', ['a', 'b'])).toEqual(true); 13 | }); 14 | 15 | test('word-break', () => { 16 | expect(fn('applepenapple', ['apple', 'pen'])).toEqual(true); 17 | }); 18 | -------------------------------------------------------------------------------- /src/leetcode/word-break/screencapture-leetcode-submissions-detail-179481115-2018-09-30-19_28_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/word-break/screencapture-leetcode-submissions-detail-179481115-2018-09-30-19_28_02.png -------------------------------------------------------------------------------- /src/leetcode/zigzag-conversion/ZigZag Conversion2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/leetcode/zigzag-conversion/ZigZag Conversion2.pdf -------------------------------------------------------------------------------- /src/notes/assets/boxmodel.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/notes/assets/boxmodel.gif -------------------------------------------------------------------------------- /src/notes/assets/constructor-proto-chain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/notes/assets/constructor-proto-chain.png -------------------------------------------------------------------------------- /src/notes/assets/lower-bound-upper-bound.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/notes/assets/lower-bound-upper-bound.png -------------------------------------------------------------------------------- /src/notes/assets/speed-metrics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/notes/assets/speed-metrics.png -------------------------------------------------------------------------------- /src/practices/2018-11-24/quick-sort/index.spec.js: -------------------------------------------------------------------------------- 1 | import sort from './index'; 2 | 3 | test('sort', () => { 4 | const data = [1, 3, 6, 6, 2, 5, 8, 0, 5]; 5 | const result = sort(data); 6 | const expectedResult = [0, 1, 2, 3, 5, 5, 6, 6, 8]; 7 | expect(result).toEqual(expectedResult); 8 | }); 9 | 10 | test('sort', () => { 11 | expect(sort([0])).toEqual([0]); 12 | expect(sort([1, 6, 3])).toEqual([1, 3, 6]); 13 | expect(sort([1, 6, 3, 4])).toEqual([1, 3, 4, 6]); 14 | expect(sort([1, 6, 0, 3])).toEqual([0, 1, 3, 6]); 15 | }); 16 | -------------------------------------------------------------------------------- /src/practices/2019-03-25/bst/index.spec.js: -------------------------------------------------------------------------------- 1 | import BST from './index'; 2 | 3 | test('BST', () => { 4 | const bst = new BST(); 5 | const data = [4, 2, 1, 3, 6, 5, 7]; 6 | data.forEach((i) => bst.insert(i)); 7 | expect([...bst]).toEqual([1, 2, 3, 4, 5, 6, 7]); 8 | }); 9 | 10 | test('BST', () => { 11 | const bst = new BST(); 12 | const data = [4, 2, 1, 3, 6, 5, 7]; 13 | data.forEach((i) => bst.insert(i)); 14 | bst.delete(2).delete(4); 15 | expect([...bst]).toEqual([1, 3, 5, 6, 7]); 16 | }); 17 | -------------------------------------------------------------------------------- /src/practices/2019-06-18/quick-sort/index.spec.js: -------------------------------------------------------------------------------- 1 | import quicksort from './index'; 2 | 3 | test('quicksort', () => { 4 | const arr = [1, 3, 4, 2, 2]; 5 | const result = quicksort(arr); 6 | expect(result).toEqual([1, 2, 2, 3, 4]); 7 | }); 8 | 9 | test('quicksort', () => { 10 | expect(quicksort([])).toEqual([]); 11 | }); 12 | -------------------------------------------------------------------------------- /src/practices/add-hexadecimal/index.js: -------------------------------------------------------------------------------- 1 | const fn = (num1, num2) => { 2 | let output = ''; 3 | let carry = 0; 4 | let i = num1.length - 1; 5 | let j = num2.length - 1; 6 | while (i >= 0 || j >= 0 || carry > 0) { 7 | // prettier-ignore 8 | const sum = (i >= 0 ? parseInt(num1[i], 16) : 0) 9 | + (j >= 0 ? parseInt(num2[j], 16) : 0) 10 | + carry; 11 | output = (sum % 16).toString(16) + output; 12 | carry = Math.floor(sum / 16); 13 | i -= 1; 14 | j -= 1; 15 | } 16 | return output; 17 | }; 18 | 19 | export default fn; 20 | -------------------------------------------------------------------------------- /src/practices/add-hexadecimal/index.spec.js: -------------------------------------------------------------------------------- 1 | import add from './index'; 2 | 3 | test('add-hexadecimal', () => { 4 | expect(add('a', 'a')).toEqual('14'); 5 | expect(add('abcd', 'deff')).toEqual('18acc'); 6 | }); 7 | -------------------------------------------------------------------------------- /src/practices/count-integer-partitions/index.js: -------------------------------------------------------------------------------- 1 | function countIntegerPartitions2(n) { 2 | const dp = new Array(n + 1).fill(0); 3 | const sum = new Array(n + 1).fill(0); 4 | dp[1] = 1; 5 | sum[1] = 1; 6 | for (let i = 2; i <= n; i++) { 7 | const min = Math.floor(i / 2); 8 | dp[i] = sum[i - 1] - sum[min - 1]; 9 | sum[i] = sum[i - 1] + dp[i]; 10 | } 11 | return dp[n]; 12 | } 13 | -------------------------------------------------------------------------------- /src/practices/count-integer-partitions/slow.js: -------------------------------------------------------------------------------- 1 | function countIntegerPartitions(n) { 2 | const dp = new Array(n + 1).fill(0); 3 | dp[1] = 1; 4 | for (let i = 2; i <= n; i++) { 5 | const min = Math.floor(i / 2); 6 | for (let j = i - 1; j >= min; j--) { 7 | dp[i] += dp[j]; 8 | } 9 | } 10 | return dp[n]; 11 | } 12 | -------------------------------------------------------------------------------- /src/practices/count-number-of-squares-in-the-matrix/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Question 4 | 5 | Count the number of squares in the matrix of zeros and ones, which consist only of zeros. 6 | 7 | Example: 8 | 9 | ``` 10 | Input 11 | [[0, 0, 0] 12 | [0, 0, 0] 13 | [0, 0, 1]] 14 | 15 | Output: 11 16 | 17 | Explanation: 18 | In len 1, there are 8 squares there. 19 | In len 2, there are 3 squares there. 20 | In len 3, there are 0 square there. 21 | So total is 11. 22 | ``` 23 | -------------------------------------------------------------------------------- /src/practices/count-number-of-squares-in-the-matrix/index.spec.js: -------------------------------------------------------------------------------- 1 | import countNumberOfSquaresInTheMatrix from './index'; 2 | 3 | test('countNumberOfSquaresInTheMatrix', () => { 4 | const matrix = [[0, 0, 0], [0, 0, 0], [0, 0, 1]]; 5 | expect(countNumberOfSquaresInTheMatrix(matrix)).toEqual(11); 6 | }); 7 | -------------------------------------------------------------------------------- /src/practices/deep-filter/index.js: -------------------------------------------------------------------------------- 1 | function deepFilter(obj, filter) { 2 | const map = {}; 3 | for (const key in obj) { 4 | const isObject = typeof obj[key] === 'object'; 5 | if (isObject) { 6 | const result = deepFilter(obj[key], filter); 7 | if (Object.keys(result).length) { 8 | map[key] = result; 9 | } 10 | } else if (!isObject && filter(obj[key])) { 11 | map[key] = obj[key]; 12 | } 13 | } 14 | return map; 15 | } 16 | 17 | export default deepFilter; 18 | -------------------------------------------------------------------------------- /src/practices/deep-filter/index.spec.js: -------------------------------------------------------------------------------- 1 | import deepFilter from './index'; 2 | 3 | test('deep filter', () => { 4 | const obj = { 5 | a: 1, 6 | b: { 7 | c: 2, 8 | d: -3, 9 | e: { 10 | f: { 11 | g: -4, 12 | }, 13 | }, 14 | h: { 15 | i: 5, 16 | j: 6, 17 | }, 18 | }, 19 | }; 20 | const filter = (n) => n >= 0; 21 | const result = deepFilter(obj, filter); 22 | expect(result).toEqual({ a: 1, b: { c: 2, h: { i: 5, j: 6 } } }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/practices/exclude-items/exclude items.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/practices/exclude-items/exclude items.pdf -------------------------------------------------------------------------------- /src/practices/exclude-items/index.js: -------------------------------------------------------------------------------- 1 | const exclude = (items, excludes) => { 2 | const query = excludes.reduce((acc, cur) => { 3 | const { k, v } = cur; 4 | if (!(k in acc)) acc[k] = new Set(); 5 | acc[k].add(v); 6 | return acc; 7 | }, {}); 8 | return items.filter((item) => { 9 | for (const key in query) { 10 | if (key in query && query[key].has(item[key])) { 11 | return false; 12 | } 13 | } 14 | return true; 15 | }); 16 | }; 17 | 18 | export default exclude; 19 | -------------------------------------------------------------------------------- /src/practices/get-dot-product/index.js: -------------------------------------------------------------------------------- 1 | function getDotProduct(v1, v2) { 2 | let i = 0; 3 | let j = 0; 4 | let sum = 0; 5 | while (i < v1.length && j < v1.length) { 6 | const [n1, t1] = v1[i]; 7 | const [n2, t2] = v2[j]; 8 | const times = Math.min(t1, t2); 9 | sum += n1 * n2 * times; 10 | if (t1 <= t2) { 11 | i += 1; 12 | v2[j][1] -= times; 13 | } else { 14 | j += 1; 15 | v1[i][1] -= times; 16 | } 17 | } 18 | return sum; 19 | } 20 | 21 | export default getDotProduct; 22 | -------------------------------------------------------------------------------- /src/practices/get-dot-product/index.spec.js: -------------------------------------------------------------------------------- 1 | import getDotProduct from './index'; 2 | 3 | test('getDotProduct', () => { 4 | // prettier-ignore 5 | const result = getDotProduct([[2, 4], [3, 1]], [[3, 5]]); 6 | expect(result).toEqual(33); 7 | }); 8 | -------------------------------------------------------------------------------- /src/practices/loading-bar/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Uber front end interview 4 | 5 | 1. Implement a loading bar that animates from 0 to 100% in 3 seconds 6 | 2. Start loading bar animation upon a button click 7 | 3. Queue multiple loading bars if the button is clicked more than once. Loading bar N starts animating with loading bar N-1 is done animating. 8 | 9 | - https://codepen.io/bobwei/pen/rXQaOb 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/practices/loading-bar/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | -------------------------------------------------------------------------------- /src/practices/loading-bar/screenshot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/practices/loading-bar/screenshot.gif -------------------------------------------------------------------------------- /src/practices/number-of-ways-staying-at-zero/Number of ways staying at zero.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bobwei/algorithms/6ab7978dc72d512f714960a8c4b39d8358e11d32/src/practices/number-of-ways-staying-at-zero/Number of ways staying at zero.pdf -------------------------------------------------------------------------------- /src/practices/number-of-ways-staying-at-zero/index.spec.js: -------------------------------------------------------------------------------- 1 | import numberOfWaysStayingAtZero from './index'; 2 | 3 | test('numberOfWaysStayingAtZero', () => { 4 | expect(numberOfWaysStayingAtZero(3)).toEqual(7); 5 | expect(numberOfWaysStayingAtZero(4)).toEqual(19); 6 | expect(numberOfWaysStayingAtZero(5)).toEqual(51); 7 | }); 8 | -------------------------------------------------------------------------------- /src/practices/range/index.js: -------------------------------------------------------------------------------- 1 | const fn = (start, end) => { 2 | let i = start; 3 | return { 4 | [Symbol.iterator]() { 5 | return this; 6 | }, 7 | next() { 8 | if (!(i < end)) { 9 | return { 10 | done: true, 11 | }; 12 | } 13 | return { 14 | value: i++, 15 | done: false, 16 | }; 17 | }, 18 | }; 19 | }; 20 | 21 | export default fn; 22 | -------------------------------------------------------------------------------- /src/practices/range/index.spec.js: -------------------------------------------------------------------------------- 1 | import range from './index'; 2 | 3 | test('range', () => { 4 | const result = [...range(0, 5)]; 5 | expect(result).toEqual([0, 1, 2, 3, 4]); 6 | }); 7 | -------------------------------------------------------------------------------- /src/practices/render-template/index.spec.js: -------------------------------------------------------------------------------- 1 | import render from './index'; 2 | 3 | test('render template', () => { 4 | expect( 5 | render('hello {var1}, yo {var2}', { 6 | var1: 'world', 7 | var2: 'test123', 8 | }), 9 | ).toEqual('hello world, yo test123'); 10 | }); 11 | 12 | test('render template', () => { 13 | expect( 14 | render('hello {var1}, yo {var2}', { 15 | var1: 'xyz', 16 | var2: 'abc', 17 | }), 18 | ).toEqual('hello xyz, yo abc'); 19 | }); 20 | -------------------------------------------------------------------------------- /src/practices/sort-a-with-b/index.js: -------------------------------------------------------------------------------- 1 | function sortAWithB(A, B) { 2 | const m = A.length; 3 | for (let i = 0; i < m; i++) { 4 | while (B[i] - 1 !== i) { 5 | const pos = B[i] - 1; 6 | [B[i], B[pos]] = [B[pos], B[i]]; 7 | [A[i], A[pos]] = [A[pos], A[i]]; 8 | } 9 | } 10 | } 11 | 12 | const A = [24, 56, 74, -23, 87, 91]; 13 | const B = [2, 3, 4, 1, 5, 6]; 14 | sortAWithB(A, B); 15 | console.log(A, B); 16 | -------------------------------------------------------------------------------- /src/system-design/rate-limiter.md: -------------------------------------------------------------------------------- 1 | # README 2 | 3 | ## Approaches 4 | 5 | - Token Bucket 6 | - Leaky Bucket 7 | - Fixed Window Counter 8 | - Sliding Window Logs 9 | - Sliding Window Counter 10 | 11 | ## Implementation 12 | 13 | - [Sliding Window Counter](../utilities/rate-limiter/index.js) 14 | 15 | ## References 16 | 17 | - [](https://www.figma.com/blog/an-alternative-approach-to-rate-limiting/) 18 | - [](https://medium.com/@saisandeepmopuri/system-design-rate-limiter-and-data-modelling-9304b0d18250) 19 | -------------------------------------------------------------------------------- /src/utilities/bind/es5.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prefer-rest-params */ 2 | function bind(fn, context) { 3 | const args1 = Array.prototype.slice.call(arguments, 2); 4 | return function() { 5 | const args2 = Array.prototype.slice.call(arguments, 0); 6 | return fn.apply(context, args1.concat(args2)); 7 | }; 8 | } 9 | 10 | export default bind; 11 | -------------------------------------------------------------------------------- /src/utilities/bind/es5.spec.js: -------------------------------------------------------------------------------- 1 | import bind from './es5'; 2 | 3 | test('bind', () => { 4 | const helper = function(a, b) { 5 | return this.name + a + b; 6 | }; 7 | const fn = bind(helper, { name: 'test' }, 'arg1'); 8 | expect(fn('arg2')).toEqual('testarg1arg2'); 9 | }); 10 | -------------------------------------------------------------------------------- /src/utilities/bind/es6.js: -------------------------------------------------------------------------------- 1 | function bind(fn, context, ...args1) { 2 | return function(...args2) { 3 | return fn.call(context, ...args1, ...args2); 4 | }; 5 | } 6 | 7 | export default bind; 8 | -------------------------------------------------------------------------------- /src/utilities/bind/es6.spec.js: -------------------------------------------------------------------------------- 1 | import bind from './es6'; 2 | 3 | test('bind', () => { 4 | const helper = function(a, b) { 5 | return this.name + a + b; 6 | }; 7 | const fn = bind(helper, { name: 'test' }, 'arg1'); 8 | expect(fn('arg2')).toEqual('testarg1arg2'); 9 | }); 10 | -------------------------------------------------------------------------------- /src/utilities/bind/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-extend-native */ 2 | Function.prototype.bind = function(context, ...args1) { 3 | const fn = this; 4 | return function(...args2) { 5 | return fn.call(context, ...args1, ...args2); 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /src/utilities/bind/index.spec.js: -------------------------------------------------------------------------------- 1 | import './index'; 2 | 3 | test('bind', () => { 4 | const helper = function(a, b) { 5 | return this.name + a + b; 6 | }; 7 | const fn = helper.bind({ name: 'test' }, 'arg1'); 8 | expect(fn('arg2')).toEqual('testarg1arg2'); 9 | }); 10 | -------------------------------------------------------------------------------- /src/utilities/curried-5-sum/index.js: -------------------------------------------------------------------------------- 1 | function sum(...args) { 2 | if (args.length >= 5) { 3 | return args.reduce((acc, cur) => acc + cur, 0); 4 | } 5 | return sum.bind(this, ...args); 6 | } 7 | 8 | export default sum; 9 | -------------------------------------------------------------------------------- /src/utilities/curried-5-sum/index.spec.js: -------------------------------------------------------------------------------- 1 | import sum from './index'; 2 | 3 | test('sum', () => { 4 | expect(sum(1, 2)(3, 4)(5)).toEqual(15); 5 | expect(sum(1, 2)(3, 4, 5)).toEqual(15); 6 | expect(sum(1, 2, 3, 4, 5)).toEqual(15); 7 | }); 8 | -------------------------------------------------------------------------------- /src/utilities/curry/index.js: -------------------------------------------------------------------------------- 1 | function curry(fn) { 2 | return function(...args) { 3 | if (args.length >= fn.length) { 4 | return fn(...args); 5 | } 6 | return curry(fn.bind(this, ...args)); 7 | }; 8 | } 9 | 10 | export default curry; 11 | -------------------------------------------------------------------------------- /src/utilities/curry/index.spec.js: -------------------------------------------------------------------------------- 1 | import curry from './index'; 2 | 3 | test('curry', () => { 4 | const add = curry((a, b, c) => { 5 | return a + b + c; 6 | }); 7 | expect(add(1, 2, 3)).toEqual(6); 8 | expect(add(1)(2)(3)).toEqual(6); 9 | expect(add(1, 2)(3)).toEqual(6); 10 | }); 11 | -------------------------------------------------------------------------------- /src/utilities/curryN/index.js: -------------------------------------------------------------------------------- 1 | function curryN(n, fn) { 2 | return function(...args) { 3 | if (args.length >= n) { 4 | return fn(...args); 5 | } 6 | return curryN(n - args.length, fn.bind(this, ...args)); 7 | }; 8 | } 9 | 10 | export default curryN; 11 | -------------------------------------------------------------------------------- /src/utilities/curryN/index.spec.js: -------------------------------------------------------------------------------- 1 | import curryN from './index'; 2 | 3 | test('curryN', () => { 4 | const sum = curryN(5, (...args) => args.reduce((acc, cur) => acc + cur, 0)); 5 | expect(sum(1, 2, 3, 4, 5)).toEqual(15); 6 | expect(sum(1)(2)(3)(4)(5)).toEqual(15); 7 | expect(sum(1)(2, 3)(4)(5)).toEqual(15); 8 | }); 9 | -------------------------------------------------------------------------------- /src/utilities/debounce/index.js: -------------------------------------------------------------------------------- 1 | const debounce = (mSec, fn) => { 2 | let timeout = null; 3 | return (...args) => { 4 | clearTimeout(timeout); 5 | timeout = setTimeout(() => fn(...args), mSec); 6 | }; 7 | }; 8 | 9 | export default debounce; 10 | -------------------------------------------------------------------------------- /src/utilities/promisify/index.js: -------------------------------------------------------------------------------- 1 | function promisify(fn) { 2 | return () => { 3 | return new Promise((resolve, reject) => { 4 | fn((err, data) => { 5 | if (err) { 6 | reject(err); 7 | return; 8 | } 9 | resolve(data); 10 | }); 11 | }); 12 | }; 13 | } 14 | 15 | export default promisify; 16 | -------------------------------------------------------------------------------- /src/utilities/promisify/index.spec.js: -------------------------------------------------------------------------------- 1 | import promisify from './index'; 2 | 3 | test('promisify', () => { 4 | function read(cb) { 5 | const error = null; 6 | const data = '123'; 7 | cb(error, data); 8 | } 9 | 10 | const readWithPromise = promisify(read); 11 | return readWithPromise() 12 | .then((data) => { 13 | expect(data).toEqual('123'); 14 | }) 15 | .catch(console.log); 16 | }); 17 | -------------------------------------------------------------------------------- /src/utilities/pubsub/index.js: -------------------------------------------------------------------------------- 1 | function createPubSub() { 2 | const listeners = new Set(); 3 | 4 | return { 5 | subscribe(cb) { 6 | listeners.add(cb); 7 | return () => { 8 | listeners.delete(cb); 9 | }; 10 | }, 11 | 12 | publish(...args) { 13 | for (const cb of listeners) { 14 | cb(...args); 15 | } 16 | }, 17 | }; 18 | } 19 | 20 | export default createPubSub; 21 | -------------------------------------------------------------------------------- /src/utilities/pubsub/index.spec.js: -------------------------------------------------------------------------------- 1 | import createPubSub from './index'; 2 | 3 | test('createPubSub', () => { 4 | const pubsub = createPubSub(); 5 | pubsub.subscribe((arg) => { 6 | expect(arg).toEqual([1, 2, 3]); 7 | }); 8 | pubsub.publish([1, 2, 3]); 9 | }); 10 | -------------------------------------------------------------------------------- /src/utilities/rate-limiter/index.spec.js: -------------------------------------------------------------------------------- 1 | import createRateLimiter from './index'; 2 | 3 | jest.useFakeTimers(); 4 | 5 | test('test', () => { 6 | let nSuccess = 0; 7 | let nError = 0; 8 | const isAllowed = createRateLimiter(5); 9 | for (let i = 0; i < 10; i++) { 10 | if (isAllowed()) { 11 | nSuccess += 1; 12 | } else { 13 | nError += 1; 14 | } 15 | } 16 | expect(nSuccess).toEqual(5); 17 | expect(nError).toEqual(5); 18 | }); 19 | -------------------------------------------------------------------------------- /src/utilities/reorder-array-with-given-order/index.js: -------------------------------------------------------------------------------- 1 | function sort(arr, order) { 2 | for (let i = 0; i < order.length; ) { 3 | while (order[i] !== i) { 4 | const j = order[i]; 5 | [order[i], order[j]] = [order[j], order[i]]; 6 | [arr[i], arr[j]] = [arr[j], arr[i]]; 7 | } 8 | i += 1; 9 | } 10 | return arr; 11 | } 12 | 13 | export default sort; 14 | -------------------------------------------------------------------------------- /src/utilities/reorder-array-with-given-order/index.spec.js: -------------------------------------------------------------------------------- 1 | import sort from './index'; 2 | 3 | test('sort', () => { 4 | const arr = [50, 40, 70, 60, 90]; 5 | const order = [3, 0, 4, 1, 2]; 6 | const result = sort(arr, order); 7 | expect(result).toEqual([40, 60, 90, 50, 70]); 8 | }); 9 | -------------------------------------------------------------------------------- /src/utilities/runner/index.spec.js: -------------------------------------------------------------------------------- 1 | import Runner from './index'; 2 | 3 | test('Runner', (done) => { 4 | const result = []; 5 | const runner = new Runner({ 6 | concurrency: 3, 7 | fn(arg) { 8 | result.push(arg); 9 | return new Promise((resolve) => setTimeout(resolve, 100)); 10 | }, 11 | }); 12 | 13 | [...new Array(6)].map((_, i) => i).forEach((i) => runner.push(i)); 14 | setTimeout(() => { 15 | expect(result).toEqual([0, 1, 2, 3, 4, 5]); 16 | done(); 17 | }, 200); 18 | }); 19 | -------------------------------------------------------------------------------- /src/utilities/throttle/index.js: -------------------------------------------------------------------------------- 1 | const throttle = (mSec, fn) => { 2 | let timestamp = 0; 3 | return (...args) => { 4 | const now = new Date().getTime(); 5 | if (now - timestamp > mSec) { 6 | timestamp = now; 7 | fn(...args); 8 | } 9 | }; 10 | }; 11 | 12 | export default throttle; 13 | -------------------------------------------------------------------------------- /src/utilities/throttle/index.spec.js: -------------------------------------------------------------------------------- 1 | import throttle from './index'; 2 | 3 | test('throttle', async () => { 4 | let counter = 0; 5 | const inc = throttle(800, () => { 6 | counter += 1; 7 | }); 8 | for (let i = 0; i < 10; i++) { 9 | inc(); 10 | } 11 | expect(counter).toEqual(1); 12 | await createTimeout(800); 13 | inc(); 14 | inc(); 15 | expect(counter).toEqual(2); 16 | }); 17 | 18 | function createTimeout(mSec) { 19 | return new Promise((resolve) => { 20 | setTimeout(resolve, mSec); 21 | }); 22 | } 23 | --------------------------------------------------------------------------------