├── .gitignore ├── README.md ├── common ├── bellman–ford.py ├── binary-search-tree.py ├── bst-in-order.py ├── dijkstra.py ├── heap-sort.py ├── insertion-sort.py ├── knapsack.py ├── merge-sort-in-place.py ├── merge-sort.py ├── min-heap.py ├── quick-sort.py ├── radix-sort.py └── trie.py └── problems ├── python ├── 01-matrix.py ├── 3sum-closest.py ├── 3sum.py ├── 4sum.py ├── accounts-merge.py ├── add-binary.py ├── add-digits.py ├── add-strings.py ├── add-two-numbers-ii.py ├── add-two-numbers.py ├── alien-dictionary.py ├── all-nodes-distance-k-in-binary-tree.py ├── amount-of-new-area-painted-each-day.py ├── analyze-user-website-visit-pattern.py ├── backspace-string-compare.py ├── balance-a-binary-search-tree.py ├── balanced-binary-tree.py ├── basic-calculator-ii.py ├── best-time-to-buy-an-stock.py ├── best-time-to-buy-and-sell-stock-iii.py ├── best-time-to-buy-and-sell-stock-with-cooldown.py ├── best-time-to-buy-and-sell-stock.py ├── big-countries.sql ├── binary-search-tree-iterator.py ├── binary-search.py ├── binary-subarrays-with-sum.py ├── binary-tree-inorder-traversal.py ├── binary-tree-level-order-traversal-ii.py ├── binary-tree-level-order-traversal.py ├── binary-tree-longest-consecutive-sequence.py ├── binary-tree-maximum-path-sum.py ├── binary-tree-paths.py ├── binary-tree-pruning.py ├── binary-tree-right-side-view.py ├── binary-tree-vertical-order-traversal.py ├── binary-watch.py ├── buildings-with-an-ocean-view.py ├── burst-balloons.py ├── campus-bikes-ii.py ├── candy.py ├── capacity-to-ship-packages-within-d-days.py ├── cheapest-flights-within-k-stops.py ├── climbing-stairs.py ├── clone-graph.py ├── closest-binary-search-tree-value.py ├── coin-change.py ├── coloring-a-border.py ├── combination-sum-ii.py ├── combination-sum-iii.py ├── combination-sum-iv.py ├── combination-sum.py ├── combinations.py ├── combine-two-tables.sql ├── compare-version-numbers.py ├── connecting-cities-with-minimum-cost.py ├── consecutive-numbers-sum.py ├── construct-binary-tree-from-inorder-and-postorder-traversal.py ├── construct-binary-tree-from-preorder-and-inorder-traversal.py ├── container-with-most-water.py ├── contains-duplicate-ii.py ├── contains-duplicate-iii.py ├── contains-duplicate.py ├── continuous-subarray-sum.py ├── convert-binary-search-tree-to-sorted-doubly-linked-list.py ├── convert-sorted-array-to-binary-search-tree.py ├── convert-sorted-list-to-binary-search-tree.py ├── copy-list-with-random-pointer.py ├── count-all-valid-pickup-and-delivery-opti.py ├── count-binary-substrings.py ├── count-complete-tree-nodes.py ├── count-number-of-nice-subarrays.py ├── count-unique-characters-of-all-substrings-of-a-given-string.py ├── course-schedule-ii.py ├── course-schedule.py ├── custom-sort-string.py ├── cutting-ribbons.py ├── data-stream-as-disjoint-intervals.py ├── decode-string.py ├── decode-ways.py ├── delete-and-earn.py ├── delete-duplicate-folders-in-system.py ├── delete-node-in-a-bst.py ├── delete-operation-for-two-strings.py ├── design-add-and-search-words-data-structure.py ├── design-in-memory-file-system.py ├── design-linked-list.py ├── design-tic-tac-toe.py ├── diagonal-traverse.py ├── diameter-of-binary-tree.py ├── different-ways-to-add-parentheses.py ├── distinct-subsequences.py ├── distribute-coins-in-binary-tree.py ├── domino-and-tromino-tiling.py ├── dot-product-of-two-sparse-vectors.py ├── dungeon-game.py ├── edit-distance.py ├── egions-cut-by-slashes.py ├── evaluate-division.py ├── evaluate-reverse-polish-notation.py ├── exclusive-time-of-functions.py ├── expression-add-operators.py ├── filling-bookcase-shelves.py ├── find-all-possible-recipes-from-given-supplies.py ├── find-and-replace-in-string.py ├── find-distance-in-a-binary-tree.py ├── find-duplicate-subtrees.py ├── find-eventual-safe-states.py ├── find-first-and-last-position-of-element-in-sorted-array.py ├── find-k-closest-elements.py ├── find-k-pairs-with-smallest-sums.py ├── find-leaves-of-binary-tree.py ├── find-median-from-data-stream.py ├── find-minimum-in-rotated-sorted-array-ii.py ├── find-minimum-in-rotated-sorted-array.py ├── find-mode-in-binary-search-tree.py ├── find-original-array-from-doubled-array,py ├── find-peak-element.py ├── find-the-duplicate-number.py ├── first-bad-version.py ├── first-missing-positive.py ├── first-unique-character-in-a-string.py ├── fizz-buzz.py ├── flatten-binary-tree-to-linked-list.py ├── flip-binary-tree-to-match-preorder-traversal.py ├── flip-string-to-monotone-increasing.py ├── flood-fill.py ├── friend-circles.py ├── fruit-into-baskets.py ├── game-of-life.py ├── generate-parentheses.py ├── graph-valid-tree.py ├── greatest-sum-divisible-by-three.py ├── group-anagrams.py ├── group-shifted-strings.py ├── guess-number-higher-or-lower-ii.py ├── guess-number-higher-or-lower.py ├── guess-the-word.py ├── h-index-ii.py ├── h-index.py ├── hamming-distance.py ├── house-robber-ii.py ├── house-robber-iii.py ├── house-robber.py ├── implement-trie-prefix-tree.py ├── increasing-triplet-subsequence.py ├── inorder-successor-in-bst-ii.py ├── inorder-successor-in-bst.py ├── insert-interval.py ├── insert-into-a-binary-search-tree.py ├── insert-into-a-sorted-circular-linked-list.py ├── insertion-sort-list.py ├── integer-to-english-words.py ├── interleaving-string.py ├── intersection-of-two-arrays-ii.py ├── intersection-of-two-arrays.py ├── invert-binary-tree.py ├── is-graph-bipartite.py ├── is-subsequence.py ├── isomorphic-strings.py ├── jewels-and-stones.py ├── jump-game.py ├── k-closest-points-to-origin.py ├── k-empty-slots.py ├── keys-and-rooms.py ├── knight-dialer.py ├── knight-probability-in-chessboard.py ├── koko-eating-bananas.py ├── kth-largest-element-in-an-array.py ├── kth-smallest-element-in-a-bst.py ├── kth-smallest-element-in-a-sorted-matrix.py ├── largest-1-bordered-square.py ├── largest-bst-subtree.py ├── largest-sum-of-averages.py ├── last-stone-weight-ii.py ├── last-stone-weight.py ├── least-number-of-unique-integers-after-k-removals.py ├── letter-case-permutation.py ├── letter-combinations-of-a-phone-number.py ├── license-key-formatting.py ├── linked-list-cycle-ii.py ├── linked-list-cycle.py ├── linked-list-random-node.py ├── logger-rate-limiter.py ├── longest-common-prefix.py ├── longest-common-subsequence.py ├── longest-consecutive-sequence.py ├── longest-increasing-path-in-a-matrix.py ├── longest-increasing-subsequence.py ├── longest-palindromic-subsequence.py ├── longest-palindromic-substring.py ├── longest-repeating-character-replacement.py ├── longest-string-chain.py ├── longest-substring-with-at-least-k-repeating-characters.py ├── longest-substring-without-repeating-characters.py ├── longest-univalue-path.py ├── lowest-common-ancestor-of-a-binary-search-tree.py ├── lowest-common-ancestor-of-a-binary-search.py ├── lowest-common-ancestor-of-a-binary-tree-ii.py ├── lowest-common-ancestor-of-a-binary-tree-iii.py ├── lowest-common-ancestor-of-a-binary-tree-iv.py ├── lowest-common-ancestor-of-a-binary-tree.py ├── lowest-common-ancestor-of-deepest-leaves.py ├── lru-cache.py ├── majority-element-ii.py ├── majority-element.py ├── making-a-large-island.py ├── max-area-of-island.py ├── max-consecutive-ones-iii.py ├── max-stack.py ├── max-sum-of-rectangle-no-larger-than-k.py ├── maximal-square.py ├── maximum-average-subtree.py ├── maximum-compatibility-score-sum.py ├── maximum-depth-of-binary-tree.py ├── maximum-gap.py ├── maximum-length-of-repeated-subarray.py ├── maximum-number-of-events-that-can-be-attended.py ├── maximum-number-of-points-with-cost.py ├── maximum-number-of-visible-points.py ├── maximum-product-of-three-numbers.py ├── maximum-product-subarray.py ├── maximum-subarray-sum-with-one-deletion.py ├── maximum-subarray.py ├── maximum-swap.py ├── maximum-units-on-a-truck.py ├── median-of-two-sorted-arrays.py ├── meeting-rooms-ii.py ├── meeting-rooms.py ├── merge-intervals.py ├── merge-k-sorted-lists.py ├── merge-sorted-array.py ├── merge-two-sorted-lists.py ├── min-cost-climbing-stairs.py ├── min-stack.py ├── minimize-malware-spread.py ├── minimum-absolute-difference-in-bst.py ├── minimum-ascii-delete-sum-for-two-strings.py ├── minimum-cost-to-connect-sticks.py ├── minimum-cost-to-hire-k-workers.py ├── minimum-cost-to-make-at-least-one-valid-path-in-a-grid.py ├── minimum-cost-to-reach-city-with-discounts.py ├── minimum-depth-of-binary-tree.py ├── minimum-difficulty-of-a-job-schedule.py ├── minimum-falling-path-sum-ii.py ├── minimum-knight-moves.py ├── minimum-number-of-flips-to-convert-binary-matrix-to-zero-matrix.py ├── minimum-path-sum.py ├── minimum-score-triangulation-of-polygon.py ├── minimum-size-subarray-sum.py ├── minimum-swaps-to-group-all-1s-together.py ├── minimum-swaps-to-make-sequences-increasing.py ├── minimum-time-difference.py ├── minimum-window-substring.py ├── minimum-xor-sum-of-two-arrays.py ├── missing-number.py ├── most-frequent-subtree-sum.py ├── most-stones-removed-with-same-row-or-column.py ├── move-zeroes.py ├── moving-average-from-data-stream.py ├── my-calendar-ii.py ├── n-ary-tree-level-order-traversal.py ├── n-ary-tree-postorder-traversal.py ├── n-ary-tree-preorder-traversal.py ├── nested-list-weight-sum.py ├── network-delay-time.py ├── next-closest-time.py ├── next-permutation.py ├── number-complement.py ├── number-of-connected-components-in-an-undirected-graph.py ├── number-of-islands-ii.py ├── number-of-islands.py ├── number-of-longest-increasing-subsequence.py ├── number-of-matching-subsequences.py ├── number-of-provinces.py ├── number-of-recent-calls.py ├── number-of-squareful-arrays.py ├── number-of-substrings-containing-all-thre.py ├── number-of-ways-to-arrive-at-destination.py ├── odd-even-jump.py ├── ones-and-zeroes.py ├── open-the-lock.py ├── out-of-boundary-paths.py ├── pacific-atlantic-water-flow.py ├── pairs-of-songs-with-total-durations-divisible-by-60.py ├── palindrome-number.py ├── palindrome-pairs.py ├── palindrome-partitioning-iii.py ├── palindrome-partitioning.py ├── palindromic-substrings.py ├── partition-array-for-maximum-sum.py ├── partition-labels.py ├── partition-to-k-equal-sum-subsets.py ├── path-sum-ii.py ├── path-sum-iii.py ├── path-sum.py ├── path-with-maximum-probability.py ├── peak-index-in-a-mountain-array.py ├── perfect-squares.py ├── permutation-in-string.py ├── permutation-sequence.py ├── permutations-ii.py ├── permutations.py ├── populating-next-right-pointers-in-each-node-ii.py ├── populating-next-right-pointers-in-each-node.py ├── powx-n.py ├── product-of-array-except-self.py ├── profitable-schemes.py ├── queue-reconstruction-by-height.py ├── random-pick-with-weight.py ├── range-addition.py ├── range-sum-of-bst.py ├── range-sum-query-immutable.py ├── range-sum-query-mutable.py ├── rearrange-string-k-distance-apart.py ├── reconstruct-itinerary.py ├── recover-binary-search-tree.py ├── redundant-connection.py ├── remove-all-adjacent-duplicates-in-string.py ├── remove-all-ones-with-row-and-column-flips.py ├── remove-duplicates-from-sorted-array-ii.py ├── remove-duplicates-from-sorted-array.py ├── remove-duplicates-from-sorted-list.py ├── remove-element.py ├── remove-invalid-parentheses.py ├── remove-linked-list-elements.py ├── remove-nth-node-from-end-of-list.py ├── reorder-list.py ├── repeated-string-match.py ├── replace-the-substring-for-balanced-string.py ├── restore-ip-addresses.py ├── reverse-integer.py ├── reverse-linked-list.py ├── reverse-string.py ├── reverse-vowels-of-a-string.py ├── reverse-words-in-a-string.py ├── robot-bounded-in-circle.py ├── roman-to-integer.py ├── rotate-array.py ├── rotate-image.py ├── russian-doll-envelopes.py ├── same-tree.py ├── satisfiability-of-equality-equations.py ├── score-of-parentheses.py ├── search-a-2d-matrix.py ├── search-in-a-binary-search-tree.py ├── search-in-rotated-sorted-array-ii.py ├── search-in-rotated-sorted-array.py ├── search-insert-position.py ├── search-suggestions-system.py ├── second-highest-salary.sql ├── sell-diminishing-valued-colored-balls.py ├── serialize-and-deserialize-binary-tree.py ├── serialize-and-deserialize-bst.py ├── set-matrix-zeroes.py ├── shortest-bridge.py ├── shortest-common-supersequence.py ├── shortest-distance-from-all-buildings.py ├── shortest-path-in-a-grid-with-obstacles-elimination.py ├── shortest-path-in-binary-matrix.py ├── shortest-path-to-get-food.py ├── shuffle-an-array.py ├── simplify-path.py ├── single-threaded-cpu.py ├── sliding-window-maximum.py ├── snapshot-array.py ├── sort-colors.py ├── sort-list.py ├── spiral-matrix.py ├── split-array-into-fibonacci-sequence.py ├── split-array-largest-sum.py ├── sqrtx.py ├── squares-of-a-sorted-array.py ├── step-by-step-directions-from-a-binary-tree-node-to-another.py ├── stock-price-fluctuation.py ├── stone-game-ii.py ├── student-attendance-record-ii.py ├── subarray-sum-equals-k.py ├── subarrays-with-k-different-integers.py ├── subdomain-visit-count.py ├── subsets-ii.py ├── subsets.py ├── substring-with-concatenation-of-all-words.py ├── subtree-of-another-tree.py ├── sum-of-subarray-minimums.py ├── sum-root-to-leaf-numbers.py ├── summary-ranges.py ├── super-ugly-number.py ├── swap-adjacent-in-lr-string.py ├── swap-nodes-in-pairs.py ├── swim-in-rising-water.py ├── symmetric-tree.py ├── tallest-billboard.py ├── target-sum.py ├── task-scheduler.py ├── text-justification.py ├── the-kth-factor-of-n.py ├── the-maze-ii.py ├── time-based-key-value-store.py ├── to-lower-case.py ├── toeplitz-matrix.py ├── top-k-frequent-elements.py ├── trapping-rain-water-ii.py ├── trapping-rain-water.py ├── trim-a-binary-search-tree.py ├── two-out-of-three.py ├── two-sum-ii-input-array-is-sorted.py ├── two-sum.py ├── ugly-number-ii.py ├── ugly-number.py ├── umber-of-islands-ii.py ├── unique-binary-search-trees-ii,py ├── unique-binary-search-trees.py ├── unique-email-addres.py ├── unique-paths.py ├── univalued-binary-tree.py ├── valid-anagram.py ├── valid-number.py ├── valid-palindrome-ii.py ├── valid-palindrome.py ├── valid-parentheses.py ├── valid-word-abbreviation.py ├── validate-binary-search-tree.py ├── verify-preorder-serialization-of-a-binary-tree.py ├── vertical-order-traversal-of-a-binary-tree.py ├── wiggle-subsequence.py ├── word-break.py ├── word-ladder-ii.py ├── word-ladder.py ├── word-search-ii.py └── word-search.py └── python3 ├── 3sum-closest.py ├── 3sum-smaller.py ├── 3sum.py ├── 4sum.py ├── add-two-numbers.py ├── alien-dictionary.py ├── balanced-binary-tree.py ├── best-time-to-buy-and-sell-stock-with-cooldown.py ├── best-time-to-buy-and-sell-stock.py ├── binary-search.py ├── binary-tree-level-order-traversal.py ├── binary-tree-maximum-path-sum.py ├── binary-tree-right-side-view.py ├── burst-balloons.py ├── car-fleet.py ├── cheapest-flights-within-k-stops.py ├── climbing-stairs.py ├── clone-graph.py ├── coin-change-ii.py ├── coin-change.py ├── combination-sum-ii.py ├── combination-sum.py ├── construct-binary-tree-from-preorder-and-inorder-traversal.py ├── container-with-most-water.py ├── contains-duplicate.py ├── copy-list-with-random-pointer.py ├── count-good-nodes-in-binary-tree.py ├── counting-bits.py ├── course-schedule-ii.py ├── course-schedule.py ├── daily-temperatures.py ├── decode-ways.py ├── design-add-and-search-words-data-structure.py ├── design-twitter.py ├── detect-squares.py ├── diameter-of-binary-tree.py ├── distinct-subsequences.py ├── edit-distance.py ├── encode-and-decode-strings.py ├── evaluate-reverse-polish-notation.py ├── find-median-from-data-stream.py ├── find-minimum-in-rotated-sorted-array.py ├── find-the-duplicate-number.py ├── gas-station.py ├── generate-parentheses.py ├── graph-valid-tree.py ├── group-anagrams.py ├── hand-of-straights.py ├── happy-number.py ├── house-robber-ii.py ├── house-robber.py ├── implement-trie-prefix-tree.py ├── insert-interval.py ├── interleaving-string.py ├── invert-binary-tree.py ├── jump-game-ii.py ├── jump-game.py ├── k-closest-points-to-origin.py ├── koko-eating-bananas.py ├── kth-largest-element-in-a-stream.py ├── kth-smallest-element-in-a-bst.py ├── largest-rectangle-in-histogram.py ├── last-stone-weight.py ├── letter-combinations-of-a-phone-number.py ├── linked-list-cycle.py ├── longest-common-subsequence.py ├── longest-consecutive-sequence.py ├── longest-increasing-path-in-a-matrix.py ├── longest-palindromic-substring.py ├── longest-repeating-character-replacement.py ├── longest-substring-without-repeating-char.py ├── lowest-common-ancestor-of-a-binary-search-tree.py ├── lru-cache.py ├── max-area-of-island.py ├── maximum-depth-of-binary-tree.py ├── maximum-product-subarray.py ├── maximum-subarray.py ├── median-of-two-sorted-arrays.py ├── meeting-rooms-ii.py ├── meeting-rooms.py ├── merge-intervals.py ├── merge-triplets-to-form-target-triplet.py ├── merge-two-sorted-lists.py ├── min-cost-climbing-stairs.py ├── min-cost-to-connect-all-points.py ├── min-stack.py ├── minimum-interval-to-include-each-query.py ├── minimum-window-substring.py ├── missing-number.py ├── multiply-strings.py ├── n-queens.py ├── network-delay-time.py ├── non-overlapping-intervals.py ├── number-of-1-bits.py ├── number-of-connected-components-in-an-undirected-graph.py ├── number-of-islands.py ├── pacific-atlantic-water-flow.py ├── palindrome-partitioning.py ├── palindromic-substrings.py ├── partition-equal-subset-sum.py ├── partition-labels.py ├── permutation-in-string.py ├── permutations.py ├── plus-one.py ├── powx-n.py ├── product-of-array-except-self.py ├── reconstruct-itinerary.py ├── redundant-connection.py ├── regular-expression-matching.py ├── remove-nth-node-from-end-of-list.py ├── reorder-list.py ├── reverse-bits.py ├── reverse-integer.py ├── reverse-linked-list.py ├── rotate-image.py ├── rotting-oranges.py ├── same-tree.py ├── search-a-2d-matrix.py ├── serialize-and-deserialize-binary-tree.py ├── set-matrix-zeroes.py ├── single-number.py ├── sliding-window-maximum.py ├── spiral-matrix.py ├── subsets-ii.py ├── subsets.py ├── substring-with-concatenation-of-all-words.py ├── subtree-of-another-tree.py ├── sum-of-two-integers.py ├── surrounded-regions.py ├── swim-in-rising-water.py ├── target-sum.py ├── task-scheduler.py ├── time-based-key-value-store.py ├── top-k-frequent-elements.py ├── trapping-rain-water.py ├── two-sum-ii-input-array-is-sorted.py ├── two-sum.py ├── unique-paths.py ├── valid-anagram.py ├── valid-palindrome.py ├── valid-parentheses.py ├── valid-parenthesis-string.py ├── valid-sudoku.py ├── validate-binary-search-tree.py ├── walls-and-gates.py ├── word-break.py ├── word-ladder.py ├── word-search-ii.py └── word-search.py /.gitignore: -------------------------------------------------------------------------------- 1 | _doc/* 2 | .vscode -------------------------------------------------------------------------------- /common/bellman–ford.py: -------------------------------------------------------------------------------- 1 | """ 2 | First, we use `distance` to track the distance from start to all others. 3 | For V nodes, it takes at least V-1 iteration to complete the algorithm. 4 | For every iteration, 5 | We use every node as the middle point to see if it can "loosen" the path from start to mid to mid's neighbors 6 | If it can loosen the path, we update the `distance`. 7 | The time complexity is O(VE) 8 | """ 9 | def min_path(G, N, start, end): 10 | distance = [float('inf') for _ in xrange(N+1)] 11 | distance[start] = 0 12 | 13 | for _ in xrange(N-1): 14 | for mid, dis in enumerate(distance): 15 | if dis==float('inf'): continue 16 | for dis_to_nei, nei in G[mid]: 17 | distance[nei] = min(distance[nei], dis+dis_to_nei) 18 | return distance[end] 19 | 20 | 21 | G = { 22 | 0: [(-2, 1), (4, 2)], 23 | 1: [(5, 2)], 24 | 2: [(12, 3), (5, 4)], 25 | 3: [(-8, 4)], 26 | 4: [] 27 | } 28 | N = 4 #nodes count 29 | start = 0 30 | end = 4 31 | print min_path(G, N, start, end) 32 | -------------------------------------------------------------------------------- /common/bst-in-order.py: -------------------------------------------------------------------------------- 1 | def inOrderTraverse(root): 2 | stack = [] 3 | node = root 4 | 5 | while node or stack: 6 | while node: 7 | stack.append(node) 8 | node = node.left 9 | 10 | node = stack.pop() 11 | 12 | #do something 13 | print node.val 14 | 15 | node = node.right -------------------------------------------------------------------------------- /common/heap-sort.py: -------------------------------------------------------------------------------- 1 | #O(LogN), used when part of the array is already heapified. 2 | def heapify(A, N, i): 3 | largest = i 4 | l = i*2+1 5 | r = i*2+2 6 | 7 | if lA[largest]: largest = l 8 | if rA[largest]: largest = r 9 | if largest!=i: 10 | A[largest], A[i] = A[i], A[largest] 11 | heapify(A, N, largest) 12 | 13 | #O(NLogN) 14 | def heapSort(A): 15 | N = len(A) 16 | 17 | #build max heap, O(NLogN). Can be optimized to the O(N). 18 | for i in range(N//2-1, -1, -1): 19 | heapify(A, N, i) 20 | 21 | #keep swapping the largest 22 | for i in range(N-1, -1, -1): 23 | A[0], A[i] = A[i], A[0] 24 | heapify(A, i, 0) 25 | 26 | 27 | A = [12, 11, 13, 5, 6, 7] 28 | heapSort(A) 29 | print(A) 30 | 31 | A = [1, 3, 5, 4, 6, 13, 10, 9, 8, 15, 17] 32 | heapSort(A) 33 | print(A) -------------------------------------------------------------------------------- /common/insertion-sort.py: -------------------------------------------------------------------------------- 1 | def insertionSort(nums): 2 | for i in xrange(len(nums)): 3 | num = nums[i] 4 | j = i-1 5 | while j>=0 and nummw: 14 | K[i][mw] = K[i-1][mw] 15 | else: 16 | K[i][mw] = max(v+K[i-1][mw-w], K[i-1][mw]) 17 | 18 | max_value = K[-1][-1] 19 | 20 | w = max_weight 21 | i = N 22 | while i>0: 23 | if K[i][w]-K[i-1][w]>0: 24 | bag.append(i-1) 25 | w = w - weight[i-1] 26 | i = i-1 27 | 28 | print 'bag: ', bag 29 | print 'max_value', max_value 30 | return max_value 31 | 32 | 33 | value = [60, 100, 120] 34 | weight = [10, 20, 30] 35 | max_weight = 50 36 | get_max_value(value, weight, max_weight) 37 | 38 | value = [40, 100, 50, 60] 39 | weight = [20, 10, 40, 30] 40 | max_weight = 60 41 | get_max_value(value, weight, max_weight) 42 | 43 | -------------------------------------------------------------------------------- /common/merge-sort-in-place.py: -------------------------------------------------------------------------------- 1 | def merge(A, start, mid, end): 2 | L, R = A[start:mid], A[mid:end] 3 | i = j = 0 4 | k = start 5 | for l in xrange(k,end): 6 | if j>=len(R) or (i 1: 15 | mid = (p+r)/2 16 | mergeSort(A, p, mid) 17 | mergeSort(A, mid, r) 18 | merge(A, p, mid, r) 19 | 20 | A = [20, 30, 21, 15, 42, 45, 31, 0, 9] 21 | mergeSort(A, 0, len(A)) 22 | print A 23 | -------------------------------------------------------------------------------- /common/merge-sort.py: -------------------------------------------------------------------------------- 1 | def mergeSort(A): 2 | def merge(a1, a2): 3 | opt = [] 4 | i1 = i2 = 0 5 | while i1=r: return A 4 | 5 | p = A[(l+r)/2] 6 | i = partition(A, l, r, p) 7 | sortRange(A, l, i-1) 8 | sortRange(A, i, r) 9 | return A 10 | 11 | def partition(A, l, r, p): 12 | while l<=r: 13 | while A[l]p: r -= 1 15 | if l<=r: 16 | A[l], A[r] = A[r], A[l] 17 | l += 1 18 | r -= 1 19 | return l 20 | 21 | return sortRange(A, 0, len(A)-1) 22 | 23 | 24 | A = [5,2,4,1,3,6,0] 25 | print quickSort(A) 26 | 27 | 28 | """ 29 | Time Complexity is O(NlogN) on best and average case. 30 | O(N^2) on the worst case, because if you choose the smallest pivot everytime the array will decay in a linear time. 31 | Space Complexity O(LogN), for we need to store the stack for the recursion. 32 | """ -------------------------------------------------------------------------------- /common/radix-sort.py: -------------------------------------------------------------------------------- 1 | def radixSort(nums): 2 | maxNumberOfDigits = len(str(max(nums))) 3 | 4 | for d in xrange(maxNumberOfDigits): 5 | b = [[] for _ in xrange(10)] 6 | 7 | for num in nums: 8 | n = (num//10**d)%10 9 | print num, d, n 10 | b[n].append(num) 11 | 12 | i = 0 13 | for a in b: 14 | for num in a: 15 | nums[i] = num 16 | i += 1 17 | 18 | 19 | test = [21, 4, 1, 3, 9, 20, 25, 6, 21, 14] 20 | radixSort(test) 21 | print test -------------------------------------------------------------------------------- /problems/python/3sum-closest.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def threeSumClosest(self, nums, target): 3 | ans = float('inf') 4 | N = len(nums) 5 | 6 | nums.sort() 7 | 8 | for i in xrange(N): 9 | l = i+1 10 | r = N-1 11 | 12 | while ltarget: 18 | r -= 1 19 | elif s9: 7 | total = 0 8 | for d in str(num): 9 | total+=int(d) 10 | num = total 11 | return num -------------------------------------------------------------------------------- /problems/python/add-strings.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def addStrings(self, nums1, nums2): 3 | ans = '' 4 | i = len(nums1)-1 5 | j = len(nums2)-1 6 | 7 | carry = 0 8 | while 0<=i and 0<=j: 9 | n1 = int(nums1[i]) 10 | n2 = int(nums2[j]) 11 | total = n1+n2+carry 12 | n = total%10 13 | carry = 1 if total>=10 else 0 14 | ans = str(n)+ans 15 | i -= 1 16 | j -= 1 17 | 18 | while 0<=i: 19 | total = int(nums1[i])+carry 20 | n = total%10 21 | carry = 1 if total>=10 else 0 22 | ans = str(n)+ans 23 | i -= 1 24 | 25 | while 0<=j: 26 | total = int(nums2[j])+carry 27 | n = total%10 28 | carry = 1 if total>=10 else 0 29 | ans = str(n)+ans 30 | j -= 1 31 | 32 | if carry: ans = str(carry)+ans 33 | 34 | return ans -------------------------------------------------------------------------------- /problems/python/best-time-to-buy-an-stock.py: -------------------------------------------------------------------------------- 1 | """ 2 | First setup a memo 3 | The value in memo is the max profit we are going to get when we only look at 0~i 4 | For every i, we either sell or not sell 5 | * If we sell, the max profit is price now - lowest price before (prices[i]-min_price). 6 | * If we not sell, the max profit we get now is the same as yesterday. 7 | Every i between these two we pick the max. 8 | So we iterate from 0 to the end. 9 | """ 10 | class Solution(object): 11 | def maxProfit(self, prices): 12 | if prices is None or len(prices)==0: return 0 13 | 14 | memo = [0]*len(prices) 15 | min_price = float('inf') 16 | 17 | for i in xrange(len(prices)): 18 | min_price = min(min_price, prices[i]) 19 | if i==0: continue 20 | memo[i] = max(prices[i]-min_price, memo[i-1]) 21 | return memo[-1] -------------------------------------------------------------------------------- /problems/python/best-time-to-buy-and-sell-stock.py: -------------------------------------------------------------------------------- 1 | """ 2 | To accomplish 0(N) solution: 3 | For each i and price in the iteration, we need to keep track of the loest price before i. 4 | Also, update the max_profit in the iteration. 5 | """ 6 | class Solution(object): 7 | def maxProfit(self, prices): 8 | if not prices: return 0 9 | max_profit = 0 10 | lowest = prices[0] 11 | 12 | for i in xrange(len(prices)): 13 | if i==0: continue 14 | max_profit = max(max_profit, prices[i]-lowest) 15 | lowest = min(lowest, prices[i]) 16 | return max_profit -------------------------------------------------------------------------------- /problems/python/big-countries.sql: -------------------------------------------------------------------------------- 1 | -- https://leetcode.com/problems/big-countries/ 2 | select name, population, area from World where area>3000000 or population>25000000 -------------------------------------------------------------------------------- /problems/python/binary-subarrays-with-sum.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def numSubarraysWithSum(self, nums, goal): 3 | #number of subarrays with sum at most "goal" 4 | def atMost(goal): 5 | ans = 0 6 | total = 0 7 | i = 0 8 | 9 | for j, num in enumerate(nums): 10 | if num==1: total += 1 11 | 12 | while igoal: 13 | if nums[i]==1: total -= 1 14 | i += 1 15 | 16 | ans += j-i+1 #number of subarrays that can generate from nums[i~j] 17 | return ans 18 | 19 | return atMost(goal)-atMost(goal-1) if goal>0 else atMost(goal) -------------------------------------------------------------------------------- /problems/python/binary-tree-inorder-traversal.py: -------------------------------------------------------------------------------- 1 | """ 2 | In-order traversal means that: if there is a left node, visit it first; visit the current node; then if there is right node, visit it. 3 | In-order: Left->Current->Right 4 | Pre-order: Current->Left->Right 5 | Post-order: Left->Right->Current 6 | """ 7 | class Solution(object): 8 | def inorderTraversal(self, root): 9 | def helper(node): 10 | if not node: return 11 | helper(node.left) 12 | opt.append(node.val) 13 | helper(node.right) 14 | 15 | opt = [] 16 | helper(root) 17 | return opt 18 | -------------------------------------------------------------------------------- /problems/python/binary-tree-longest-consecutive-sequence.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(N) 3 | Space: O(N) 4 | 5 | Use DFS to traverse the tree along with the consecutive sequence count for the node. 6 | """ 7 | class Solution(object): 8 | def longestConsecutive(self, root): 9 | if not root: return 0 10 | ans = 1 11 | stack = [(root, 1)] 12 | 13 | while stack: 14 | node, count = stack.pop() 15 | ans = max(ans, count) 16 | 17 | if node.left: 18 | stack.append((node.left, count+1 if node.val+1==node.left.val else 1)) 19 | if node.right: 20 | stack.append((node.right, count+1 if node.val+1==node.right.val else 1)) 21 | 22 | return ans -------------------------------------------------------------------------------- /problems/python/binary-tree-pruning.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def pruneTree(self, root): 3 | def hasOne(node): 4 | if not node: return False 5 | 6 | left_has_one = hasOne(node.left) 7 | right_has_one = hasOne(node.right) 8 | 9 | if not left_has_one: node.left = None 10 | if not right_has_one: node.right = None 11 | 12 | return node.val==1 or left_has_one or right_has_one 13 | 14 | return root if hasOne(root) else None 15 | 16 | class Solution(object): 17 | def pruneTree(self, node): 18 | if not node: return None 19 | node.left = self.pruneTree(node.left) 20 | node.right = self.pruneTree(node.right) 21 | if not node.left and not node.right and node.val==0: return None 22 | return node 23 | 24 | """ 25 | Time complexity is O(N). Because we traverse all the nodes. 26 | Space complexity is O(N). In the worst case, the recursion will go O(N) level deep. 27 | """ -------------------------------------------------------------------------------- /problems/python/binary-watch.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(1) 3 | Space: O(1), no "extra" space are used. 4 | """ 5 | class Solution(object): 6 | def readBinaryWatch(self, turnedOn): 7 | ans = [] 8 | if turnedOn>8: return ans #at most 8 LED are turned on for a valid time. 9 | 10 | for h in xrange(12): 11 | for m in xrange(60): 12 | if (bin(h) + bin(m)).count('1')==turnedOn: 13 | ans.append('%d:%02d' % (h, m)) 14 | return ans -------------------------------------------------------------------------------- /problems/python/buildings-with-an-ocean-view.py: -------------------------------------------------------------------------------- 1 | """ 2 | Traverse from the right and keep track of the highest building. 3 | 4 | Time: O(N) 5 | Space: O(1) 6 | """ 7 | class Solution(object): 8 | def findBuildings(self, heights): 9 | ans = [] 10 | currMaxHeight = 0 11 | for i in xrange(len(heights)-1, -1, -1): 12 | h = heights[i] 13 | if h>currMaxHeight: ans.append(i) 14 | currMaxHeight = max(currMaxHeight, h) 15 | 16 | return reversed(ans) -------------------------------------------------------------------------------- /problems/python/candy.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def candy(self, ratings): 3 | N = len(ratings) 4 | 5 | l2r = [1]*N 6 | r2l = [1]*N 7 | 8 | for i in xrange(1, N): 9 | if ratings[i]>ratings[i-1]: 10 | l2r[i] = l2r[i-1]+1 11 | 12 | for i in xrange(N-2, -1, -1): 13 | if ratings[i]>ratings[i+1]: 14 | r2l[i] = r2l[i+1]+1 15 | 16 | ans = 0 17 | for i in xrange(N): 18 | ans += max(l2r[i], r2l[i]) 19 | 20 | return ans 21 | -------------------------------------------------------------------------------- /problems/python/closest-binary-search-tree-value.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(LogN) 3 | Space: O(1) 4 | 5 | Basically we are going to search the target in the BST. 6 | Along the way, we compare it with the `ans`, if the difference is smaller, update it. 7 | """ 8 | class Solution(object): 9 | def closestValue(self, root, target): 10 | node = root 11 | ans = float('inf') 12 | 13 | while node: 14 | if not node: break 15 | 16 | if abs(ans-target)>abs(node.val-target): 17 | ans = node.val 18 | 19 | if target>node.val: 20 | node = node.right 21 | else: 22 | node = node.left 23 | 24 | return ans -------------------------------------------------------------------------------- /problems/python/combine-two-tables.sql: -------------------------------------------------------------------------------- 1 | -- https://leetcode.com/problems/combine-two-tables/ 2 | select FirstName, LastName, City, State 3 | from Person left join Address 4 | on Person.PersonId = Address.PersonId -------------------------------------------------------------------------------- /problems/python/contains-duplicate-ii.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(N) 3 | Space: O(N) 4 | """ 5 | class Solution(object): 6 | def containsNearbyDuplicate(self, nums, k): 7 | lastSeen = {} 8 | 9 | for i, num in enumerate(nums): 10 | if num in lastSeen: 11 | if i-lastSeen[num]<=k: return True 12 | lastSeen[num] = i 13 | 14 | return False -------------------------------------------------------------------------------- /problems/python/contains-duplicate.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(N) 3 | Space: O(N) 4 | """ 5 | class Solution(object): 6 | def containsDuplicate(self, nums): 7 | seen = set() 8 | 9 | for num in nums: 10 | if num in seen: return True 11 | seen.add(num) 12 | 13 | return False -------------------------------------------------------------------------------- /problems/python/count-all-valid-pickup-and-delivery-opti.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def countOrders(self, n): 3 | d = 1 4 | for i in xrange(1, 2*n, 2): d*=i 5 | return math.factorial(n)*d % (10**9 + 7) -------------------------------------------------------------------------------- /problems/python/count-binary-substrings.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def countBinarySubstrings(self, s): 3 | groups = [] 4 | count = 0 5 | last = s[0] 6 | ans = 0 7 | 8 | for bit in s: 9 | if bit==last: 10 | count += 1 11 | else: 12 | groups.append(count) 13 | count = 1 14 | last = bit 15 | 16 | groups.append(count) 17 | 18 | for i in xrange(1, len(groups)): 19 | ans += min(groups[i], groups[i-1]) 20 | 21 | return ans -------------------------------------------------------------------------------- /problems/python/count-complete-tree-nodes.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(H^2). The time complexity will countNodes() will be LogH if the tree is perfect. 3 | If not, we will need Log(H-1) 4 | 5 | Space: O(H) 6 | """ 7 | class Solution(object): 8 | def countNodes(self, root): 9 | if not root: return 0 10 | 11 | node = root 12 | l = 1 #level on the right side 13 | while node.left: 14 | node = node.left 15 | l += 1 16 | 17 | node = root 18 | r = 1 #level on the left side 19 | while node.right: 20 | node = node.right 21 | r += 1 22 | 23 | if l==r: 24 | #perfect tree 25 | return (2**r)-1 26 | else: 27 | return 1+self.countNodes(root.left)+self.countNodes(root.right) -------------------------------------------------------------------------------- /problems/python/count-number-of-nice-subarrays.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def numberOfSubarrays(self, nums, K): 3 | def atMost(k): 4 | oddCount = 0 5 | ans = 0 6 | i = 0 7 | 8 | for j in xrange(len(nums)): 9 | if nums[j]%2!=0: oddCount += 1 10 | 11 | while oddCount>k: 12 | if nums[i]%2!=0: oddCount -= 1 13 | i += 1 14 | 15 | ans += j-i+1 16 | 17 | return ans 18 | 19 | return atMost(K)-atMost(K-1) -------------------------------------------------------------------------------- /problems/python/count-unique-characters-of-all-substrings-of-a-given-string.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def uniqueLetterString(self, s): 3 | index = {} 4 | ans = 0 5 | for c in 'abcdefghijklmnopqrstuvwxyz': 6 | index[c.upper()] = [-1, -1] 7 | 8 | # count the substring that s[j] is the unique letter 9 | for k, c in enumerate(s): 10 | i, j = index[c] 11 | ans += (j-i) * (k-j) 12 | index[c] = [j, k] 13 | 14 | # count the substring that s[j] is the unique letter, because last iteration did not count the last letter 15 | for c in index: 16 | i, j = index[c] 17 | ans += (j-i) * (len(s)-j) 18 | return ans -------------------------------------------------------------------------------- /problems/python/custom-sort-string.py: -------------------------------------------------------------------------------- 1 | """ 2 | Take a look at the char in s. 3 | For the char that is in the order, rearrange them to sortedChars with respect to the "order". 4 | For the char that is in not the order, put them in postString. 5 | """ 6 | class Solution(object): 7 | def customSortString(self, order, s): 8 | sortedChars = '' 9 | counter = collections.Counter(s) 10 | for c in order: 11 | if c in order: 12 | sortedChars += c*counter[c] 13 | 14 | orderSet = set(order) 15 | postString = '' 16 | for c in s: 17 | if c not in orderSet: 18 | postString += c 19 | 20 | return sortedChars+postString -------------------------------------------------------------------------------- /problems/python/cutting-ribbons.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def maxLength(self, ribbons, k): 3 | maxLen = max(ribbons) 4 | minLen = 0 5 | 6 | while minLen=k: 10 | minLen = l 11 | else: 12 | maxLen = l-1 13 | return maxLen -------------------------------------------------------------------------------- /problems/python/decode-ways.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(N), due to the "memo", the time can reduce from O(2^N) to O(N). 3 | Space: O(N) 4 | """ 5 | class Solution(object): 6 | def numDecodings(self, s): 7 | def helper(s, i): 8 | if (s, i) in memo: return memo[(s, i)] 9 | if i>=len(s): return 1 10 | if s[i]=='0': return 0 11 | 12 | count = 0 13 | count += helper(s, i+1) 14 | if len(s)-i>=2 and int(s[i:i+2])<=26: count += helper(s, i+2) 15 | memo[(s, i)] = count 16 | return count 17 | 18 | memo = {} 19 | return helper(s, 0) -------------------------------------------------------------------------------- /problems/python/delete-and-earn.py: -------------------------------------------------------------------------------- 1 | import collections 2 | 3 | class Solution(object): 4 | def deleteAndEarn(self, nums): 5 | if not nums: return 0 6 | m = min(nums) 7 | M = max(nums) 8 | c = collections.Counter(nums) 9 | 10 | prev = 0 11 | curr = 0 12 | for n in xrange(m, M+1): 13 | prev, curr = curr, max(prev+n*c[n], curr) 14 | return curr -------------------------------------------------------------------------------- /problems/python/design-linked-list.py: -------------------------------------------------------------------------------- 1 | class Node(object): 2 | def __init__(self, val): 3 | self.val = val 4 | self.next = None 5 | 6 | class MyLinkedList(object): 7 | def __init__(self): 8 | self.l = [] #trade space for speed 9 | 10 | def get(self, index): #O(1) 11 | if index<0 or index>=len(self.l): 12 | return -1 13 | return self.l[index].val 14 | 15 | def addAtHead(self, val): #O(N), list extend takes O(N), . 16 | self.l = [Node(val)]+self.l 17 | 18 | def addAtTail(self, val): #O(N) 19 | self.l = self.l+[Node(val)] 20 | 21 | def addAtIndex(self, index, val): #O(N) 22 | self.l = self.l[:index]+[Node(val)]+self.l[index:] 23 | 24 | def deleteAtIndex(self, index): #O(N) 25 | self.l = self.l[:index]+self.l[index+1:] 26 | -------------------------------------------------------------------------------- /problems/python/diagonal-traverse.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def findDiagonalOrder(self, mat): 3 | def helper(i, j, reverse): 4 | output = [] 5 | while 0<=i=2: ans.append(data[s][0]) 16 | return ans -------------------------------------------------------------------------------- /problems/python/find-eventual-safe-states.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict, deque 2 | 3 | class Solution(object): 4 | def eventualSafeNodes(self, graph): 5 | inbounds = defaultdict(list) 6 | outbondsCounter = defaultdict(int) 7 | q = deque() 8 | ans = [] 9 | 10 | for n, nei_list in enumerate(graph): 11 | outbondsCounter[n] = len(nei_list) 12 | for nei in nei_list: 13 | inbounds[nei].append(n) 14 | 15 | for n in outbondsCounter: 16 | if outbondsCounter[n]==0: 17 | q.append(n) 18 | 19 | while q: 20 | n = q.popleft() 21 | 22 | for nei in inbounds[n]: 23 | outbondsCounter[nei] -= 1 24 | if outbondsCounter[nei]==0: 25 | q.append(nei) 26 | 27 | ans.append(n) 28 | 29 | return ans.sort() -------------------------------------------------------------------------------- /problems/python/find-k-closest-elements.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def findClosestElements(self, arr, K, X): 3 | def isCloserThan(n1, n2, x): 4 | return abs(x-n1)=len(arr) or (l>=0 and isCloserThan(arr[l], arr[r], X)): 14 | output1.append(arr[l]) 15 | l -= 1 16 | else: 17 | output2.append(arr[r]) 18 | r += 1 19 | 20 | return output1[::-1]+output2 21 | -------------------------------------------------------------------------------- /problems/python/find-original-array-from-doubled-array,py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(NLogN) 3 | Space: O(N) 4 | """ 5 | class Solution(object): 6 | def findOriginalArray(self, changed): 7 | if len(changed)%2!=0: return [] 8 | 9 | ans = [] 10 | counter = collections.Counter() #store the count of the doubled number 11 | count = 0 #sum of count in counter 12 | 13 | changed.sort() #need to be sorted, otherwise we cannot identify which number is orginal or it is doubled. 14 | 15 | for num in changed: 16 | if counter[num]>0: 17 | #num is a doubled num 18 | counter[num] -= 1 19 | count -= 1 20 | ans.append(num/2) 21 | else: 22 | #num is an original num 23 | counter[num*2] += 1 24 | count += 1 25 | 26 | return ans if count==0 else [] -------------------------------------------------------------------------------- /problems/python/find-the-duplicate-number.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(N) 3 | Space: O(1) 4 | 5 | Floyd's Tortoise and Hare Algorithm: Given a linked list, return the node where the cycle begins. 6 | """ 7 | class Solution(object): 8 | def findDuplicate(self, nums): 9 | 10 | #find the intersect node, where slow and fast pointer meets. 11 | slow = fast = 0 12 | while True: 13 | slow = nums[slow] 14 | fast = nums[nums[fast]] 15 | if slow==fast: break 16 | 17 | #find the intersect node, where slow and slow2 pointer meets. slow2 is starting from the begin. 18 | slow2 = 0 19 | while True: 20 | slow = nums[slow] 21 | slow2 = nums[slow2] 22 | if slow==slow2: return slow 23 | 24 | return 0 -------------------------------------------------------------------------------- /problems/python/first-unique-character-in-a-string.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | class Solution(object): 4 | def firstUniqChar(self, string): 5 | # counter = Counter() 6 | # for char in string: 7 | # counter[char]+=1 8 | counter = Counter(string) 9 | 10 | for i in xrange(len(string)): 11 | char = string[i] 12 | if counter[char]==1: return i 13 | 14 | return -1 15 | -------------------------------------------------------------------------------- /problems/python/fizz-buzz.py: -------------------------------------------------------------------------------- 1 | #https://leetcode.com/problems/fizz-buzz/ 2 | class Solution(object): 3 | def fizzBuzz(self, n): 4 | nums = [] 5 | for num in range(1, n+1): 6 | 7 | if num%3==0 and num%5==0: 8 | nums.append('FizzBuzz') 9 | elif num%3==0: 10 | nums.append('Fizz') 11 | elif num%5==0: 12 | nums.append('Buzz') 13 | else: 14 | nums.append(str(num)) 15 | 16 | return nums -------------------------------------------------------------------------------- /problems/python/flip-binary-tree-to-match-preorder-traversal.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def flipMatchVoyage(self, root, voyage): 3 | def helper(node): 4 | if not node: return 5 | if node.val!=voyage[self.i]: 6 | self.valid = False 7 | return 8 | 9 | self.i += 1 10 | if node.left and node.left.val!=voyage[self.i]: 11 | self.ans.append(node.val) 12 | helper(node.right) 13 | helper(node.left) 14 | 15 | else: 16 | helper(node.left) 17 | helper(node.right) 18 | 19 | self.ans = [] 20 | self.i = 0 21 | self.valid = True 22 | helper(root) 23 | return self.ans if self.valid else [-1] -------------------------------------------------------------------------------- /problems/python/flip-string-to-monotone-increasing.py: -------------------------------------------------------------------------------- 1 | """ 2 | dp[i][0] := min number of flips to form monotone string that ends s[:i] at 0 3 | dp[i][1] := min number of flips to form monotone string that ends s[:i] at 1 4 | 5 | Time: O(N) 6 | Space: O(N), can further deduce to O(1) 7 | """ 8 | class Solution(object): 9 | def minFlipsMonoIncr(self, s): 10 | dp = [[0, 0] for _ in xrange(len(s)+1)] 11 | 12 | for i, c in enumerate(s): 13 | if c=='0': 14 | dp[i+1][0] = dp[i][0] 15 | dp[i+1][1] = min(dp[i][0], dp[i][1]) + 1 16 | elif c=='1': 17 | dp[i+1][0] = dp[i][0] + 1 18 | dp[i+1][1] = min(dp[i][0], dp[i][1]) 19 | 20 | return min(dp[-1]) -------------------------------------------------------------------------------- /problems/python/flood-fill.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def floodFill(self, image, sr, sc, newColor): 3 | stack = [(sr, sc)] 4 | originColor = image[sr][sc] 5 | 6 | while stack: 7 | i, j = stack.pop() 8 | 9 | if image[i][j]==newColor or image[i][j]!=originColor: continue 10 | 11 | image[i][j] = newColor 12 | if i+1=0 else 26+(getNumByChar(c)+offset)) 8 | return h 9 | 10 | def getNumByChar(letter): 11 | return ord(letter) - 97 12 | 13 | def getCharByNum(pos): 14 | return chr(pos + 97) 15 | 16 | groups = collections.defaultdict(list) 17 | for string in strings: 18 | h = getHash(string) 19 | groups[h].append(string) 20 | return groups.values() -------------------------------------------------------------------------------- /problems/python/guess-number-higher-or-lower-ii.py: -------------------------------------------------------------------------------- 1 | """ 2 | dp[i][j] := min money guarantee to win within i~j 3 | k is the first guess, try all k and update dp[i][j]. 4 | """ 5 | class Solution(object): 6 | def getMoneyAmount(self, N): 7 | dp = [[float('inf') for _ in xrange(N)] for _ in xrange(N)] 8 | for i in xrange(N): dp[i][i] = 0 9 | 10 | 11 | for l in xrange(2, N+1): 12 | for i in xrange(N): 13 | j = i+l-1 14 | if j>=N: continue 15 | for k in xrange(i, j+1): 16 | dp[i][j] = min(dp[i][j], max(dp[i][k-1] if k-1>=0 else 0, dp[k+1][j] if k+1 do nothing. 8 | 1. Smaller than min1 => update min1. 9 | 2. Larger than min1 and smaller than min2 => update min2. 10 | 3. Larger than min2 => return True. 11 | """ 12 | class Solution(object): 13 | def increasingTriplet(self, nums): 14 | min1 = min2 = float('inf') 15 | 16 | for n in nums: 17 | if n=len(s): break 7 | if s[i]==c: i += 1 8 | 9 | return i==len(s) -------------------------------------------------------------------------------- /problems/python/jewels-and-stones.py: -------------------------------------------------------------------------------- 1 | #https://leetcode.com/problems/jewels-and-stones/ 2 | class Solution(object): 3 | def numJewelsInStones(self, J, S): 4 | n=0 5 | for j in J: 6 | n+=S.count(j) 7 | return n -------------------------------------------------------------------------------- /problems/python/jump-game.py: -------------------------------------------------------------------------------- 1 | """ 2 | Let's reverse engineer the process. 3 | Imagine you are standing at the last index i 4 | index i-1 will need the value>=1 to go to i (step_need=1) 5 | index i-2 will need the value>=2 to go to i (step_need=2) 6 | ... 7 | 8 | At a certain index x, the value>=step_need 9 | This means that, from x, we can go to i no problem. 10 | Now we are standing at x and reset step_need to 0. 11 | See if we can repeat the process until we reach the first index. 12 | """ 13 | class Solution(object): 14 | def canJump(self, nums): 15 | step_need = 0 16 | for num in reversed(nums[:-1]): 17 | step_need+=1 18 | if num>=step_need: 19 | step_need = 0 20 | return step_need==0 -------------------------------------------------------------------------------- /problems/python/keys-and-rooms.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def canVisitAllRooms(self, rooms): 3 | if not rooms: return True 4 | 5 | visited = set() 6 | stack = [0] 7 | 8 | while stack: 9 | key = stack.pop() 10 | if key in visited: continue 11 | visited.add(key) 12 | stack.extend(rooms[key]) 13 | 14 | return len(rooms)==len(visited) 15 | 16 | """ 17 | Time: O(N). 18 | Space: O(N). 19 | N is the number of rooms. 20 | """ -------------------------------------------------------------------------------- /problems/python/last-stone-weight.py: -------------------------------------------------------------------------------- 1 | import bisect 2 | class Solution(object): 3 | def lastStoneWeight(self, stones): 4 | stones.sort() 5 | 6 | while len(stones)>1: 7 | x = stones.pop() 8 | y = stones.pop() 9 | bisect.insort_left(stones, abs(x-y)) 10 | 11 | return 0 if not stones else stones[0] 12 | 13 | import heapq 14 | class Solution(object): 15 | def lastStoneWeight(self, stones): 16 | h = [] 17 | 18 | for stone in stones: 19 | heapq.heappush(h, stone*-1) 20 | 21 | while len(h)>1: 22 | x = heapq.heappop(h) 23 | y = heapq.heappop(h) 24 | heapq.heappush(h, abs(x-y)*-1) 25 | 26 | return 0 if not h else abs(h[0]) -------------------------------------------------------------------------------- /problems/python/least-number-of-unique-integers-after-k-removals.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: Build counter takes O(N). Build heap takes O(NLogN). Last operation takes O(KLogN). 3 | Since N>k, O(N+NLogN+KLogN) ~= O(NLogN) 4 | 5 | Space: O(N) 6 | """ 7 | class Solution(object): 8 | def findLeastNumOfUniqueInts(self, nums, k): 9 | counter = collections.Counter(nums) 10 | h = [] 11 | 12 | for num in counter: 13 | heapq.heappush(h, (counter[num], num)) 14 | 15 | for _ in xrange(k): 16 | count, num = heapq.heappop(h) 17 | count -= 1 18 | if count>0: heapq.heappush(h, (count, num)) 19 | 20 | return len(h) -------------------------------------------------------------------------------- /problems/python/letter-case-permutation.py: -------------------------------------------------------------------------------- 1 | """ 2 | For each character in the `S` (if it is not a number), it has 2 possibilities, upper or lower. 3 | So starting from an empty string 4 | We explore all the possibilities for the character at index i is upper or lower. 5 | 6 | The time complexity is `O(2^N)`. 7 | The space took `O(2^N), too. And the recursion level has N level. 8 | """ 9 | class Solution(object): 10 | def letterCasePermutation(self, S): 11 | def dfs(path, i): 12 | if i>=len(S): 13 | opt.append(path) 14 | return 15 | if S[i] not in num_char: 16 | dfs(path+S[i].upper(), i+1) 17 | dfs(path+S[i].lower(), i+1) 18 | else: 19 | dfs(path+S[i], i+1) 20 | 21 | num_char = set(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']) 22 | opt = [] 23 | dfs('', 0) 24 | return opt 25 | -------------------------------------------------------------------------------- /problems/python/letter-combinations-of-a-phone-number.py: -------------------------------------------------------------------------------- 1 | """ 2 | I put all the posible answer in the `ans`. 3 | For every digit in the input, we got whole new sets of answers, which is generated from the previous input. 4 | """ 5 | class Solution(object): 6 | def letterCombinations(self, digits): 7 | def helper(A, digit): 8 | if not A: return memo[digit] 9 | 10 | opt = [] 11 | for letter in memo[digit]: 12 | for string in A: 13 | opt.append(string+letter) 14 | return opt 15 | 16 | ans = [] 17 | memo = { 18 | '2': ['a', 'b', 'c'], 19 | '3': ['d', 'e', 'f'], 20 | '4': ['g', 'h', 'i'], 21 | '5': ['j', 'k', 'l'], 22 | '6': ['m', 'n', 'o'], 23 | '7': ['p', 'q', 'r', 's'], 24 | '8': ['t', 'u', 'v'], 25 | '9': ['w', 'x', 'y', 'z'] 26 | } 27 | 28 | for digit in digits: 29 | ans = helper(ans, digit) 30 | return ans 31 | -------------------------------------------------------------------------------- /problems/python/license-key-formatting.py: -------------------------------------------------------------------------------- 1 | #https://leetcode.com/problems/license-key-formatting/ 2 | class Solution(object): 3 | def licenseKeyFormatting(self, S, K): 4 | r = '' 5 | s = S.replace('-', '').upper() 6 | 7 | #cut first part of string 8 | remainder = len(s)%K 9 | if remainder!=0: 10 | r = s[:remainder]+'-' 11 | s = s[remainder:] 12 | 13 | while len(s)>0: 14 | r += s[:K]+'-' 15 | s = s[K:] 16 | 17 | #remove last '-' 18 | r = r[:-1] 19 | 20 | return r -------------------------------------------------------------------------------- /problems/python/linked-list-cycle-ii.py: -------------------------------------------------------------------------------- 1 | #Flag 2 | #Use a flag that stores on the nodes to know if we visited or not. 3 | #time: O(N). 4 | #space: O(N), for each node we use O(1) and there are N nodes. 5 | class Solution(object): 6 | def detectCycle(self, head): 7 | curr = head 8 | while curr: 9 | if hasattr(curr, 'visited') and curr.visited: return curr 10 | curr.visited = True 11 | curr = curr.next 12 | return None 13 | 14 | #HashSet 15 | #Use a hash-set to store the visited nodes 16 | #time: O(N). 17 | #space: O(N). 18 | class Solution(object): 19 | def detectCycle(self, head): 20 | visited = set() 21 | curr = head 22 | while curr: 23 | if curr in visited: return curr 24 | visited.add(curr) 25 | curr = curr.next 26 | return None -------------------------------------------------------------------------------- /problems/python/linked-list-random-node.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(N) for __init__() and getRandom() 3 | Space: O(1) 4 | """ 5 | class Solution(object): 6 | 7 | def __init__(self, head): 8 | self.count = 1 9 | self.curr = head 10 | 11 | while self.curr.next: 12 | self.curr = self.curr.next 13 | self.count += 1 14 | self.curr.next = head 15 | 16 | 17 | def getRandom(self): 18 | rand = randrange(self.count) 19 | while rand>0: 20 | rand -= 1 21 | self.curr = self.curr.next 22 | return self.curr.val -------------------------------------------------------------------------------- /problems/python/logger-rate-limiter.py: -------------------------------------------------------------------------------- 1 | class Logger(object): 2 | def __init__(self): 3 | self.log = collections.Counter() #store the latest timestamp 4 | 5 | def shouldPrintMessage(self, timestamp, message): 6 | if message not in self.log or self.log[message]+10<=timestamp: 7 | self.log[message] = timestamp 8 | return True 9 | else: 10 | return False 11 | 12 | 13 | 14 | class Logger(object): 15 | 16 | def __init__(self): 17 | #stores the messages within 10 seconds 18 | self.q = collections.deque() 19 | self.set = set() 20 | 21 | 22 | def shouldPrintMessage(self, timestamp, message): 23 | while self.q and timestamp-self.q[0][0]>=10: 24 | time, msg = self.q.popleft() 25 | self.set.remove(msg) 26 | 27 | if message not in self.set: 28 | self.q.append((timestamp, message)) 29 | self.set.add(message) 30 | return True 31 | else: 32 | return False -------------------------------------------------------------------------------- /problems/python/longest-common-subsequence.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def longestCommonSubsequence(self, text1, text2): 3 | M, N = len(text1), len(text2) 4 | 5 | #dp[i][j] := logest subsequence of text1[0:i-1] and text[0:j-1] 6 | dp = [[0 for _ in xrange(N+1)] for _ in xrange(M+1)] 7 | 8 | for i in xrange(1, M+1): 9 | for j in xrange(1, N+1): 10 | if text1[i-1]==text2[j-1]: 11 | dp[i][j] = dp[i-1][j-1]+1 12 | else: 13 | dp[i][j] = max(dp[i-1][j], dp[i][j-1]) 14 | 15 | return dp[M][N] 16 | 17 | """ 18 | Time: O(MN) 19 | Space: O(MN) 20 | """ 21 | 22 | -------------------------------------------------------------------------------- /problems/python/longest-consecutive-sequence.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(N), the while loop will only be executed if `n` is the beginning of a consecutive sequence. So each n will only be iterated once. 3 | Space: O(N). 4 | 5 | For each `n` in the set, check if it is a beginning of a consecutive sequence. (`n-1 not in s`) 6 | If so, get the length of the consecutive sequence (`c`) and update the `ans`. 7 | """ 8 | class Solution(object): 9 | def longestConsecutive(self, nums): 10 | s = set(nums) 11 | ans = 0 12 | 13 | for n in s: 14 | if n-1 not in s: 15 | c = 1 16 | curr = n 17 | 18 | while curr+1 in s: 19 | curr = curr+1 20 | c += 1 21 | 22 | ans = max(ans, c) 23 | 24 | return ans -------------------------------------------------------------------------------- /problems/python/longest-palindromic-subsequence.py: -------------------------------------------------------------------------------- 1 | """ 2 | dp[i][j] := longest palindromic subsequence of s[i:j+1] 3 | """ 4 | class Solution(object): 5 | def longestPalindromeSubseq(self, s): 6 | N = len(s) 7 | 8 | dp = [[0 for _ in xrange(N)] for _ in xrange(N)] 9 | for i in xrange(N): dp[i][i] = 1 10 | 11 | for l in xrange(2, N+1): 12 | for i in xrange(N): 13 | j = i+l-1 14 | if j>=N: continue 15 | dp[i][j] = dp[i+1][j-1]+2 if s[i]==s[j] else max(dp[i+1][j], dp[i][j-1]) 16 | 17 | return dp[0][N-1] -------------------------------------------------------------------------------- /problems/python/longest-repeating-character-replacement.py: -------------------------------------------------------------------------------- 1 | """ 2 | Use the sliding window to iterate over the sub-strings. At the same time use a counter to track the count. 3 | The operation needed is the (length of the window) - (count of the max count char in the counter) 4 | Since there are at most 26 char in the counter, `max(counter.values())` can be view as a O(1) operation. 5 | 6 | Time: O(N) 7 | Space: O(N) 8 | """ 9 | class Solution(object): 10 | def characterReplacement(self, s, k): 11 | counter = collections.Counter() 12 | ans = 0 13 | 14 | l = 0 15 | for r in xrange(len(s)): 16 | counter[s[r]] += 1 17 | 18 | while r-l+1-max(counter.values())>k: 19 | counter[s[l]] -= 1 20 | l += 1 21 | 22 | ans = max(ans, r-l+1) 23 | return ans -------------------------------------------------------------------------------- /problems/python/longest-univalue-path.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def longestUnivaluePath(self, root): 3 | def getUnivalueLength(node, val): 4 | if not node: return 0 5 | 6 | l, r = getUnivalueLength(node.left, node.val), getUnivalueLength(node.right, node.val) 7 | self.ans = max(self.ans, l+r) 8 | 9 | if node.val==val: return 1+max(l, r) 10 | return 0 11 | 12 | if not root: return 0 13 | self.ans = float('-inf') 14 | getUnivalueLength(root, root.val) 15 | return self.ans 16 | 17 | """ 18 | The main I idea is simple. 19 | Traverse all the node. 20 | Each node, we assume that the longestUnivaluePath will pass through it. 21 | So we can update the `self.ans` if `l+r` is larger. 22 | At the same time, `getUnivalueLength()` will return the max length of the path (start from itself) which has the value `val`. 23 | """ -------------------------------------------------------------------------------- /problems/python/lowest-common-ancestor-of-a-binary-search-tree.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(LogN). O(N) if the tree is unbalanced. 3 | Space: O(1) 4 | 5 | If both p and q are both on the left subtree, then search the left subtree. 6 | If both p and q are both on the right subtree, then search the right subtree. 7 | Else the current must be the ans. 8 | """ 9 | class Solution(object): 10 | def lowestCommonAncestor(self, root, p, q): 11 | node = root 12 | 13 | while node: 14 | if node.val>q.val and node.val>p.val: 15 | node = node.left 16 | elif node.val=2 and not self.ans: self.ans = node 14 | return count 15 | 16 | dfs(root) 17 | return self.ans 18 | -------------------------------------------------------------------------------- /problems/python/lowest-common-ancestor-of-a-binary-tree-iv.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def __init__(self): 3 | self.ans = None 4 | 5 | def lowestCommonAncestor(self, root, nodes): 6 | def dfs(node): 7 | if not node: return 0 8 | 9 | count = 0 10 | if node in nodes: count += 1 11 | count += dfs(node.left) 12 | count += dfs(node.right) 13 | if count>=len(nodes) and not self.ans: self.ans = node 14 | return count 15 | 16 | nodes = set(nodes) 17 | dfs(root) 18 | return self.ans -------------------------------------------------------------------------------- /problems/python/majority-element-ii.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def majorityElement(self, nums): 3 | ans = [] 4 | counter = {} 5 | requiredCount = len(nums)/3.0 6 | 7 | for n in nums: 8 | if n not in counter: counter[n] = 0 9 | counter[n] += 1 10 | 11 | for n in counter: 12 | if counter[n]>requiredCount: ans.append(n) 13 | 14 | return ans -------------------------------------------------------------------------------- /problems/python/max-consecutive-ones-iii.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def longestOnes(self, nums, k): 3 | ans = 0 4 | zeroCount = 0 5 | i = 0 6 | 7 | for j, num in enumerate(nums): 8 | if num==0: zeroCount += 1 9 | 10 | while zeroCount>k: 11 | if nums[i]==0: zeroCount -= 1 12 | i += 1 13 | ans = max(ans, j-i+1) 14 | 15 | return ans -------------------------------------------------------------------------------- /problems/python/max-stack.py: -------------------------------------------------------------------------------- 1 | #https://leetcode.com/problems/max-stack/ 2 | 3 | #peekMax() and popMax() are O(N) 4 | #Else are O(1) 5 | class MaxStack(object): 6 | 7 | def __init__(self): 8 | self.stack = [] 9 | 10 | 11 | def push(self, x): 12 | self.stack.append(x) 13 | 14 | 15 | def pop(self): 16 | return self.stack.pop() 17 | 18 | 19 | def top(self): 20 | return self.stack[-1] 21 | 22 | 23 | def peekMax(self): 24 | return max(self.stack) 25 | 26 | 27 | def popMax(self): 28 | max_num = None 29 | max_index = None 30 | 31 | for i in range(len(self.stack)): 32 | num = self.stack[i] 33 | if num>=max_num: 34 | max_num = num 35 | max_index = i 36 | 37 | return self.stack.pop(max_index) -------------------------------------------------------------------------------- /problems/python/maximum-average-subtree.py: -------------------------------------------------------------------------------- 1 | """ 2 | Recursivly get the average and count of each node. 3 | Update the self.ans before returning. 4 | 5 | Time: O(N), N is the number of nodes. 6 | Space: O(LogN) for the recursive stack, since the tree hight is LogN if the tree is balanced. 7 | """ 8 | class Solution(object): 9 | def __init__(self): 10 | self.ans = float('-inf') 11 | 12 | def maximumAverageSubtree(self, root): 13 | def getAVGAndCount(node): 14 | if not node: return 0, 0 15 | leftAvg, leftCount = getAVGAndCount(node.left) 16 | rightAvg, rightCount = getAVGAndCount(node.right) 17 | 18 | count = leftCount+rightCount+1 19 | avg = (leftAvg*leftCount + rightAvg*rightCount + node.val)/float(count) 20 | 21 | self.ans = max(self.ans, avg) 22 | return avg, count 23 | 24 | getAVGAndCount(root) 25 | return self.ans -------------------------------------------------------------------------------- /problems/python/maximum-length-of-repeated-subarray.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def findLength(self, A, B): 3 | M, N = len(A), len(B) 4 | 5 | #dp[i][j] := the logest length of sub array that needs to involve A[i] and B[j] 6 | dp = [[0 for _ in xrange(N+1)] for _ in xrange(M+1)] 7 | 8 | for i in xrange(1, M+1): 9 | for j in xrange(1, N+1): 10 | if A[i-1]==B[j-1]: 11 | dp[i][j] = dp[i-1][j-1]+1 12 | 13 | return max(max(row) for row in dp) -------------------------------------------------------------------------------- /problems/python/maximum-number-of-events-that-can-be-attended.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(NLogN). Sort the event takes O(NLogN). Each event will get push in and pop out the heap: O(NLogN) 3 | Space: O(N) 4 | """ 5 | class Solution(object): 6 | def maxEvents(self, A): 7 | d = 0 8 | count = 0 9 | h = [] #a heap. store the started event 10 | A.sort(reverse=True) 11 | 12 | #for each day, attend the event with smallest endtime, so we can have the most free time in the future. 13 | while A or h: 14 | if not h: d = A[-1][0] 15 | 16 | while A and A[-1][0]<=d: 17 | heapq.heappush(h, A.pop()[1]) 18 | 19 | heapq.heappop(h) #attend the event with smallest endtime 20 | count += 1 21 | d += 1 22 | 23 | while h and h[0]0: 12 | units, count = sortedBox.pop() 13 | d = min(count, truckSize) 14 | truckSize -= d 15 | ans += d*units 16 | 17 | return ans -------------------------------------------------------------------------------- /problems/python/meeting-rooms.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(NLogN) 3 | Space: O(1) 4 | 5 | Sort the interval (mainly by start time), see if the end overlaps with the start of next. 6 | """ 7 | class Solution(object): 8 | def canAttendMeetings(self, intervals): 9 | intervals.sort() 10 | 11 | for i in xrange(len(intervals)-1): 12 | end = intervals[i][1] 13 | nextStart = intervals[i+1][0] 14 | if end>nextStart: return False 15 | 16 | return True -------------------------------------------------------------------------------- /problems/python/merge-sorted-array.py: -------------------------------------------------------------------------------- 1 | #https://leetcode.com/problems/merge-sorted-array/ 2 | class Solution(object): 3 | def merge(self, nums1, m, nums2, n): 4 | #Compare nums1 and nums2 from backward 5 | #Put the larger one to nums1's end 6 | #If one of the array is done 7 | #The rest is already sorted 8 | #Just put them in place 9 | 10 | i = m+n-1 #cursor on nums1 that we are editting 11 | i1 = m-1 #cursor on nums1 12 | i2 = n-1 #cursor on nums2 13 | 14 | while i1>=0 and i2>=0: 15 | if nums1[i1]>nums2[i2]: 16 | nums1[i] = nums1[i1] 17 | i1 = i1-1 18 | i = i-1 19 | else: 20 | nums1[i] = nums2[i2] 21 | i2 = i2-1 22 | i = i-1 23 | 24 | #One of the array is done, put the rest in place 25 | nums1[:i2+1] = nums2[:i2+1] -------------------------------------------------------------------------------- /problems/python/merge-two-sorted-lists.py: -------------------------------------------------------------------------------- 1 | #https://leetcode.com/problems/merge-two-sorted-lists/ 2 | 3 | class Solution(object): 4 | def mergeTwoLists(self, l1, l2): 5 | pre_head = ListNode(-1) 6 | curr = pre_head 7 | 8 | while l1 and l2: 9 | if l1.val1: 11 | currSum = heapq.heappop(h)+heapq.heappop(h) 12 | cost += currSum 13 | heapq.heappush(h, currSum) 14 | 15 | return cost -------------------------------------------------------------------------------- /problems/python/minimum-cost-to-reach-city-with-discounts.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def minimumCost(self, n, highways, discounts): 3 | pq = [(0, discounts, 0)] 4 | visited = set() 5 | 6 | adj = collections.defaultdict(list) 7 | for city1, city2, toll in highways: 8 | adj[city1].append((city2, toll)) 9 | adj[city2].append((city1, toll)) 10 | 11 | 12 | while pq: 13 | toll, d, city = heapq.heappop(pq) 14 | if (d, city) in visited: continue 15 | visited.add((d, city)) 16 | 17 | if city==n-1: return toll 18 | 19 | for nei, toll2 in adj[city]: 20 | if (d, nei) not in visited: 21 | heapq.heappush(pq, (toll+toll2, d, nei)) 22 | if d>0 and (d-1, nei) not in visited: 23 | heapq.heappush(pq, (toll+toll2/2, d-1, nei)) 24 | 25 | return -1 -------------------------------------------------------------------------------- /problems/python/minimum-score-triangulation-of-polygon.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def minScoreTriangulation(self, values): 3 | N = len(values) 4 | dp = [[float('inf')]*N for _ in xrange(N)] 5 | 6 | for i in xrange(N-1): 7 | dp[i][i+1] = 0 8 | 9 | for l in xrange(3, N+1): 10 | for i in xrange(N-l+1): 11 | j = i+l-1 12 | 13 | for k in xrange(i+1, j): 14 | dp[i][j] = min(dp[i][j], dp[i][k]+values[i]*values[k]*values[j]+dp[k][j]) 15 | return dp[0][N-1] 16 | -------------------------------------------------------------------------------- /problems/python/minimum-size-subarray-sum.py: -------------------------------------------------------------------------------- 1 | """ 2 | As we move right the i and increament s, if the s >= target, we 3 | 4 | """ 5 | class Solution(object): 6 | def minSubArrayLen(self, target, nums): 7 | s = 0 8 | l = 0 9 | ans = float('inf') 10 | 11 | for i in xrange(len(nums)): 12 | s += nums[i] 13 | 14 | while s>=target: 15 | ans = min(i-l+1, ans) 16 | s -= nums[l] 17 | l += 1 18 | 19 | return ans if ans!=float('inf') else 0 20 | -------------------------------------------------------------------------------- /problems/python/minimum-swaps-to-make-sequences-increasing.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def minSwap(self, A, B): 3 | keep = [float('inf') for _ in xrange(len(A))] 4 | swap = [float('inf') for _ in xrange(len(A))] 5 | 6 | keep[0] = 0 7 | swap[0] = 1 8 | 9 | for i in xrange(1, len(A)): 10 | 11 | if A[i]>A[i-1] and B[i]>B[i-1]: 12 | keep[i] = keep[i-1] 13 | swap[i] = swap[i-1]+1 14 | 15 | if A[i]>B[i-1] and B[i]>A[i-1]: 16 | keep[i] = min(keep[i], swap[i-1]) 17 | swap[i] = min(swap[i], keep[i-1]+1) 18 | 19 | return min(keep[-1], swap[-1]) -------------------------------------------------------------------------------- /problems/python/minimum-xor-sum-of-two-arrays.py: -------------------------------------------------------------------------------- 1 | """ 2 | state[i] := nums1[i] has been matched. 3 | """ 4 | class Solution(object): 5 | def minimumXORSum(self, nums1, nums2): 6 | N = len(nums1) 7 | 8 | pq = [(0, '0'*N)] 9 | visited = set() 10 | while pq: 11 | s, state = heapq.heappop(pq) 12 | if state in visited: continue 13 | visited.add(state) 14 | 15 | j = state.count('1') 16 | if j==N: return s 17 | 18 | for i in xrange(N): 19 | if state[i]=='1': continue 20 | nextState = state[:i]+'1'+state[i+1:] 21 | if nextState in visited: continue 22 | heapq.heappush(pq, ((s+(nums1[i]^nums2[j-1]), nextState))) 23 | 24 | return float('inf') -------------------------------------------------------------------------------- /problems/python/missing-number.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(N) 3 | Space: O(N) 4 | """ 5 | class Solution(object): 6 | def missingNumber(self, nums): 7 | maxNum = max(nums) 8 | s = set(nums) 9 | 10 | for num in xrange(maxNum+1): 11 | if num not in s: 12 | return num 13 | 14 | return maxNum+1 15 | 16 | """ 17 | Time: O(N) 18 | Space: O(1) 19 | 20 | [0] Gauss' Formula: 0+1+2+...+n = n*(n+1)/2 21 | [1] Knowing that there is a missing num in nums, the last/max num will be len(nums). 22 | """ 23 | class Solution: 24 | def missingNumber(self, nums): 25 | n = len(nums) #[1] 26 | expectedSum = n*(n+1)/2 #[0] 27 | actualSum = sum(nums) 28 | return expectedSum-actualSum -------------------------------------------------------------------------------- /problems/python/moving-average-from-data-stream.py: -------------------------------------------------------------------------------- 1 | class MovingAverage(object): 2 | 3 | def __init__(self, size): 4 | self.queue = collections.deque() 5 | self.size = size 6 | self.sum = 0 7 | 8 | def next(self, val): 9 | self.queue.append(val) 10 | 11 | if len(self.queue)>self.size: 12 | self.sum = self.sum+val-self.queue.popleft() 13 | else: 14 | self.sum = self.sum+val 15 | 16 | return self.sum/float(len(self.queue)) 17 | 18 | """ 19 | Time: O(1) 20 | Space: O(Size) 21 | """ 22 | class MovingAverage(object): 23 | 24 | def __init__(self, size): 25 | self.size = size 26 | self.q = collections.deque() 27 | self.sum = 0 28 | 29 | 30 | def next(self, val): 31 | if len(self.q)>=self.size: 32 | self.sum -= self.q.popleft() 33 | 34 | self.sum += val 35 | self.q.append(val) 36 | return float(self.sum)/len(self.q) -------------------------------------------------------------------------------- /problems/python/my-calendar-ii.py: -------------------------------------------------------------------------------- 1 | """ 2 | self.booked := booked times. 3 | self.overlaps := overlaped times. 4 | 5 | For each new book, 6 | 1. check if the new book overlaps with the times in self.overlaps, if so, return False. 7 | 2. check if the new book overlaps with the times in self.booked, if so, store the overlaped time in self.overlaps. 8 | 3. store the new book in self.booked. 9 | """ 10 | class MyCalendarTwo(object): 11 | 12 | def __init__(self): 13 | self.overlaps = [] 14 | self.booked = [] 15 | 16 | 17 | def book(self, start, end): 18 | for s, e in self.overlaps: 19 | if not (e<=start or end<=s): 20 | return False 21 | 22 | for s, e in self.booked: 23 | if not (e<=start or end<=s): 24 | self.overlaps.append((max(start, s), min(end, e))) 25 | 26 | self.booked.append((start, end)) 27 | return True -------------------------------------------------------------------------------- /problems/python/n-ary-tree-level-order-traversal.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | 3 | class Solution(object): 4 | def levelOrder(self, root): 5 | opt = [] 6 | 7 | if not root: return opt 8 | 9 | q = deque() 10 | q.append((root, 0)) 11 | 12 | while q: 13 | node, depth = q.popleft() 14 | if depthCurrent->Right 4 | Pre-order: Current->Left->Right 5 | Post-order: Left->Right->Current 6 | """ 7 | class Solution(object): 8 | def postorder(self, root): 9 | def helper(node): 10 | if not node: return 11 | for child in node.children: 12 | helper(child) 13 | opt.append(node.val) 14 | opt = [] 15 | helper(root) 16 | return opt -------------------------------------------------------------------------------- /problems/python/n-ary-tree-preorder-traversal.py: -------------------------------------------------------------------------------- 1 | """ 2 | Pre-order traversal means that: visit the current node; if there is a left node, visit it; then if there is right node, visit it. 3 | In-order: Left->Current->Right 4 | Pre-order: Current->Left->Right 5 | Post-order: Left->Right->Current 6 | """ 7 | class Solution(object): 8 | def preorder(self, root): 9 | def helper(node): 10 | if not node: return 11 | opt.append(node.val) 12 | for child in node.children: 13 | helper(child) 14 | opt = [] 15 | helper(root) 16 | return opt -------------------------------------------------------------------------------- /problems/python/number-complement.py: -------------------------------------------------------------------------------- 1 | """ 2 | First, we convert the num to its birary. 3 | ``` 4 | >>> bin(5) 5 | >>> '0b101' 6 | ``` 7 | 8 | Second, we need to return the base10 of binary's the complement. 9 | Complement is easy `'101' => '010'`. 10 | Turn to base10: 11 | ``` 12 | '010' => 0*pow(2, 2) + 1*pow(2, 1) + 0*pow(2, 0) 13 | '11011' => 1*pow(2, 4) + 1*pow(2, 3) + 0*pow(2, 2) + 1*pow(2, 1) + 1*pow(2, 0) 14 | ``` 15 | 16 | Basics bit manipulation. 17 | 18 | """ 19 | class Solution(object): 20 | def findComplement(self, num): 21 | b = bin(num)[2:] 22 | opt = 0 23 | for i, c in enumerate(reversed(b)): 24 | if c=='0': opt+=pow(2, i) 25 | return opt 26 | -------------------------------------------------------------------------------- /problems/python/number-of-matching-subsequences.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(WL x LogS), W is the length of words, L is the length of word. 3 | LogS is the time for binary search and S should be the count of repetitive words, we can assume it is Log(S/26) ~= LogS. 4 | 5 | Space: O(S) 6 | """ 7 | class Solution(object): 8 | def numMatchingSubseq(self, s, words): 9 | def match(position, word): 10 | prev = -1 11 | for c in word: 12 | if c not in position: return False 13 | i = bisect.bisect_left(position[c], prev+1) 14 | if i==len(position[c]): return False 15 | prev = position[c][i] 16 | return True 17 | 18 | position = collections.defaultdict(list) 19 | count = 0 20 | for i, c in enumerate(s): 21 | position[c].append(i) 22 | 23 | for word in words: 24 | if match(position, word): count += 1 25 | return count -------------------------------------------------------------------------------- /problems/python/number-of-provinces.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def findCircleNum(self, isConnected): 3 | def bfs(startNode): 4 | q = collections.deque([startNode]) 5 | 6 | while q: 7 | node = q.popleft() 8 | if node in visited: continue 9 | visited.add(node) 10 | 11 | for nei in xrange(N): 12 | if nei!=node and isConnected[node][nei]==1: 13 | q.append(nei) 14 | 15 | N = len(isConnected) 16 | visited = set() 17 | ans = 0 18 | 19 | for node in xrange(N): 20 | if node in visited: continue 21 | bfs(node) #put all the nodes in the same province to visited 22 | ans += 1 23 | 24 | return ans -------------------------------------------------------------------------------- /problems/python/number-of-recent-calls.py: -------------------------------------------------------------------------------- 1 | """ 2 | everytime we ping 3 | we put the t in the queue 4 | 5 | and check the leftmost(smallest) if it is in the range of 3000 6 | if it is out of range, pop it, we don't need it anymore 7 | bc it would definitely be out of range for the next ping 8 | and bc the description says t is strictly increasing 9 | keep do the same until the leftmost is in the range 10 | 11 | now all the value in the queue is in the range 12 | return the length of the queue 13 | """ 14 | from collections import deque 15 | class RecentCounter(object): 16 | def __init__(self): 17 | self.q = collections.deque() 18 | 19 | def ping(self, t): 20 | self.q.append(t) 21 | while len(self.q)>0 and self.q[0]k: 15 | counter[s[i]] -= 1 16 | if counter[s[i]]==0: uniqueCount-= 1 17 | i += 1 18 | ans += j-i+1 19 | return ans 20 | 21 | n = len(s) 22 | return atMost(3) - atMost(2) -------------------------------------------------------------------------------- /problems/python/ones-and-zeroes.py: -------------------------------------------------------------------------------- 1 | """ 2 | dp[i][n][m] := max size of the subset with total m 0's and n 1's. 3 | Find max size for each m<=M and n<=N. 4 | """ 5 | class Solution(object): 6 | def findMaxForm(self, strs, M, N): 7 | dp = [[[0 for _ in xrange(M+1)] for _ in xrange(N+1)] for _ in xrange(len(strs)+1)] 8 | 9 | for i in xrange(1, len(strs)+1): 10 | count0 = strs[i-1].count('0') 11 | count1 = len(strs[i-1])-count0 12 | 13 | for n in xrange(N+1): 14 | for m in xrange(M+1): 15 | dp[i][n][m] = max(dp[i-1][n][m], (dp[i-1][n-count1][m-count0]+1) if m>=count0 and n>=count1 else 0) 16 | 17 | ans = 0 18 | for n in xrange(N+1): 19 | for m in xrange(M+1): 20 | ans = max(ans, dp[-1][n][m]) 21 | 22 | return ans -------------------------------------------------------------------------------- /problems/python/out-of-boundary-paths.py: -------------------------------------------------------------------------------- 1 | """ 2 | dp[k][i][j] := number of ways to get to (i, j) 3 | dp[k+1][i][j] = sum(dp[k][x][y]) for all (x, y) that can get to (i, j) 4 | For each k and i and j, also accumulate the ans 5 | 6 | Time: O(KMN) 7 | Space: O(KMN) 8 | """ 9 | 10 | class Solution(object): 11 | def findPaths(self, M, N, K, i, j): 12 | ans = 0 13 | 14 | dp = [[[0 for _ in xrange(N)] for _ in xrange(M)] for _ in xrange(K+1)] 15 | dp[0][i][j] = 1 16 | 17 | for k in xrange(K): 18 | for i in xrange(M): 19 | for j in xrange(N): 20 | if dp[k][i][j]>0: 21 | for x, y in [(i+1, j), (i-1, j), (i, j+1), (i, j-1)]: 22 | if x<0 or x>=M or y<0 or y>=N: 23 | ans+=dp[k][i][j] 24 | else: 25 | dp[k+1][x][y]+=dp[k][i][j] 26 | return ans % (1000000007) -------------------------------------------------------------------------------- /problems/python/pairs-of-songs-with-total-durations-divisible-by-60.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def numPairsDivisibleBy60(self, times): 3 | counter = collections.Counter() 4 | ans = 0 5 | 6 | for time in times: 7 | time = time%60 8 | ans += counter[60-time if time!=0 else 0] 9 | counter[time] += 1 10 | return ans -------------------------------------------------------------------------------- /problems/python/palindrome-number.py: -------------------------------------------------------------------------------- 1 | #https://leetcode.com/problems/palindrome-number/ 2 | class Solution(object): 3 | def isPalindrome(self, x): 4 | return str(x)==str(x)[::-1] -------------------------------------------------------------------------------- /problems/python/palindrome-partitioning.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def partition(self, S): 3 | def isPalindrome(s): 4 | return len(s)==1 or (len(s)>0 and s==s[::-1]) 5 | def search(s, pal_list): 6 | if len(s)==0: 7 | opt.append(pal_list) 8 | return 9 | for i in xrange(1, len(s)+1): 10 | if isPalindrome(s[:i]): 11 | search(s[i:], pal_list+[s[:i]]) 12 | opt = [] 13 | search(S, []) 14 | return opt -------------------------------------------------------------------------------- /problems/python/partition-array-for-maximum-sum.py: -------------------------------------------------------------------------------- 1 | """ 2 | dp[i] = max(k*max(A[i-k]~A[i]) + dp[i-k]) for k in 1~K. 3 | """ 4 | class Solution(object): 5 | def maxSumAfterPartitioning(self, A, K): 6 | dp = [0 for _ in xrange(len(A)+1)] 7 | 8 | for i in xrange(1, len(A)+1): 9 | m = float('-inf') # max in A[i-k]~A[i-1] 10 | for k in xrange(1, min(i+1, K+1)): 11 | m = max(m, A[i-k]) 12 | dp[i] = max(dp[i], m*k + dp[i-k]) 13 | 14 | return dp[-1] -------------------------------------------------------------------------------- /problems/python/path-with-maximum-probability.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def maxProbability(self, n, edges, succProb, start, end): 3 | pq = [(-1, start)] 4 | visited = set() 5 | adj = collections.defaultdict(list) 6 | for i in xrange(len(edges)): 7 | a, b = edges[i] 8 | p = succProb[i] 9 | adj[a].append((b, p)) 10 | adj[b].append((a, p)) 11 | 12 | while pq: 13 | p, node = heapq.heappop(pq) 14 | p = p*-1 15 | if node in visited: continue 16 | visited.add(node) 17 | 18 | if node==end: return p 19 | 20 | for nei, p2 in adj[node]: 21 | if nei in visited: continue 22 | heapq.heappush(pq, (-1*p*p2, nei)) 23 | 24 | return 0 -------------------------------------------------------------------------------- /problems/python/peak-index-in-a-mountain-array.py: -------------------------------------------------------------------------------- 1 | """ 2 | Take a look at the code first. 3 | If `A[p]0: 8 | a = K/math.factorial(N-1) 9 | ans += str(nums[a]) 10 | nums.pop(a) 11 | 12 | K -= math.factorial(N-1)*(a+1) 13 | N -= 1 14 | return ans -------------------------------------------------------------------------------- /problems/python/powx-n.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def myPow(self, x, n): 3 | if n==0: 4 | return 1 5 | elif n<0: 6 | return 1/self.myPow(x, -n) 7 | elif n%2>0: 8 | half = self.myPow(x, n-1) 9 | return x*half 10 | elif n%2==0: 11 | half = self.myPow(x, n/2) 12 | return half*half -------------------------------------------------------------------------------- /problems/python/queue-reconstruction-by-height.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(N^2) 3 | Space: O(N) 4 | 5 | People need to be exactly insert to index k, so that there are "exact" k people equal or taller to k. 6 | Shorter person does not matter (invisible) to taller person, so insert taller person first. 7 | People does not care about the people on their right, so insert the person with smaller k first. 8 | """ 9 | class Solution(object): 10 | def reconstructQueue(self, people): 11 | people.sort(key=lambda x: (-x[0], x[1])) 12 | ans = [] 13 | for h, k in people: 14 | ans.insert(k, (h, k)) 15 | return ans -------------------------------------------------------------------------------- /problems/python/random-pick-with-weight.py: -------------------------------------------------------------------------------- 1 | """ 2 | For W = [1,3,2,4] (total 10, 1+2+3+4) 3 | Think of a line _,___,__,____ ([1,4,6,10]) 4 | Now we randomly throw a ball on the line the probability to land on the first section will be 1/10. 5 | the second section, 3/10. 6 | the third section, 2/10. 7 | the forth section, 4/10. 8 | 9 | Above is equivilant to we randomly pick a number [0~10) and see which section it is in. 10 | And since the cumulative probability in the "line" is strictly increasing, we can use binary search. 11 | 12 | Time: O(LogN), N is the number of W. 13 | Space: O(N). 14 | """ 15 | from random import randrange 16 | 17 | class Solution(object): 18 | 19 | def __init__(self, W): 20 | self.line = [] #cumulative probability distribution 21 | self.total = 0 22 | 23 | for w in W: 24 | self.total += w 25 | self.line.append(self.total) 26 | 27 | def pickIndex(self): 28 | rand = random.randrange(self.total) 29 | return bisect.bisect(self.line, rand) -------------------------------------------------------------------------------- /problems/python/range-sum-of-bst.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def rangeSumBST(self, root, low, high): 3 | def helper(node, low, high): 4 | total = 0 5 | if not node: return total 6 | if low<=node.val<=high: total += node.val 7 | if node.val<=high: total += helper(node.right, low, high) 8 | if node.val>=low: total += helper(node.left, low, high) 9 | return total 10 | 11 | return helper(root, low, high) -------------------------------------------------------------------------------- /problems/python/range-sum-query-immutable.py: -------------------------------------------------------------------------------- 1 | class NumArray(object): 2 | def __init__(self, nums): 3 | #total[i] = nums[0]+nums[1]+...+nums[i] 4 | self.total = [] 5 | 6 | #initialize total 7 | temp = 0 8 | for num in nums: 9 | temp += num 10 | self.total.append(temp) 11 | 12 | def sumRange(self, i, j): 13 | return self.total[j] - self.total[i-1] if i>0 else self.total[j] -------------------------------------------------------------------------------- /problems/python/remove-all-adjacent-duplicates-in-string.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def removeDuplicates(self, s): 3 | stack = [] 4 | i = 0 5 | while i0: 21 | k -= 1 22 | curr = curr.next 23 | 24 | removeNext(curr) 25 | return head -------------------------------------------------------------------------------- /problems/python/replace-the-substring-for-balanced-string.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def balancedString(self, s): 3 | n = len(s) 4 | counter = collections.Counter(s) 5 | i = 0 6 | ans = n 7 | 8 | for j, c in enumerate(s): 9 | counter[c] -= 1 10 | 11 | while i=(2**31)-1 or x<(-2)**31: 5 | return 0 6 | 7 | if x>=0: 8 | x = str(x)[::-1] 9 | else: 10 | x = str(-x)[::-1] 11 | x = '-'+x 12 | 13 | if x[0] == '0': 14 | x = x[0:] 15 | 16 | x = int(x) 17 | 18 | if x>=(2**31)-1 or x<(-2)**31: 19 | return 0 20 | 21 | return x 22 | 23 | -------------------------------------------------------------------------------- /problems/python/reverse-string.py: -------------------------------------------------------------------------------- 1 | """ 2 | Reversing a string is equivalent to 3 | Switch the first and the last, the second and the second last, the third and the third last... 4 | So I use two pointers, 's' at the start, 'e' at the end. 5 | If e and s collapse, the proccess is finished. 6 | 7 | (a, b) = (b, a) is equal to 8 | 9 | temp = a 10 | a = b 11 | b = temp 12 | 13 | For time complexity is O(N), N is the length of the string. 14 | Space complexity is O(1), because I only use pointers and a space to store one char. 15 | """ 16 | class Solution(object): 17 | def reverseString(self, string): 18 | s = 0 19 | e = len(string)-1 20 | while e>s: 21 | (string[s], string[e]) = (string[e], string[s]) 22 | s+=1 23 | e-=1 24 | return string 25 | -------------------------------------------------------------------------------- /problems/python/reverse-vowels-of-a-string.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def reverseVowels(self, s): 3 | i = 0 4 | j = len(s)-1 5 | vowels = set(['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U']) 6 | s = list(s) 7 | 8 | while ival: 13 | node = node.left 14 | else: 15 | node = node.right 16 | 17 | return None 18 | 19 | """ 20 | Time complexity: O(LogN) 21 | Space complexity: O(LogN) 22 | """ 23 | class Solution(object): 24 | def searchBST(self, node, val): 25 | if not node: return None 26 | if node.val==val: 27 | return node 28 | elif node.valval: 31 | return self.searchBST(node.left, val) -------------------------------------------------------------------------------- /problems/python/second-highest-salary.sql: -------------------------------------------------------------------------------- 1 | -- https://leetcode.com/problems/second-highest-salary/ 2 | Select MAX(Salary) AS SecondHighestSalary from Employee 3 | where Salary < (Select MAX(Salary) from Employee) -------------------------------------------------------------------------------- /problems/python/sell-diminishing-valued-colored-balls.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def maxProfit(self, I, orders): 3 | I.sort(reverse=True) 4 | I.append(0) 5 | 6 | profit = 0 7 | w = 1 8 | 9 | for i in xrange(len(I)-1): 10 | if orders==0: break 11 | if I[i]>I[i+1]: 12 | if w*(I[i]-I[i+1])=N or i<0 or j>=M or j<0: continue 19 | if grid[i][j]==1 and k0>0: 20 | qNext.append((step+1, i, j, k0-1)) 21 | elif grid[i][j]==0: 22 | qNext.append((step+1, i, j, k0)) 23 | if not q: q = qNext 24 | 25 | return -1 -------------------------------------------------------------------------------- /problems/python/shortest-path-in-binary-matrix.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def shortestPathBinaryMatrix(self, grid): 3 | q = collections.deque([(0, 0, 1)]) 4 | seen = 2 5 | 6 | while q: 7 | i, j, step = q.popleft() 8 | if not (0<=i0: 13 | skip -= 1 14 | continue 15 | else: 16 | ans = '/'+directory+ans 17 | 18 | return ans if ans!='' else '/' -------------------------------------------------------------------------------- /problems/python/single-threaded-cpu.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def getOrder(self, tasks): 3 | ans = [] 4 | tasks = sorted([(task[0], task[1], i) for i, task in enumerate(tasks)], reverse=True) 5 | pq = [] #tasks available 6 | now = 0 7 | 8 | 9 | while tasks or pq: 10 | #check if the task is availiable, if yes, add to pq 11 | while tasks and tasks[-1][0]<=now: 12 | startTime, processTime, i = tasks.pop() 13 | heapq.heappush(pq, (processTime, i)) 14 | 15 | if pq: 16 | processTime, i = heapq.heappop(pq) 17 | ans.append(i) 18 | now += processTime 19 | else: 20 | now = tasks[-1][0] 21 | 22 | return ans -------------------------------------------------------------------------------- /problems/python/snapshot-array.py: -------------------------------------------------------------------------------- 1 | class SnapshotArray(object): 2 | 3 | def __init__(self, length): 4 | self.data = [[(-1, 0)] for _ in xrange(length)] 5 | self.snapId = 0 6 | 7 | 8 | def set(self, index, val): 9 | self.data[index].append((self.snapId, val)) 10 | 11 | 12 | def snap(self): 13 | self.snapId += 1 14 | return self.snapId - 1 15 | 16 | 17 | def get(self, index, snapId): 18 | j = bisect.bisect_right(self.data[index], (snapId, float('inf'))) - 1 19 | return self.data[index][j][1] -------------------------------------------------------------------------------- /problems/python/split-array-into-fibonacci-sequence.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def splitIntoFibonacci(self, S): 3 | def is_bibonacci(opt, num): 4 | return num == opt[-1]+opt[-2] 5 | 6 | def helper(s, first): 7 | if first==len(s) and len(opt)>=3: 8 | return True 9 | 10 | for i in xrange(first, len(s)): 11 | if s[first]=='0' and i!=first: break #skip leading zero 12 | num = int(s[first:i+1]) 13 | 14 | if num>2147483648: break 15 | 16 | #early termination 17 | if len(opt)>=2 and num>opt[-1]+opt[-2]: 18 | break 19 | 20 | if len(opt)<=1 or is_bibonacci(opt, num): 21 | opt.append(int(num)) 22 | if helper(s, i+1): return True 23 | opt.pop() 24 | return False 25 | 26 | opt = [] 27 | helper(S, 0) 28 | return opt 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /problems/python/stone-game-ii.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def stoneGameII(self, piles): 3 | def helper(start, m): 4 | if (start, m) in history: return history[(start, m)] 5 | 6 | if start>=len(piles): return 0 7 | if start+m*2>=len(piles): return sum(piles[start:]) 8 | 9 | max_stones = float('-inf') 10 | for x in xrange(1, m*2+1): 11 | max_stones = max(max_stones, sum(piles[start:])-helper(start+x, max(m, x))) 12 | 13 | history[(start, m)] = max_stones 14 | return history[(start, m)] 15 | 16 | history = {} 17 | return helper(0, 1) 18 | 19 | """ 20 | helper(start, m) := the max stones that the first player will get with given piles[start:] and M. 21 | max_stones = MAX{ (sum of all the stones) - (max_stones the other player will get) } = MAX{ sum(piles[start:]) - helper(start+x, max(m, x)) } 22 | """ -------------------------------------------------------------------------------- /problems/python/student-attendance-record-ii.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def checkRecord(self, n): 3 | """ 4 | dp[l] := number of eligible combination of a length l record without A 5 | """ 6 | 7 | ans = 0 8 | M = 1000000007 9 | 10 | dp = [0]*max(n+1, 4) 11 | dp[0] = 1 12 | dp[1] = 2 13 | dp[2] = 4 14 | dp[3] = 7 15 | 16 | for i in xrange(4, n+1): 17 | dp[i] += dp[i-1]%M #ends at P 18 | dp[i] += (dp[i-1]%M - dp[i-4]%M) #ends at L. All posiblity but the end cannot be PLL 19 | 20 | ans += dp[n] 21 | 22 | for i in xrange(n): 23 | ans += dp[i] * dp[n-i-1] 24 | ans %= M 25 | 26 | return ans 27 | -------------------------------------------------------------------------------- /problems/python/subarrays-with-k-different-integers.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def subarraysWithKDistinct(self, nums, K): 3 | #number of subarray of nums which have at most k different numbers. 4 | def atMost(k): 5 | i = 0 6 | ans = 0 7 | counter = collections.Counter() 8 | uniqueCount = 0 9 | 10 | for j in xrange(len(nums)): 11 | counter[nums[j]] += 1 12 | if counter[nums[j]]==1: uniqueCount += 1 13 | 14 | while uniqueCount>k: 15 | counter[nums[i]] -= 1 16 | if counter[nums[i]]==0: uniqueCount -= 1 17 | i += 1 18 | 19 | # the logest subarray that ends at j is nums[i:j+1] 20 | # nums[i:j+1] can produce j-i+1 subarrays that at most has k different number. 21 | ans += j-i+1 22 | 23 | return ans 24 | 25 | return atMost(K)-atMost(K-1) -------------------------------------------------------------------------------- /problems/python/subdomain-visit-count.py: -------------------------------------------------------------------------------- 1 | #https://leetcode.com/problems/subdomain-visit-count/ 2 | class Solution(object): 3 | def subdomainVisits(self, cpdomains): 4 | data = collections.Counter() 5 | return_data = [] 6 | for domain in cpdomains: 7 | count, domain = domain.split() 8 | count = int(count) 9 | data[domain]+=count 10 | 11 | sub_domain1 = domain.split('.', 1)[-1] 12 | data[sub_domain1]+=count 13 | 14 | if '.' in sub_domain1: 15 | sub_domain2 = sub_domain1.split('.', 1)[-1] 16 | data[sub_domain2]+=count 17 | 18 | for domain, count in data.items(): 19 | return_data.append(str(count)+' '+domain) 20 | 21 | return return_data -------------------------------------------------------------------------------- /problems/python/summary-ranges.py: -------------------------------------------------------------------------------- 1 | """ 2 | For each iteration, if we found a new starting point we will append previous range to the opt. 3 | The range start from index s to index i-1. 4 | """ 5 | class Solution(object): 6 | def summaryRanges(self, nums): 7 | nums.append('#') 8 | opt = [] 9 | s = 0 10 | 11 | for i in xrange(1, len(nums)): 12 | if nums[i-1]+1!=nums[i]: 13 | if i-1>s: 14 | opt.append(str(nums[s])+'->'+str(nums[i-1])) 15 | else: 16 | opt.append(str(nums[s])) 17 | s = i 18 | return opt -------------------------------------------------------------------------------- /problems/python/super-ugly-number.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def nthSuperUglyNumber(self, n, primes): 3 | p = [0]*len(primes) #p[i] stores the index of ugly number in ans that not yet times primes[i] yet 4 | ans = [1] 5 | h = [] 6 | 7 | for i in xrange(len(primes)): 8 | heapq.heappush(h, (primes[i]*ans[p[i]], i)) 9 | 10 | for _ in xrange(n-1): 11 | curr = h[0][0] 12 | ans.append(curr) 13 | 14 | while h and h[0][0]==curr: 15 | i = h[0][1] 16 | heapq.heappop(h) 17 | p[i] += 1 18 | heapq.heappush(h, (primes[i]*ans[p[i]], i)) 19 | 20 | return ans[-1] -------------------------------------------------------------------------------- /problems/python/swap-adjacent-in-lr-string.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def canTransform(self, start, end): 3 | if len(start)!=len(end): return False 4 | if start.replace('X', '')!=end.replace('X', ''): return False 5 | 6 | startLIndex = [i for i, c in enumerate(start) if c=='L'] 7 | endLIndex = [i for i, c in enumerate(end) if c=='L'] 8 | for i in xrange(len(startLIndex)): 9 | if startLIndex[i]endRIndex[i]: 16 | return False 17 | 18 | return True -------------------------------------------------------------------------------- /problems/python/tallest-billboard.py: -------------------------------------------------------------------------------- 1 | #TLE 2 | class Solution(object): 3 | def tallestBillboard(self, rods): 4 | D = sum(rods) 5 | N = len(rods) 6 | 7 | dp = [[float('-inf') for _ in xrange(-D, D+1)] for _ in xrange(N+1)] 8 | dp[0][D] = 0 9 | 10 | for i in xrange(1, N+1): 11 | for d in xrange(-D, D+1): 12 | h = rods[i-1] 13 | dp[i][d+D] = max(dp[i-1][d+D], (dp[i-1][d+D-h]+h) if d+D-h>=0 else float('-inf'), dp[i-1][d+D+h] if d+D+h<2*D+1 else float('-inf')) 14 | 15 | return dp[N][D] -------------------------------------------------------------------------------- /problems/python/the-kth-factor-of-n.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(N) 3 | Space: O(F), storing number of factors for N. 4 | """ 5 | class Solution(object): 6 | def kthFactor(self, n, k): 7 | factors = [] 8 | 9 | for i in xrange(1, n+1): 10 | if n%i==0: 11 | factors.append(i) 12 | if len(factors)==k: return factors[-1] 13 | return -1 14 | 15 | 16 | """ 17 | Time: O(N^1/2) 18 | Space: O(F), storing number of factors for N. 19 | """ 20 | class Solution(object): 21 | def kthFactor(self, n, k): 22 | factors1 = [] 23 | factors2 = [] 24 | 25 | for i in xrange(1, int(n**0.5)+1): 26 | if n%i==0: 27 | factors1.append(i) 28 | if i!=n/i: factors2.append(n/i) 29 | 30 | factors = factors1+factors2[::-1] 31 | 32 | return factors[k-1] if k-1 water[i] = (height[i-1] + water[i-1]) - height[i] (l2r below) 6 | 7 | Do the same from right to left, this time considering only the right boandary. 8 | 9 | The amount of water at i considering both left and right wall will be min(l2r[i], r2l[i]) 10 | """ 11 | class Solution(object): 12 | def trap(self, height): 13 | N = len(height) 14 | l2r = [0]*N #water 15 | r2l = [0]*N #water 16 | 17 | for i in xrange(1, N): 18 | l2r[i] = max(l2r[i-1]+height[i-1]-height[i], 0) 19 | 20 | for i in xrange(N-2, -1, -1): 21 | r2l[i] = max(r2l[i+1]+height[i+1]-height[i], 0) 22 | 23 | ans = 0 24 | for i in xrange(N): 25 | ans += min(l2r[i], r2l[i]) 26 | return ans -------------------------------------------------------------------------------- /problems/python/trim-a-binary-search-tree.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def trimBST(self, root, L, R): 3 | if not root: return root 4 | root.left = self.trimBST(root.left, L, R) 5 | root.right = self.trimBST(root.right, L, R) 6 | return root if L<=root.val and root.val<=R else root.left or root.right 7 | 8 | """ 9 | First, trim left child and right child. 10 | Second, if the root is in range, return the root. 11 | if not, return the trimed left child. 12 | if not trimed left child, return the trimed right child. 13 | if both left and right child is None, it will return None anyway. 14 | 15 | Time complexity is O(N). For we simply just traverse all the nodes. 16 | Space complexity is O(N). In the worst case, the recursion will go O(N) level deep. 17 | """ -------------------------------------------------------------------------------- /problems/python/two-out-of-three.py: -------------------------------------------------------------------------------- 1 | class Solution(object): 2 | def twoOutOfThree(self, nums1, nums2, nums3): 3 | ans = [] 4 | 5 | counter = collections.Counter() 6 | 7 | for num in list(set(nums1)): 8 | counter[num] += 1 9 | for num in list(set(nums2)): 10 | counter[num] += 1 11 | for num in list(set(nums3)): 12 | counter[num] += 1 13 | 14 | for num in counter: 15 | if counter[num]>=2: ans.append(num) 16 | 17 | return ans -------------------------------------------------------------------------------- /problems/python/ugly-number-ii.py: -------------------------------------------------------------------------------- 1 | """ 2 | `ans` contains sorted ugly numbers. 3 | For each ugly number we can x2 or x3 or x5 to produce another ugly number. 4 | 5 | i2 points at the number that has been x2 yet. 6 | i3 points at the number that has been x3 yet. 7 | i5 points at the number that has been x5 yet. 8 | 9 | Each time we append one minimum ugly number and move the pointer. 10 | 11 | Time: O(N) 12 | Space: O(N) 13 | """ 14 | class Solution(object): 15 | def nthUglyNumber(self, k): 16 | i2 = i3 = i5 = 0 17 | 18 | ans = [1] 19 | while len(ans) int: 7 | nums.sort() 8 | 9 | N = len(nums) 10 | ans = float('inf') 11 | 12 | for i in range(N): 13 | j = i+1 14 | k = N-1 15 | 16 | while jabs(target-total): ans = total 20 | if total>target: 21 | k -= 1 22 | elif total int: 3 | N = len(nums) 4 | ans = 0 5 | 6 | nums.sort() 7 | 8 | 9 | for i in range(N): 10 | j = i+1 11 | k = N-1 12 | while j Optional[ListNode]: 3 | carry = 0 4 | dummy = ListNode() 5 | curr = dummy 6 | 7 | while l1 or l2 or carry: 8 | n = (l1.val if l1 else 0) + (l2.val if l2 else 0) + carry 9 | if n>=10: 10 | curr.next = ListNode(n-10) 11 | carry = 1 12 | else: 13 | curr.next = ListNode(n) 14 | carry = 0 15 | curr = curr.next 16 | if l1: l1 = l1.next 17 | if l2: l2 = l2.next 18 | 19 | return dummy.next -------------------------------------------------------------------------------- /problems/python3/balanced-binary-tree.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(N) 3 | Space: O(LogN) Recursion stack. If the tree is balanced. 4 | """ 5 | class Solution: 6 | def isBalanced(self, root: Optional[TreeNode]) -> bool: 7 | def getHeight(node) -> (bool, int): 8 | if not node: return True, 0 9 | leftIsBalanced, leftHeight = getHeight(node.left) 10 | if not leftIsBalanced: return False, 0 11 | 12 | rightIsBalanced, rightHeight = getHeight(node.right) 13 | if not rightIsBalanced: return False, 0 14 | 15 | return abs(leftHeight-rightHeight)<2, 1+max(leftHeight, rightHeight) 16 | 17 | isBalanced, h = getHeight(root) 18 | return isBalanced -------------------------------------------------------------------------------- /problems/python3/best-time-to-buy-and-sell-stock-with-cooldown.py: -------------------------------------------------------------------------------- 1 | #dp[i][0] := max profit when last action is buy 2 | #dp[i][1] := max profit when last action is sell 3 | class Solution: 4 | def maxProfit(self, prices: List[int]) -> int: 5 | if not prices or len(prices)<=1: return 0 6 | 7 | N = len(prices) 8 | dp = [[0, 0] for _ in range(N)] 9 | dp[0] = [-prices[0], 0] 10 | dp[1][0] = max(-prices[1], -prices[0]) 11 | dp[1][1] = max(prices[1]+dp[0][0], dp[0][1]) 12 | 13 | for i in range(2, N): 14 | dp[i][0] = max(dp[i-2][1]-prices[i], dp[i-1][0]) 15 | dp[i][1] = max(prices[i]+dp[i-1][0], dp[i-1][1]) 16 | return max(dp[-1][0], dp[-1][1], 0) -------------------------------------------------------------------------------- /problems/python3/best-time-to-buy-and-sell-stock.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def maxProfit(self, prices: List[int]) -> int: 3 | minPrice = prices[0] 4 | ans = 0 5 | 6 | for i in range(1, len(prices)): 7 | ans = max(ans, prices[i]-minPrice) 8 | minPrice = min(prices[i], minPrice) 9 | 10 | return ans -------------------------------------------------------------------------------- /problems/python3/binary-search.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def search(self, nums: List[int], target: int) -> int: 3 | l = 0 4 | r = len(nums)-1 5 | 6 | while l<=r: 7 | m = l + int((r-l)/2) 8 | 9 | if nums[m]>target: 10 | r = m-1 11 | elif nums[m] List[int]: 10 | def helper(node, level): 11 | if not node: return 12 | if len(ans) int: 17 | def dfs(l, r)->int: 18 | if l>r: return 0 19 | if (l, r) in dp: return dp[(l, r)] 20 | 21 | dp[(l, r)] = 0 22 | for i in range(l, r+1): 23 | dp[(l, r)] = max(dp[(l, r)], nums[l-1]*nums[i]*nums[r+1] + dfs(l, i-1) + dfs(i+1, r)) 24 | return dp[(l, r)] 25 | 26 | nums = [1]+nums+[1] 27 | dp = {} 28 | return dfs(1, len(nums)-2) -------------------------------------------------------------------------------- /problems/python3/car-fleet.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def carFleet(self, target: int, position: List[int], speed: List[int]) -> int: 3 | N = len(position) 4 | 5 | timeInfo = [] 6 | for i in range(N): 7 | timeInfo.append((position[i], (target-position[i])/speed[i])) 8 | timeInfo.sort(reverse=True) 9 | 10 | stack = [] 11 | for _, time in timeInfo: 12 | stack.append(time) 13 | if len(stack)>=2 and stack[-2]>=stack[-1]: 14 | stack.pop() 15 | 16 | return len(stack) -------------------------------------------------------------------------------- /problems/python3/cheapest-flights-within-k-stops.py: -------------------------------------------------------------------------------- 1 | """ 2 | Bellman-Ford. 3 | Time: O(KE) 4 | """ 5 | class Solution: 6 | def findCheapestPrice(self, N: int, flights: List[List[int]], src: int, dst: int, K: int) -> int: 7 | prices = {n:float('inf') for n in range(N)} 8 | prices[src] = 0 9 | 10 | for k in range(K+1): 11 | temp = prices.copy() 12 | for source, destination, price in flights: 13 | if prices[source]==float('inf'): continue 14 | if prices[source]+price int: 3 | dp = [0]*(N+1) 4 | dp[0] = 1 5 | for i in range(len(dp)): 6 | if i-1>=0: 7 | dp[i] += dp[i-1] 8 | if i-2>=0: 9 | dp[i] += dp[i-2] 10 | return dp[-1] -------------------------------------------------------------------------------- /problems/python3/clone-graph.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def cloneGraph(self, start: 'Node') -> 'Node': 3 | def dfs(node): 4 | if node in clones: return clones[node] 5 | 6 | copy = Node(node.val) 7 | clones[node] = copy 8 | 9 | for neighbor in node.neighbors: 10 | copy.neighbors.append(dfs(neighbor)) 11 | 12 | return clones[node] 13 | if not start: return start 14 | clones = {} 15 | dfs(start) 16 | return clones[start] -------------------------------------------------------------------------------- /problems/python3/coin-change-ii.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def change(self, amount: int, coins: List[int]) -> int: 3 | dp = [0]*(amount+1) 4 | dp[0] = 1 5 | 6 | coins.sort() 7 | 8 | for coin in coins: 9 | for a in range(1, amount+1): 10 | if a-coin<0: continue 11 | dp[a] += dp[a-coin] 12 | return dp[-1] -------------------------------------------------------------------------------- /problems/python3/coin-change.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def coinChange(self, coins: List[int], amount: int) -> int: 3 | dp = [float('inf')]*(amount+1) 4 | dp[0] = 0 5 | for coin in coins: 6 | if coin List[List[int]]: 3 | def helper(i, target): 4 | if target==0: 5 | ans.append(combination.copy()) 6 | return 7 | 8 | if i==len(candidates) or candidates[i]>target: 9 | return 10 | 11 | combination.append(candidates[i]) 12 | helper(i+1, target-candidates[i]) 13 | combination.pop() 14 | 15 | while i+1 List[List[int]]: 13 | def helper(i, currSum, target): 14 | if currSum>target: 15 | return 16 | 17 | if currSum==target: 18 | ans.append(combination.copy()) 19 | return 20 | 21 | for j in range(i, len(candidates)): 22 | combination.append(candidates[j]) 23 | helper(j, currSum+candidates[j], target) 24 | combination.pop() 25 | 26 | ans = [] 27 | combination = [] 28 | helper(0, 0, target) 29 | return ans -------------------------------------------------------------------------------- /problems/python3/contains-duplicate.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def containsDuplicate(self, nums: List[int]) -> bool: 3 | seen = set() 4 | for num in nums: 5 | if num in seen: return True 6 | seen.add(num) 7 | return False -------------------------------------------------------------------------------- /problems/python3/count-good-nodes-in-binary-tree.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(N) 3 | Space: O(LogN) for recursion stack if the tree is balanced. 4 | """ 5 | class Solution: 6 | def goodNodes(self, root: TreeNode) -> int: 7 | def helper(node, maxVal): 8 | nonlocal count 9 | if not node: return 10 | if node.val>=maxVal: count += 1 11 | helper(node.left, max(maxVal, node.val)) 12 | helper(node.right, max(maxVal, node.val)) 13 | 14 | count = 0 15 | helper(root, float('-inf')) 16 | return count -------------------------------------------------------------------------------- /problems/python3/counting-bits.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def countBits(self, n: int) -> List[int]: 3 | ans = [0]*(n+1) 4 | offset = 1 5 | 6 | for i in range(1, n+1): 7 | if offset*2==i: offset = offset*2 8 | ans[i] = 1+ans[i-offset] 9 | return ans -------------------------------------------------------------------------------- /problems/python3/course-schedule.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool: 3 | sortedCourse = [] 4 | inbounds = collections.Counter() 5 | G = collections.defaultdict(list) 6 | q = collections.deque() 7 | 8 | for c1, c2 in prerequisites: 9 | G[c2].append(c1) 10 | inbounds[c1] += 1 11 | 12 | for c in range(numCourses): 13 | if inbounds[c]==0: q.append(c) 14 | 15 | while q: 16 | c = q.popleft() 17 | 18 | for c2 in G[c]: 19 | inbounds[c2] -= 1 20 | if inbounds[c2]==0: q.append(c2) 21 | sortedCourse.append(c) 22 | 23 | return len(sortedCourse)==numCourses -------------------------------------------------------------------------------- /problems/python3/daily-temperatures.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def dailyTemperatures(self, temperatures: List[int]) -> List[int]: 3 | ans = [0]*len(temperatures) 4 | stack = [] 5 | 6 | for i, temp in enumerate(temperatures): 7 | while stack and stack[-1][0] int: 6 | mapping = set([str(n) for n in range(1, 27)]) 7 | N = len(s) 8 | dp = [0]*(N+1) 9 | dp[0] = 1 10 | 11 | for i in range(1, N+1): 12 | if i-1>=0 and s[i-1] in mapping: dp[i] += dp[i-1] 13 | if i-2>=0 and s[i-2:i] in mapping: dp[i] += dp[i-2] 14 | return dp[-1] -------------------------------------------------------------------------------- /problems/python3/design-add-and-search-words-data-structure.py: -------------------------------------------------------------------------------- 1 | class WordDictionary: 2 | 3 | def __init__(self): 4 | self.root = {} 5 | 6 | def addWord(self, word: str) -> None: 7 | node = self.root 8 | for c in word: 9 | if c not in node: node[c] = {} 10 | node = node[c] 11 | node['$'] = {} #'.' means the end of the word 12 | 13 | def search(self, word: str) -> bool: 14 | def helper(node, i): 15 | if i==len(word): return '$' in node 16 | 17 | if word[i]=='.': 18 | for c in node: 19 | if helper(node[c], i+1): return True 20 | return False 21 | else: 22 | if word[i] not in node: return False 23 | return helper(node[word[i]], i+1) 24 | return helper(self.root, 0) 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /problems/python3/detect-squares.py: -------------------------------------------------------------------------------- 1 | class DetectSquares: 2 | 3 | def __init__(self): 4 | self.store = collections.Counter() 5 | 6 | def add(self, point: List[int]) -> None: 7 | self.store[tuple(point)] += 1 8 | 9 | def count(self, point: List[int]) -> int: 10 | x, y = point 11 | ans = 0 12 | 13 | for dx, dy in self.store: 14 | if abs(x-dx)!=abs(y-dy) or x==dx or y==dy: continue 15 | ans += self.store[(dx, dy)]*self.store[(dx, y)]*self.store[(x, dy)] 16 | return ans 17 | 18 | 19 | # Your DetectSquares object will be instantiated and called as such: 20 | # obj = DetectSquares() 21 | # obj.add(point) 22 | # param_2 = obj.count(point) -------------------------------------------------------------------------------- /problems/python3/diameter-of-binary-tree.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(N) 3 | Space: O(LogN) for the recursion stack. If the tree is balanced. 4 | """ 5 | class Solution: 6 | def diameterOfBinaryTree(self, root: Optional[TreeNode]) -> int: 7 | def helper(node): 8 | if not node: return 0 9 | l = helper(node.left) 10 | r = helper(node.right) 11 | self.ans = max(self.ans, 1+l+r) 12 | return 1+max(l, r) 13 | 14 | self.ans = 0 15 | 16 | helper(root) 17 | return self.ans-1 -------------------------------------------------------------------------------- /problems/python3/distinct-subsequences.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def numDistinct(self, s: str, t: str) -> int: 3 | def dfs(i, j): 4 | if (i, j) in visited: return visited[(i, j)] 5 | 6 | if j>=len(t): return 1 7 | if i>=len(s): return 0 8 | 9 | if s[i]==t[j]: 10 | visited[(i, j)] = dfs(i+1, j+1)+dfs(i+1, j) 11 | else: 12 | visited[(i, j)] = dfs(i+1, j) 13 | return visited[(i, j)] 14 | 15 | visited = {} 16 | dfs(0, 0) 17 | return dfs(0, 0) -------------------------------------------------------------------------------- /problems/python3/encode-and-decode-strings.py: -------------------------------------------------------------------------------- 1 | class Codec: 2 | def encode(self, strs: List[str]) -> str: 3 | output = '' 4 | for string in strs: 5 | output += str(len(string))+'#'+string 6 | return output 7 | 8 | 9 | def decode(self, s: str) -> List[str]: 10 | output = [] 11 | i = 0 12 | 13 | while i int: 3 | operators = set(['+', '-', '*', '/']) 4 | stack = [] 5 | 6 | for c in tokens: 7 | if c in operators: 8 | n2 = stack.pop() 9 | n1 = stack.pop() 10 | 11 | if c=='+': 12 | stack.append(n1+n2) 13 | elif c=='-': 14 | stack.append(n1-n2) 15 | elif c=='*': 16 | stack.append(n1*n2) 17 | elif c=='/': 18 | stack.append(int(n1/n2)) 19 | else: 20 | stack.append(int(c)) 21 | 22 | return stack.pop() -------------------------------------------------------------------------------- /problems/python3/find-minimum-in-rotated-sorted-array.py: -------------------------------------------------------------------------------- 1 | """ 2 | Usually the binary search problem, the hard part is to clear all the edge cases. 3 | What will be the edge case? It will be when the recursive function executed at the deepest level. Usually the list with only one or two element. 4 | So I will suggest before submit, try out the case like [0,1] or [1,0] to make sure it will not run unstop. 5 | """ 6 | class Solution: 7 | def findMin(self, nums: List[int]) -> int: 8 | def helper(l, r): 9 | nonlocal ans 10 | if l>r: return 11 | 12 | m = l + int((r-l)/2) 13 | if nums[l]<=nums[m]: 14 | ans = min(ans, nums[l]) 15 | helper(m+1, r) 16 | else: 17 | ans = min(ans, nums[m+1]) 18 | helper(l, m) 19 | 20 | ans = float('inf') 21 | helper(0, len(nums)-1) 22 | return ans -------------------------------------------------------------------------------- /problems/python3/find-the-duplicate-number.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def findDuplicate(self, nums: List[int]) -> int: 3 | head = nums[0] 4 | slow = head 5 | fast = head 6 | 7 | while True: 8 | slow = nums[slow] 9 | fast = nums[nums[fast]] 10 | if slow==fast: break 11 | 12 | slow = head 13 | while slow!=fast: 14 | slow = nums[slow] 15 | fast = nums[fast] 16 | return slow -------------------------------------------------------------------------------- /problems/python3/gas-station.py: -------------------------------------------------------------------------------- 1 | """ 2 | First thing, you must understand that if sum(gas)>=sum(cost) there must be an answer. Guaranteed. 3 | If we know there is an answer, we can simply test all the index. 4 | If the currGas ever drops to below 0, it means that we need to switch a "start". 5 | 6 | Time: O(N) 7 | Space: O(1) 8 | """ 9 | class Solution: 10 | def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int: 11 | if sum(gas) List[str]: 3 | def helper(parentheses, left, right): 4 | if len(parentheses)==n*2: 5 | ans.append("".join(parentheses)) 6 | return 7 | 8 | if leftright: 14 | parentheses.append(')') 15 | helper(parentheses, left, right+1) 16 | parentheses.pop() 17 | 18 | ans = [] 19 | helper([], 0, 0) 20 | return ans -------------------------------------------------------------------------------- /problems/python3/graph-valid-tree.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def validTree(self, N: int, edges: List[List[int]]) -> bool: 3 | def union(n1, n2) -> bool: 4 | p1 = find(n1) 5 | p2 = find(n2) 6 | 7 | if p1==p2: 8 | return False 9 | elif p1 int: 18 | p = parents[n] 19 | while p!=parents[p]: p = find(p) 20 | parents[n] = p 21 | return p 22 | 23 | parents = [n for n in range(N)] 24 | 25 | for n1, n2 in edges: 26 | if not union(n1, n2): return False 27 | 28 | #check if all node trace back to the same root 29 | root = find(0) 30 | for n in range(1, N): 31 | if root!=find(n): return False 32 | 33 | return True -------------------------------------------------------------------------------- /problems/python3/group-anagrams.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def groupAnagrams(self, strs: List[str]) -> List[List[str]]: 3 | def normalize(string: str) -> str: 4 | counter = collections.Counter() 5 | ans = '' 6 | 7 | for c in string: 8 | counter[c] += 1 9 | 10 | for c in 'abcdefghijklmnopqrstuvwxyz': 11 | if counter[c]>0: 12 | ans += c+str(counter[c]) 13 | return ans 14 | 15 | group = collections.defaultdict(list) 16 | ans = [] 17 | 18 | for string in strs: 19 | group[normalize(string)].append(string) 20 | 21 | for normalizedString in group: 22 | ans.append(group[normalizedString]) 23 | return ans -------------------------------------------------------------------------------- /problems/python3/hand-of-straights.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def isNStraightHand(self, hand: List[int], groupSize: int) -> bool: 3 | if len(hand)%groupSize!=0: return False 4 | 5 | counter = collections.Counter(hand) 6 | h = list(counter.keys()) 7 | heapq.heapify(h) 8 | 9 | while h: 10 | minNum = h[0] 11 | for n in range(minNum, minNum+groupSize): 12 | if counter[n]<=0: return False 13 | counter[n] -= 1 14 | if counter[n]==0: 15 | if h[0]!=n: return False 16 | heapq.heappop(h) 17 | 18 | return True -------------------------------------------------------------------------------- /problems/python3/happy-number.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def isHappy(self, n: int) -> bool: 3 | def digitSquare(n) -> int: 4 | ans = 0 5 | while n>0: 6 | ans += (n%10)**2 7 | n = n//10 8 | return ans 9 | 10 | visited = set() 11 | visited.add(1) 12 | 13 | while n not in visited: 14 | visited.add(n) 15 | n = digitSquare(n) 16 | 17 | return n==1 18 | -------------------------------------------------------------------------------- /problems/python3/house-robber-ii.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def rob(self, nums: List[int]) -> int: 3 | if len(nums)<=1: return max(nums) 4 | 5 | N = len(nums) 6 | dp = [[0, 0] for _ in range(N)] 7 | dp[0][0] = nums[0] 8 | 9 | for i in range(1, N): 10 | dp[i][0] = nums[i]+dp[i-1][1] 11 | dp[i][1] = max(dp[i-1]) 12 | 13 | dp2 = [[0, 0] for _ in range(N)] 14 | for i in range(1, N): 15 | dp2[i][0] = nums[i]+dp2[i-1][1] 16 | dp2[i][1] = max(dp2[i-1]) 17 | 18 | return max(dp[-1][1], dp2[-1][0]) -------------------------------------------------------------------------------- /problems/python3/house-robber.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(N) 3 | Space: O(N), can reduece to O(1). 4 | 5 | dp[i][0] := max revenue if house i robbed 6 | dp[i][1] := max revenue if house i not robbed 7 | """ 8 | class Solution: 9 | def rob(self, nums: List[int]) -> int: 10 | N = len(nums) 11 | dp = [[0, 0] for _ in range(N)] 12 | dp[0][0] = nums[0] 13 | 14 | for i in range(1, N): 15 | dp[i][0] = nums[i]+dp[i-1][1] 16 | dp[i][1] = max(dp[i-1]) 17 | return max(dp[-1]) -------------------------------------------------------------------------------- /problems/python3/implement-trie-prefix-tree.py: -------------------------------------------------------------------------------- 1 | class Trie: 2 | 3 | def __init__(self): 4 | self.root = {} 5 | 6 | def insert(self, word: str) -> None: 7 | node = self.root 8 | for c in word: 9 | if c not in node: node[c] = {} 10 | node = node[c] 11 | node['.'] = {} #'.' means the end of the word 12 | 13 | 14 | def search(self, word: str) -> bool: 15 | node = self.root 16 | for c in word: 17 | if c not in node: return False 18 | node = node[c] 19 | return '.' in node 20 | 21 | def startsWith(self, prefix: str) -> bool: 22 | node = self.root 23 | for c in prefix: 24 | if c not in node: return False 25 | node = node[c] 26 | return True 27 | -------------------------------------------------------------------------------- /problems/python3/insert-interval.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def insert(self, intervals: List[List[int]], newInterval: List[int]) -> List[List[int]]: 3 | ans = [] 4 | i = 0 5 | 6 | #add intervals before newInterval 7 | while i bool: 3 | def dfs(i, j): 4 | if (i, j) in history: return False 5 | if i+j==len(s3): return True 6 | if i Optional[TreeNode]: 8 | if not root: return root 9 | left = root.left 10 | right = root.right 11 | root.left = self.invertTree(right) 12 | root.right = self.invertTree(left) 13 | return root 14 | 15 | 16 | """ 17 | Iterative 18 | Time: O(N) 19 | Space: O(N) 20 | """ 21 | class Solution: 22 | def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]: 23 | if not root: return root 24 | q = collections.deque([root]) 25 | 26 | while q: 27 | node = q.popleft() 28 | left = node.left 29 | right = node.right 30 | node.right = left 31 | node.left = right 32 | 33 | if node.left: q.append(node.left) 34 | if node.right: q.append(node.right) 35 | 36 | return root -------------------------------------------------------------------------------- /problems/python3/jump-game-ii.py: -------------------------------------------------------------------------------- 1 | """ 2 | l and r is the index range we can reach within "steps". 3 | So while r can not reach the end (`r int: 10 | l = r = 0 11 | steps = 0 12 | 13 | while r bool: 3 | maxIndex = 0 4 | 5 | for i, num in enumerate(nums): 6 | if maxIndex List[List[int]]: 3 | h = [] 4 | 5 | for x, y in points: 6 | dis = (x**2+y**2)**0.5 7 | heapq.heappush(h, (-dis, x, y)) 8 | if len(h)>k: heapq.heappop(h) 9 | 10 | return [(x, y) for dis, x, y in h] -------------------------------------------------------------------------------- /problems/python3/koko-eating-bananas.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def minEatingSpeed(self, piles: List[int], h: int) -> int: 3 | def canFinish(k): 4 | timeNeeded = 0 5 | for pile in piles: 6 | timeNeeded += math.ceil(pile/k) 7 | return timeNeeded<=h 8 | 9 | kMin = 1 10 | kMax = max(piles) 11 | ans = kMax 12 | 13 | while kMin<=kMax: 14 | k = kMin + int((kMax-kMin)/2) 15 | if canFinish(k): 16 | ans = min(ans, k) 17 | kMax = k-1 18 | else: 19 | kMin = k+1 20 | 21 | return ans -------------------------------------------------------------------------------- /problems/python3/kth-largest-element-in-a-stream.py: -------------------------------------------------------------------------------- 1 | class KthLargest: 2 | 3 | def __init__(self, k: int, nums: List[int]): 4 | self.k = k 5 | self.nums = nums 6 | 7 | heapq.heapify(self.nums) 8 | while len(self.nums)>self.k: heapq.heappop(self.nums) 9 | 10 | 11 | def add(self, val: int) -> int: 12 | heapq.heappush(self.nums, val) 13 | if len(self.nums)>self.k: heapq.heappop(self.nums) 14 | return self.nums[0] -------------------------------------------------------------------------------- /problems/python3/kth-smallest-element-in-a-bst.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(N) for the inorder traversal 3 | Space: O(LogN) if the tree is balanced. 4 | """ 5 | class Solution: 6 | def kthSmallest(self, root: Optional[TreeNode], k: int) -> int: 7 | count = 0 8 | stack = [] 9 | node = root 10 | 11 | while stack or node: 12 | while node: 13 | stack.append(node) 14 | node = node.left 15 | node = stack.pop() 16 | 17 | count += 1 18 | if count==k: return node.val 19 | 20 | node = node.right 21 | return 0 -------------------------------------------------------------------------------- /problems/python3/largest-rectangle-in-histogram.py: -------------------------------------------------------------------------------- 1 | """ 2 | [0] For each height, if the it is lower than the previous one, it means that the previous are not able to extend anymore. So we calculate its area. 3 | 4 | [1] If the previous area, is larger than the current one, it means that the current one are able to extand backward. 5 | """ 6 | class Solution: 7 | def largestRectangleArea(self, heights: List[int]) -> int: 8 | maxArea = 0 9 | stack = [] 10 | 11 | heights.append(0) #dummy for the ending 12 | 13 | for i, h in enumerate(heights): 14 | start = i 15 | while stack and h int: 3 | stones = [-stone for stone in stones] 4 | heapq.heapify(stones) 5 | 6 | while len(stones)>=2: 7 | w1 = -heapq.heappop(stones) 8 | w2 = -heapq.heappop(stones) 9 | 10 | if w1-w2>0: heapq.heappush(stones, -(w1-w2)) 11 | 12 | return -stones[0] if stones else 0 -------------------------------------------------------------------------------- /problems/python3/letter-combinations-of-a-phone-number.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(4^N * N), there are around 4^N of combination. Each taking O(N) to form. 3 | Space: O(N). O(N) for recursion stack. O(N). O(N) for `combination`. O(N+N) ~= O(N). 4 | """ 5 | class Solution: 6 | def letterCombinations(self, digits: str) -> List[str]: 7 | def helper(i): 8 | if i==len(digits): 9 | ans.append(''.join(combination)) 10 | return 11 | 12 | for c in mapping[digits[i]]: 13 | combination.append(c) 14 | helper(i+1) 15 | combination.pop() 16 | 17 | mapping = {'2': ('a', 'b', 'c'), '3': ('d', 'e', 'f'), 18 | '4': ('g', 'h', 'i'), '5': ('j', 'k', 'l'), '6': ('m', 'n', 'o'), 19 | '7': ('p', 'q', 'r', 's'), '8': ('t', 'u', 'v'), '9': ('w', 'x', 'y', 'z')} 20 | 21 | if not digits: return [] 22 | ans = [] 23 | combination = [] 24 | helper(0) 25 | return ans -------------------------------------------------------------------------------- /problems/python3/linked-list-cycle.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def hasCycle(self, head: Optional[ListNode]) -> bool: 3 | if not head: return False 4 | 5 | slow = head 6 | fast = head 7 | 8 | while fast: 9 | slow = slow.next 10 | 11 | if not fast.next: return False 12 | fast = fast.next.next 13 | 14 | if slow==fast: return True 15 | 16 | return False -------------------------------------------------------------------------------- /problems/python3/longest-common-subsequence.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def longestCommonSubsequence(self, text1: str, text2: str) -> int: 3 | #dp[i][j] := number of longest Common Subsequence with text2[:i] and text2[:j] 4 | 5 | N = len(text1) 6 | M = len(text2) 7 | 8 | dp = [[0]*(M+1) for _ in range(N+1)] 9 | 10 | for i in range(1, N+1): 11 | for j in range(1, M+1): 12 | if text1[i-1]==text2[j-1]: 13 | dp[i][j] = dp[i-1][j-1]+1 14 | else: 15 | dp[i][j] = max(dp[i][j-1], dp[i-1][j]) 16 | return dp[-1][-1] -------------------------------------------------------------------------------- /problems/python3/longest-consecutive-sequence.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def longestConsecutive(self, nums: List[int]) -> int: 3 | numSet = set(nums) 4 | ans = 0 5 | 6 | for num in nums: 7 | isStart = num-1 not in numSet 8 | if isStart: 9 | count = 0 10 | temp = num 11 | while temp in numSet: 12 | count += 1 13 | temp += 1 14 | ans = max(count, ans) 15 | return ans -------------------------------------------------------------------------------- /problems/python3/longest-increasing-path-in-a-matrix.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(MN) since the memo at most has MN index. 3 | Space: O(MN) 4 | """ 5 | class Solution: 6 | def longestIncreasingPath(self, matrix: List[List[int]]) -> int: 7 | def dfs(i0, j0): 8 | if (i0, j0) in memo: return memo[(i0, j0)] 9 | ans = 1 10 | 11 | for i, j in ((i0+1, j0), (i0-1, j0), (i0, j0+1),(i0, j0-1)): 12 | if i<0 or i>=N or j<0 or j>=M: continue 13 | if matrix[i][j]<=matrix[i0][j0]: continue 14 | ans = max(ans, 1+dfs(i, j)) 15 | 16 | memo[(i0, j0)] = ans 17 | return ans 18 | 19 | N = len(matrix) 20 | M = len(matrix[0]) 21 | memo = {} 22 | ans = 0 23 | for i in range(N): 24 | for j in range(M): 25 | ans = max(ans, dfs(i, j)) 26 | return ans -------------------------------------------------------------------------------- /problems/python3/longest-repeating-character-replacement.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def characterReplacement(self, s: str, k: int) -> int: 3 | counter = collections.Counter() 4 | l = 0 5 | ans = 0 6 | 7 | for r in range(len(s)): 8 | counter[s[r]] += 1 9 | while (r-l+1)-max(counter.values()) > k: 10 | counter[s[l]] -= 1 11 | l += 1 12 | ans = max(ans, r-l+1) 13 | return ans -------------------------------------------------------------------------------- /problems/python3/longest-substring-without-repeating-char.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def lengthOfLongestSubstring(self, s: str) -> int: 3 | ans = 0 4 | l = 0 5 | seen = set() 6 | 7 | for r in range(len(s)): 8 | while s[r] in seen: 9 | seen.remove(s[l]) 10 | l += 1 11 | seen.add(s[r]) 12 | ans = max(ans, r-l+1) 13 | 14 | return ans -------------------------------------------------------------------------------- /problems/python3/max-area-of-island.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def maxAreaOfIsland(self, grid: List[List[int]]) -> int: 3 | def dfs(i, j) -> int: 4 | if i<0 or j<0 or i>=MAX_ROW or j>=MAX_COL: return 0 5 | if grid[i][j]==0 or grid[i][j]==2: return 0 6 | 7 | grid[i][j] = 2 #mark as visited 8 | 9 | area = 1 10 | area += dfs(i+1, j) 11 | area += dfs(i-1, j) 12 | area += dfs(i, j+1) 13 | area += dfs(i, j-1) 14 | return area 15 | 16 | ans = 0 17 | MAX_ROW = len(grid) 18 | MAX_COL = len(grid[0]) 19 | 20 | for i in range(MAX_ROW): 21 | for j in range(MAX_COL): 22 | ans = max(ans, dfs(i, j)) 23 | return ans -------------------------------------------------------------------------------- /problems/python3/maximum-depth-of-binary-tree.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(N) 3 | Space:O(LogN), for recursion stack space. 4 | """ 5 | class Solution: 6 | def maxDepth(self, root: Optional[TreeNode]) -> int: 7 | if not root: return 0 8 | return 1+max(self.maxDepth(root.left), self.maxDepth(root.right)) -------------------------------------------------------------------------------- /problems/python3/maximum-product-subarray.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(N) 3 | Space: O(N), can be reduce to O(1) 4 | 5 | dp[i][0] := The max product from subarray that end with nums[i] 6 | dp[i][1] := The min product from subarray that end with nums[i] 7 | """ 8 | class Solution: 9 | def maxProduct(self, nums: List[int]) -> int: 10 | N = len(nums) 11 | dp = [[1, 1] for _ in range(N+1)] 12 | ans = float('-inf') 13 | 14 | for i in range(1, N+1): 15 | dp[i][0] = dp[i][1] = nums[i-1] 16 | 17 | if nums[i-1]>0: 18 | dp[i][0] = max(dp[i][0], nums[i-1]*dp[i-1][0]) 19 | dp[i][1] = min(dp[i][1], nums[i-1]*dp[i-1][1]) 20 | else: 21 | dp[i][0] = max(dp[i][0], nums[i-1]*dp[i-1][1]) 22 | dp[i][1] = min(dp[i][1], nums[i-1]*dp[i-1][0]) 23 | ans = max(ans, dp[i][0]) 24 | 25 | return ans -------------------------------------------------------------------------------- /problems/python3/maximum-subarray.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(N) 3 | Space: O(1) 4 | 5 | Calculate the prefix sum. Whenever the prefix is negative, we ignore all the value before. 6 | Update the ans along the way. 7 | """ 8 | class Solution: 9 | def maxSubArray(self, nums: List[int]) -> int: 10 | ans = float('-inf') 11 | currSum = 0 12 | 13 | for num in nums: 14 | if currSum<0: currSum = 0 15 | currSum += num 16 | ans = max(ans, currSum) 17 | return ans -------------------------------------------------------------------------------- /problems/python3/meeting-rooms-ii.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def minMeetingRooms(self, intervals: List[List[int]]) -> int: 3 | intervals.sort() 4 | h = [] 5 | ans = 0 6 | 7 | for s, e in intervals: 8 | while h and s>=h[0][0]: 9 | heapq.heappop(h) 10 | heapq.heappush(h, (e, s)) 11 | ans = max(ans, len(h)) 12 | return ans -------------------------------------------------------------------------------- /problems/python3/meeting-rooms.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def canAttendMeetings(self, intervals: List[List[int]]) -> bool: 3 | intervals.sort() 4 | lastEnd = float('-inf') 5 | for s, e in intervals: 6 | if lastEnd>s: 7 | return False 8 | else: 9 | lastEnd = e 10 | return True -------------------------------------------------------------------------------- /problems/python3/merge-intervals.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(NLogN) for sorting 3 | Space: O(1) excluding the output. 4 | """ 5 | class Solution: 6 | def merge(self, intervals: List[List[int]]) -> List[List[int]]: 7 | ans = [] 8 | intervals.sort() 9 | 10 | for s, e in intervals: 11 | if not ans: 12 | ans.append([s, e]) 13 | elif ans[-1][1]>=s: 14 | ans[-1][1] = max(ans[-1][1], e) 15 | else: 16 | ans.append([s, e]) 17 | return ans -------------------------------------------------------------------------------- /problems/python3/merge-triplets-to-form-target-triplet.py: -------------------------------------------------------------------------------- 1 | """ 2 | If any element in the triplets is larger than the element in target, it cannot be used. 3 | Check if we have all 3 index found the same value. 4 | """ 5 | class Solution: 6 | def mergeTriplets(self, triplets: List[List[int]], target: List[int]) -> bool: 7 | okIndex = set() 8 | 9 | for a, b, c in triplets: 10 | if a>target[0] or b>target[1] or c>target[2]: continue 11 | if a==target[0]: okIndex.add(0) 12 | if b==target[1]: okIndex.add(1) 13 | if c==target[2]: okIndex.add(2) 14 | 15 | return len(okIndex)==3 -------------------------------------------------------------------------------- /problems/python3/merge-two-sorted-lists.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]: 3 | head = ListNode() #dummy 4 | node = head 5 | while list1 and list2: 6 | if list1.val O(1). 4 | 5 | dp[i] := the cost to get to index i. 6 | """ 7 | class Solution: 8 | def minCostClimbingStairs(self, cost: List[int]) -> int: 9 | N = len(cost) 10 | dp = [float('inf')]*(N+1) 11 | dp[0] = 0 12 | dp[1] = 0 13 | 14 | for i in range(2, len(dp)): 15 | dp[i] = min(dp[i-1]+cost[i-1], dp[i-2]+cost[i-2]) 16 | return dp[-1] -------------------------------------------------------------------------------- /problems/python3/min-stack.py: -------------------------------------------------------------------------------- 1 | #"stack" is just a normal stack. 2 | #"minStack" stores the min of the stack element in the same position. 3 | #i.e. At the time stack[x] put in to the stack. minStack[x] is the min. 4 | 5 | class MinStack: 6 | 7 | def __init__(self): 8 | self.stack = [] 9 | self.minStack = [] 10 | 11 | def push(self, val: int) -> None: 12 | self.stack.append(val) 13 | self.minStack.append(val if (not self.minStack or val None: 16 | self.minStack.pop() 17 | return self.stack.pop() 18 | 19 | def top(self) -> int: 20 | return self.stack[-1] 21 | 22 | def getMin(self) -> int: 23 | return self.minStack[-1] -------------------------------------------------------------------------------- /problems/python3/missing-number.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def missingNumber(self, nums: List[int]) -> int: 3 | N = len(nums) 4 | ans = 0 5 | 6 | for n in range(N+1): 7 | ans ^= n 8 | 9 | for n in nums: 10 | ans ^= n 11 | 12 | return ans -------------------------------------------------------------------------------- /problems/python3/multiply-strings.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def multiply(self, num1: str, num2: str) -> str: 3 | if num1=='0' or num2=='0': return '0' 4 | M, N = len(num1), len(num2) 5 | temp = [0]*(M+N+1) 6 | 7 | num1, num2 = num1[::-1], num2[::-1] 8 | for i in range(M): 9 | for j in range(N): 10 | digits = int(num1[i])*int(num2[j]) 11 | temp[i+j] += digits 12 | temp[i+j+1] += temp[i+j]//10 13 | temp[i+j] = temp[i+j]%10 14 | 15 | ans = '' 16 | temp = temp[::-1] 17 | isLeadingZero = True 18 | for d in temp: 19 | if d!=0 or not isLeadingZero: 20 | isLeadingZero = False 21 | ans += str(d) 22 | return ans -------------------------------------------------------------------------------- /problems/python3/network-delay-time.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def networkDelayTime(self, times: List[List[int]], n: int, k: int) -> int: 3 | ans = 0 4 | adj = collections.defaultdict(list) 5 | h = [] 6 | visited = set() 7 | 8 | for u, v, w in times: 9 | adj[u].append((v, w)) 10 | 11 | heapq.heappush(h, (0, k)) 12 | while h: 13 | timeNeededToGetHere, node = heapq.heappop(h) 14 | 15 | if node in visited: continue 16 | visited.add(node) 17 | ans = max(ans, timeNeededToGetHere) 18 | 19 | for nei, time in adj[node]: 20 | if nei in visited: continue 21 | heapq.heappush(h, (time+timeNeededToGetHere, nei)) 22 | 23 | return ans if len(visited)==n else -1 -------------------------------------------------------------------------------- /problems/python3/non-overlapping-intervals.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(NLogN) for sorting. 3 | """ 4 | class Solution: 5 | def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int: 6 | intervals.sort() 7 | 8 | ans = 0 9 | prevEnd = intervals[0][1] 10 | 11 | for s, e in intervals[1:]: 12 | if s>=prevEnd: 13 | prevEnd = e 14 | else: 15 | ans += 1 16 | prevEnd = min(prevEnd, e) 17 | return ans -------------------------------------------------------------------------------- /problems/python3/number-of-1-bits.py: -------------------------------------------------------------------------------- 1 | """ 2 | n = n&(n-1) will turn the right most 1 to 0. 3 | """ 4 | class Solution: 5 | def hammingWeight(self, n: int) -> int: 6 | ans = 0 7 | while n>0: 8 | n = n&(n-1) 9 | ans += 1 10 | return ans -------------------------------------------------------------------------------- /problems/python3/number-of-connected-components-in-an-undirected-graph.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def countComponents(self, N: int, edges: List[List[int]]) -> int: 3 | def union(n1, n2): 4 | p1 = find(n1) 5 | p2 = find(n2) 6 | if p1==p2: 7 | return 8 | elif p1 int: 3 | def dfs(i, j): 4 | if i<0 or j<0 or i>=MAX_ROWS or j>=MAX_COLS: return 5 | if grid[i][j]!='1': return 6 | 7 | grid[i][j] = '2' 8 | dfs(i+1, j) 9 | dfs(i-1, j) 10 | dfs(i, j+1) 11 | dfs(i, j-1) 12 | 13 | count = 0 14 | MAX_ROWS = len(grid) 15 | MAX_COLS = len(grid[0]) 16 | 17 | for i in range(MAX_ROWS): 18 | for j in range(MAX_COLS): 19 | if grid[i][j]=='1': 20 | dfs(i, j) 21 | count += 1 22 | return count -------------------------------------------------------------------------------- /problems/python3/palindromic-substrings.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def countSubstrings(self, s: str) -> int: 3 | def countPalindrome(l, r) -> int: 4 | count = 0 5 | while l>=0 and r bool: 7 | total = sum(nums) 8 | if total%2!=0: return False 9 | 10 | target = total/2 11 | possibleSum = set() 12 | possibleSum.add(0) 13 | for num in nums: 14 | temp = set() 15 | for p in possibleSum: 16 | if p==target or p+num==target: return True 17 | temp.add(p) 18 | temp.add(p+num) 19 | possibleSum = temp 20 | return False -------------------------------------------------------------------------------- /problems/python3/partition-labels.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(N) 3 | Space: O(N) 4 | 5 | For each char, store its max index in maxIndex. 6 | Iterate through the string, update the "currMax" along the way. 7 | currMax is the place we can partition unless it get updated again. 8 | If the current index is the currMax, update "ans". 9 | """ 10 | class Solution: 11 | def partitionLabels(self, s: str) -> List[int]: 12 | ans = [] 13 | maxIndex = {} 14 | 15 | for i, c in enumerate(s): 16 | maxIndex[c] = i 17 | 18 | currMax = 0 19 | processedLength = 0 20 | for i, c in enumerate(s): 21 | currMax = max(currMax, maxIndex[c]) 22 | if i==currMax: 23 | ans.append(i+1 - processedLength) 24 | processedLength += ans[-1] 25 | 26 | return ans -------------------------------------------------------------------------------- /problems/python3/permutations.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(N!), since we call helper() N! times. 3 | Space: O(N) for recursion stacks. 4 | 5 | Whenever we call `helper()`, we pick a num that is not "used" and add it to the `permutation`. 6 | Recursively call the `helper()` until we filled the `permutation`. 7 | Resotre `permutation` and `used` and try another `num`. 8 | """ 9 | class Solution: 10 | def permute(self, nums: List[int]) -> List[List[int]]: 11 | def helper(): 12 | if len(permutation)==len(nums): 13 | ans.append(permutation.copy()) 14 | return 15 | 16 | for num in nums: 17 | if num in used: continue 18 | used.add(num) 19 | permutation.append(num) 20 | helper() 21 | used.remove(num) 22 | permutation.pop() 23 | 24 | ans = [] 25 | permutation = [] 26 | used = set() 27 | helper() 28 | return ans -------------------------------------------------------------------------------- /problems/python3/plus-one.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def plusOne(self, digits: List[int]) -> List[int]: 3 | i = len(digits)-1 4 | needAdditionDigit = True 5 | 6 | while i>=0 and needAdditionDigit: 7 | if digits[i]==9: 8 | digits[i] = 0 9 | i -= 1 10 | needAdditionDigit = True 11 | else: 12 | digits[i] += 1 13 | needAdditionDigit = False 14 | if needAdditionDigit: digits.insert(0, 1) 15 | return digits 16 | -------------------------------------------------------------------------------- /problems/python3/powx-n.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def myPow(self, x: float, k: int) -> float: 3 | if k<0: return 1/self.myPow(x, -k) 4 | 5 | if k==0: 6 | return 1 7 | elif k==1: 8 | return x 9 | elif k%2==0: 10 | half = self.myPow(x, k//2) 11 | return half * half 12 | else: 13 | half = self.myPow(x, (k-1)//2) 14 | return half * half * x -------------------------------------------------------------------------------- /problems/python3/reconstruct-itinerary.py: -------------------------------------------------------------------------------- 1 | """ 2 | DFS with backtracking. 3 | """ 4 | class Solution: 5 | def findItinerary(self, tickets: List[List[str]]) -> List[str]: 6 | def dfs(start) -> bool: 7 | if len(ans)==len(tickets)+1: return True 8 | if start not in adj: return False 9 | 10 | temp = list(adj[start]) 11 | for i, arr in enumerate(temp): 12 | adj[start].pop(i) 13 | ans.append(arr) 14 | if dfs(arr): return True 15 | adj[start].insert(i, arr) 16 | ans.pop() 17 | return False 18 | 19 | ans = ['JFK'] 20 | adj = collections.defaultdict(list) 21 | 22 | tickets.sort() 23 | for des, arr in tickets: 24 | adj[des].append(arr) 25 | 26 | dfs('JFK') 27 | return ans -------------------------------------------------------------------------------- /problems/python3/redundant-connection.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def findRedundantConnection(self, edges: List[List[int]]) -> List[int]: 3 | def union(n1, n2): 4 | p1 = find(n1) 5 | p2 = find(n2) 6 | 7 | if p1==p2: 8 | return False #union failed, already united. 9 | elif p1 bool: 3 | def dfs(i, j): 4 | if (i, j) in cache: return cache[(i, j)] 5 | if i>=M and j>=N: return True 6 | if j>=N: return False 7 | 8 | match = i int: 3 | res = 0 4 | for i in range(32): 5 | bit = (n >> i) & 1 6 | res = res | (bit << (31 - i)) 7 | return res -------------------------------------------------------------------------------- /problems/python3/reverse-integer.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def reverse(self, x: int) -> int: 3 | MAX = 2**31-1 4 | MIN = -2**31 5 | ans = 0 6 | 7 | while x: 8 | digit = int(math.fmod(x, 10)) 9 | x = int(x/10) 10 | 11 | if ans>MAX//10 or (ans==MAX//10 and digit>MAX%10): return 0 12 | if ans Optional[ListNode]: 4 | if not head or not head.next: return head 5 | temp = self.reverseList(head.next) 6 | head.next.next = head 7 | head.next = None 8 | return temp 9 | 10 | #Iterative 11 | class Solution: 12 | def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: 13 | pre = None 14 | node = head 15 | 16 | while node: 17 | nextNode = node.next 18 | node.next = pre 19 | if not nextNode: return node 20 | pre = node 21 | node = nextNode -------------------------------------------------------------------------------- /problems/python3/rotate-image.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def rotate(self, matrix: List[List[int]]) -> None: 3 | l, r = 0, len(matrix[0])-1 4 | 5 | while l bool: 7 | if not node1 and not node2: 8 | return True 9 | 10 | if (not node1 and node2) or (node1 and not node2): 11 | return False 12 | 13 | if node1.val!=node2.val: 14 | return False 15 | 16 | return self.isSameTree(node1.left, node2.left) and self.isSameTree(node1.right, node2.right) -------------------------------------------------------------------------------- /problems/python3/search-a-2d-matrix.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def searchMatrix(self, matrix: List[List[int]], target: int) -> bool: 3 | N = len(matrix) 4 | M = len(matrix[0]) 5 | 6 | l = 0 7 | r = N*M-1 8 | 9 | while l<=r: 10 | m = l + int((r-l)/2) 11 | 12 | i = int(m/M) 13 | j = m%M 14 | 15 | if matrix[i][j]target: 18 | r = m-1 19 | else: 20 | return True 21 | 22 | return False -------------------------------------------------------------------------------- /problems/python3/serialize-and-deserialize-binary-tree.py: -------------------------------------------------------------------------------- 1 | class Codec: 2 | 3 | def serialize(self, root): 4 | if not root: return '#' 5 | return str(root.val)+','+self.serialize(root.left)+','+self.serialize(root.right) 6 | 7 | 8 | def deserialize(self, data): 9 | def helper(): 10 | if data[self.i]=='#': 11 | self.i += 1 12 | return None 13 | 14 | node = TreeNode(int(data[self.i])) 15 | self.i += 1 16 | node.left = helper() 17 | node.right = helper() 18 | return node 19 | 20 | data = data.split(",") 21 | self.i = 0 22 | return helper() -------------------------------------------------------------------------------- /problems/python3/set-matrix-zeroes.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def setZeroes(self, matrix: List[List[int]]) -> None: 3 | M = len(matrix) 4 | N = len(matrix[0]) 5 | firstRowZero = False 6 | 7 | for i in range(M): 8 | for j in range(N): 9 | if matrix[i][j]==0: 10 | matrix[0][j] = 0 11 | if i==0: 12 | firstRowZero = True 13 | else: 14 | matrix[i][0] = 0 15 | 16 | for i in range(1, M): 17 | if matrix[i][0]==0: 18 | for j in range(N): 19 | matrix[i][j] = 0 20 | 21 | for j in range(N): 22 | if matrix[0][j]==0: 23 | for i in range(M): 24 | matrix[i][j] = 0 25 | 26 | if firstRowZero: 27 | for j in range(N): 28 | matrix[0][j] = 0 -------------------------------------------------------------------------------- /problems/python3/single-number.py: -------------------------------------------------------------------------------- 1 | """ 2 | ^ (XOR) 3 | The same will be 0 4 | 0^0 = 0 5 | 1^1 = 0 6 | 7 | Different will be 1 8 | 1^0 = 1 9 | 0^1 = 1 10 | """ 11 | class Solution: 12 | def singleNumber(self, nums: List[int]) -> int: 13 | ans = 0 14 | for num in nums: ans ^= num 15 | return ans -------------------------------------------------------------------------------- /problems/python3/sliding-window-maximum.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]: 3 | ans = [] 4 | q = collections.deque() 5 | l = r = 0 6 | 7 | while r List[List[int]]: 7 | def helper(i): 8 | if i==len(nums): 9 | ans.append(subset.copy()) 10 | return 11 | 12 | subset.append(nums[i]) 13 | helper(i+1) 14 | subset.pop() 15 | 16 | while i+1 List[List[int]]: 7 | def helper(i): 8 | if not i bool: 3 | if not root or not subRoot: return root==subRoot 4 | if self.isSame(root, subRoot): return True 5 | return self.isSubtree(root.left, subRoot) or self.isSubtree(root.right, subRoot) 6 | 7 | def isSame(self, p, q): 8 | if not p or not q: return p==q 9 | if p.val!=q.val: return False 10 | return self.isSame(p.left, q.left) and self.isSame(p.right, q.right) -------------------------------------------------------------------------------- /problems/python3/sum-of-two-integers.py: -------------------------------------------------------------------------------- 1 | """ 2 | Does not work with negative values yet. 3 | """ 4 | class Solution: 5 | def getSum(self, a: int, b: int) -> int: 6 | ans = a^b 7 | carry = (a&b)<<1 8 | 9 | while carry!=0: 10 | ans, carry = ans^carry, (ans&carry)<<1 11 | 12 | return ans -------------------------------------------------------------------------------- /problems/python3/swim-in-rising-water.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(N^2 * LogN^2) = O(N^2 * 2LogN) = O(N^2LogN), N is the number of elements in a row or column. 3 | Space: O(N^2) 4 | """ 5 | class Solution: 6 | def swimInWater(self, grid: List[List[int]]) -> int: 7 | ROWS = len(grid) 8 | COLS = len(grid[0]) 9 | 10 | visited = set() 11 | h = [(grid[0][0], 0, 0)] 12 | 13 | while h: 14 | t, r0, c0 = heapq.heappop(h) 15 | 16 | if (r0, c0) in visited: continue 17 | visited.add((r0, c0)) 18 | if r0==ROWS-1 and c0==COLS-1: return t 19 | 20 | for r, c in ((r0+1, c0), (r0-1, c0), (r0, c0+1), (r0, c0-1)): 21 | if r<0 or c<0 or r>=ROWS or c>=COLS: continue 22 | if (r, c) in visited: continue 23 | heapq.heappush(h, (max(t, grid[r][c]), r, c)) -------------------------------------------------------------------------------- /problems/python3/target-sum.py: -------------------------------------------------------------------------------- 1 | """ 2 | Time: O(NS), S is sum(nums), N is len(nums). This is the max possible number of element in "history". Which will be lesser than 2^N. 3 | Space: O(NS) 4 | """ 5 | class Solution: 6 | def findTargetSumWays(self, nums: List[int], target: int) -> int: 7 | def dfs(i, curr): 8 | #cache 9 | if (i, curr) in history: 10 | return history[(i, curr)] 11 | 12 | #ending condition 13 | if i==len(nums): 14 | if curr==target: 15 | history[(i, curr)] = 1 16 | else: 17 | history[(i, curr)] = 0 18 | return history[(i, curr)] 19 | 20 | history[(i, curr)] = dfs(i+1, curr+nums[i])+dfs(i+1, curr-nums[i]) 21 | return history[(i, curr)] 22 | 23 | ans = 0 24 | history = {} 25 | return dfs(0, 0) -------------------------------------------------------------------------------- /problems/python3/task-scheduler.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def leastInterval(self, tasks: List[str], n: int) -> int: 3 | q = collections.deque() 4 | h = [] 5 | time = 0 6 | 7 | counter = collections.Counter(tasks) 8 | for task in counter: 9 | heapq.heappush(h, (-counter[task], task)) 10 | 11 | while h or q: 12 | if q and q[0][0]<=time: 13 | _, count, task = q.popleft() 14 | heapq.heappush(h, (-count, task)) 15 | 16 | if h: 17 | count, task = heapq.heappop(h) 18 | count*=-1 19 | count -= 1 20 | if count>0: q.append((time+n+1, count, task)) 21 | time += 1 22 | 23 | return time -------------------------------------------------------------------------------- /problems/python3/time-based-key-value-store.py: -------------------------------------------------------------------------------- 1 | class TimeMap: 2 | 3 | def __init__(self): 4 | self.data = collections.defaultdict(list) 5 | 6 | def set(self, key: str, value: str, timestamp: int) -> None: 7 | self.data[key].append((timestamp, value)) 8 | 9 | def get(self, key: str, timestamp: int) -> str: 10 | dataList = self.data[key] 11 | l = 0 12 | r = len(dataList)-1 13 | ans = '' 14 | 15 | while l<=r: 16 | m = l + int((r-l)/2) 17 | t = dataList[m][0] 18 | 19 | if ttimestamp: 23 | r = m-1 24 | else: 25 | ans = dataList[m][1] 26 | break 27 | 28 | return ans -------------------------------------------------------------------------------- /problems/python3/two-sum-ii-input-array-is-sorted.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def twoSum(self, numbers: List[int], target: int) -> List[int]: 3 | i = 0 4 | j = len(numbers)-1 5 | 6 | while numbers[i]+numbers[j] != target: 7 | if numbers[i]+numbers[j] > target: 8 | j -= 1 9 | else: 10 | i += 1 11 | return (i+1, j+1) -------------------------------------------------------------------------------- /problems/python3/two-sum.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def twoSum(self, nums: List[int], target: int) -> List[int]: 3 | #needed: {number required : counter part index} 4 | needed = {} 5 | for i, num in enumerate(nums): 6 | if num in needed: 7 | return (needed[num], i) 8 | needed[target-num] = i -------------------------------------------------------------------------------- /problems/python3/unique-paths.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def uniquePaths(self, m: int, n: int) -> int: 3 | m = m-1 #number of steps need to move down 4 | n = n-1 #number of steps need to move right 5 | 6 | #the total combination of m and n to sort will be (m+n)! 7 | #since all "move down" are consider the same, we need to remove the repeatition of it sorting: m!. 8 | #since all "move right" are consider the same, we need to remove the repeatition of it sorting: n!. 9 | #(m+n)!/m!n! 10 | 11 | return math.factorial(m+n)//(math.factorial(m)*math.factorial(n)) -------------------------------------------------------------------------------- /problems/python3/valid-anagram.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def isAnagram(self, s: str, t: str) -> bool: 3 | counter = collections.Counter() 4 | 5 | for c in s: 6 | counter[c] += 1 7 | 8 | for c in t: 9 | if c not in counter: 10 | return False 11 | counter[c] -= 1 12 | 13 | for c in counter: 14 | if counter[c]>0: 15 | return False 16 | 17 | return True -------------------------------------------------------------------------------- /problems/python3/valid-palindrome.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def isPalindrome(self, s: str) -> bool: 3 | i = 0 4 | j = len(s)-1 5 | 6 | while i<=j: 7 | while i bool: 3 | mapping = {')': '(', ']': '[', '}':'{'} 4 | stack = [] 5 | 6 | for c in s: 7 | if c not in mapping: 8 | #open parentheses 9 | stack.append(c) 10 | else: 11 | #close parentheses 12 | if stack and stack[-1]==mapping[c]: 13 | stack.pop() 14 | else: 15 | return False 16 | 17 | return not stack -------------------------------------------------------------------------------- /problems/python3/valid-parenthesis-string.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def checkValidString(self, s: str) -> bool: 3 | leftMin = 0 4 | leftMax = 0 5 | 6 | for c in s: 7 | if c=='(': 8 | leftMin += 1 9 | leftMax += 1 10 | elif c==')': 11 | leftMin -= 1 12 | leftMax -= 1 13 | else: 14 | leftMin -= 1 15 | leftMax += 1 16 | 17 | if leftMax<0: 18 | return False 19 | 20 | if leftMin<0: 21 | leftMin = 0 22 | 23 | return leftMin == 0 -------------------------------------------------------------------------------- /problems/python3/validate-binary-search-tree.py: -------------------------------------------------------------------------------- 1 | """ 2 | The inorder travsersal of a BST is always increasing. 3 | 4 | Time: O(N) 5 | Space: O(N) 6 | """ 7 | class Solution: 8 | def isValidBST(self, root: Optional[TreeNode]) -> bool: 9 | lastVal = float('-inf') 10 | stack = [] 11 | 12 | node = root 13 | while stack or node: 14 | while node: 15 | stack.append(node) 16 | node = node.left 17 | 18 | node = stack.pop() 19 | 20 | if not lastVal bool: 11 | def dfs(i): 12 | if i==len(s): return True 13 | if i in history and not history[i]: return False 14 | 15 | for word in wordDict: 16 | if i+len(word)<=len(s) and s[i:i+len(word)]==word: 17 | history[i] = True 18 | if dfs(i+len(word)): return True 19 | history[i] = False 20 | return False 21 | 22 | history = {} 23 | return dfs(0) --------------------------------------------------------------------------------