├── .coveragerc ├── .github └── workflows │ └── main.yml ├── .gitignore ├── LICENSE ├── README.md ├── algorithms ├── __init__.py ├── hashing │ ├── __init__.py │ └── mad_compression.py ├── math │ ├── __init__.py │ ├── factorial.py │ ├── fibonacci.py │ └── tests │ │ ├── test_factorial.py │ │ └── test_fibonacci.py ├── searching │ ├── __init__.py │ ├── binary_search.py │ ├── linear_search.py │ └── tests │ │ ├── test_binary_search.py │ │ └── test_linear_search.py └── sorting │ ├── __init__.py │ ├── bubble_sort.py │ ├── counting_sort.py │ ├── heapsort.py │ ├── insertion_sort.py │ ├── mergesort.py │ ├── quicksort.py │ ├── selection_sort.py │ └── tests │ ├── benchmark_quicksort.py │ ├── test_bubble_sort.py │ ├── test_counting_sort.py │ ├── test_heapsort.py │ ├── test_insertion_sort.py │ ├── test_mergesort.py │ ├── test_quicksort.py │ └── test_selection_sort.py ├── codecov.yml ├── data_structures ├── __init__.py ├── arrays │ ├── __init__.py │ ├── circular_array.py │ ├── dynamic_array.py │ └── tests │ │ ├── test_circular_array.py │ │ └── test_dynamic_array.py ├── b_trees │ ├── __init__.py │ ├── b_plus_tree.py │ ├── b_tree.py │ └── tests │ │ ├── test_b_plus_tree.py │ │ └── test_b_tree.py ├── graphs │ ├── __init__.py │ ├── adjacency_map_directed_weighted_graph.py │ ├── adjacency_map_undirected_weighted_graph.py │ └── tests │ │ ├── test_adjacency_map_directed_weighted_graph.py │ │ └── test_adjacency_map_undirected_weighted_graph.py ├── hash_maps │ ├── __init__.py │ ├── base_map.py │ ├── chain_hash_map.py │ ├── linear_probing_hash_map.py │ ├── sorted_table_map.py │ ├── tests │ │ ├── test_chain_hash_map.py │ │ ├── test_linear_probing_hash_map.py │ │ ├── test_sorted_table_map.py │ │ └── test_unsorted_table_map.py │ └── unsorted_table_map.py ├── heaps │ ├── __init__.py │ ├── array_based_binary_heap.py │ └── tests │ │ └── test_array_based_binary_heap.py ├── linked_lists │ ├── __init__.py │ ├── doubly_linked_list.py │ ├── singly_linked_list.py │ └── tests │ │ ├── test_doubly_linked_list.py │ │ └── test_singly_linked_list.py ├── queues │ ├── __init__.py │ ├── array_based_queue.py │ ├── circular_array_based_queue.py │ ├── doubly_linked_list_based_deque.py │ ├── heap_based_priority_queue.py │ ├── linked_list_based_queue.py │ └── tests │ │ ├── test_array_based_queue.py │ │ ├── test_circular_array_based_queue.py │ │ ├── test_doubly_linked_list_based_deque.py │ │ ├── test_heap_based_priority_queue.py │ │ └── test_linked_list_based_queue.py ├── sets │ ├── __init__.py │ ├── hash_map_based_multiset.py │ ├── hash_map_based_set.py │ ├── quick_find_union_find.py │ ├── tests │ │ ├── test_hash_map_based_multiset.py │ │ ├── test_hash_map_based_set.py │ │ ├── test_quick_find_union_find.py │ │ └── test_weighted_quick_union_union_find.py │ └── weighted_quick_union_union_find.py ├── stacks │ ├── __init__.py │ ├── array_based_stack.py │ ├── linked_list_based_stack.py │ └── tests │ │ ├── test_array_based_stack.py │ │ └── test_linked_list_based_stack.py └── trees │ ├── __init__.py │ ├── base_tree.py │ ├── binary_search_tree.py │ ├── binary_tree_serialization.py │ ├── tests │ ├── test_binary_search_tree.py │ ├── test_binary_tree_serialization.py │ ├── test_treap.py │ └── test_trie.py │ ├── treap.py │ └── trie.py ├── poetry.lock ├── problems ├── __init__.py ├── add_two_numbers.py ├── array_intersection.py ├── array_sum.py ├── balanced_binary_tree.py ├── best_time_to_buy_and_sell_stock.py ├── bfs_shortest_path_in_a_graph.py ├── big_countries.sql ├── binary_search_tree_iterator.py ├── binary_tree_inorder_traversal.py ├── binary_tree_level_order_traversal.py ├── binary_tree_maximum_path_sum.py ├── binary_tree_postorder_traversal.py ├── binary_tree_preorder_traversal.py ├── camel_case.py ├── check_completeness_of_a_binary_tree.py ├── clone_graph.py ├── coin_change.py ├── combinations.py ├── container_with_most_water.py ├── contains_duplicate.py ├── counting_valleys.py ├── course_schedule.py ├── delete_node_in_a_linked_list.py ├── dijkstra_shortest_reach_2.py ├── equality_in_a_array.py ├── fibonacci_number.py ├── find_minimum_in_rotated_sorted_array.py ├── find_mode_in_binary_search_tree.py ├── find_the_duplicate_number.py ├── fizz_buzz.py ├── group_anagrams.py ├── hackerrank_in_a_string.py ├── hash_tables_ransom_note.py ├── implement_strstr.py ├── implement_trie_prefix_tree.py ├── invert_binary_tree.py ├── is_subsequence.py ├── jumping_on_the_clouds.py ├── kruskal_mst_really_special_subtree.py ├── kth_largest_element_in_an_array.py ├── kth_smallest_element_in_a_bst.py ├── linked_list_cycle.py ├── mars_exploration.py ├── maximum_depth_of_binary_tree.py ├── maximum_element.py ├── maximum_product_subarray.py ├── maximum_subarray.py ├── median_of_two_sorted_arrays.py ├── merge_intervals.py ├── merge_k_sorted_lists.py ├── merge_two_sorted_lists.py ├── middle_of_the_linked_list.py ├── min_stack.py ├── minimum_depth_of_binary_tree.py ├── missing_number.py ├── nth_highest_salary.sql ├── pangrams.py ├── path_sum.py ├── permutations.py ├── power_of_two.py ├── prim_mst_special_subtree.py ├── product_of_array_except_self.py ├── rank_scores.sql ├── remove_nth_node_from_end_of_list.py ├── repeated_string.py ├── reverse_integer.py ├── reverse_linked_list.py ├── reverse_only_alphabetical.py ├── reverse_string.py ├── same_tree.py ├── search_in_a_binary_search_tree.py ├── search_in_rotated_sorted_array.py ├── second_highest_salary.sql ├── serialize_and_deserialize_binary_tree.py ├── shuffle_the_array.py ├── simple_text_editor.py ├── single_number.py ├── sock_merchant.py ├── sort_colors.py ├── sort_list.py ├── subsets.py ├── task_scheduler.py ├── tests │ ├── test_add_two_numbers.py │ ├── test_array_intersection.py │ ├── test_balanced_binary_tree.py │ ├── test_best_time_to_buy_and_sell_stock.py │ ├── test_binary_search_tree_iterator.py │ ├── test_binary_tree_inorder_traversal.py │ ├── test_binary_tree_level_order_traversal.py │ ├── test_binary_tree_maximum_path_sum.py │ ├── test_binary_tree_postorder_traversal.py │ ├── test_binary_tree_preorder_traversal.py │ ├── test_camel_case.py │ ├── test_check_completeness_of_a_binary_tree.py │ ├── test_coin_change.py │ ├── test_combinations.py │ ├── test_container_with_most_water.py │ ├── test_contains_duplicate.py │ ├── test_counting_valleys.py │ ├── test_equality_in_a_array.py │ ├── test_fibonacci_number.py │ ├── test_find_minimum_in_rotated_sorted_array.py │ ├── test_find_mode_in_binary_search_tree.py │ ├── test_find_the_duplicate_number.py │ ├── test_fizz_buzz.py │ ├── test_group_anagrams.py │ ├── test_hackerrank_in_a_string.py │ ├── test_implement_strstr.py │ ├── test_implement_trie_prefix_tree.py │ ├── test_invert_binary_tree.py │ ├── test_is_subsequence.py │ ├── test_jumping_on_the_clouds.py │ ├── test_kth_largest_element_in_an_array.py │ ├── test_kth_smallest_element_in_a_bst.py │ ├── test_mars_exploration.py │ ├── test_maximum_depth_of_binary_tree.py │ ├── test_maximum_product_subarray.py │ ├── test_maximum_subarray.py │ ├── test_median_of_two_sorted_arrays.py │ ├── test_merge_intervals.py │ ├── test_merge_k_sorted_lists.py │ ├── test_merge_two_sorted_lists.py │ ├── test_middle_of_the_linked_list.py │ ├── test_min_stack.py │ ├── test_minimum_depth_of_binary_tree.py │ ├── test_missing_number.py │ ├── test_pangrams.py │ ├── test_path_sum.py │ ├── test_permutations.py │ ├── test_power_of_two.py │ ├── test_product_of_array_except_self.py │ ├── test_remove_nth_node_from_end_of_list.py │ ├── test_repeated_string.py │ ├── test_reverse_integer.py │ ├── test_reverse_linked_list.py │ ├── test_reverse_only_alphabetical.py │ ├── test_reverse_string.py │ ├── test_same_tree.py │ ├── test_search_in_a_binary_search_tree.py │ ├── test_search_in_rotated_sorted_array.py │ ├── test_serialize_and_deserialize_binary_tree.py │ ├── test_shuffle_the_array.py │ ├── test_single_number.py │ ├── test_sock_merchant.py │ ├── test_sort_colors.py │ ├── test_sort_list.py │ ├── test_subsets.py │ ├── test_task_scheduler.py │ ├── test_third_maximum_number.py │ ├── test_three_sum.py │ ├── test_top_k_frequent_elements.py │ ├── test_trapping_rain_water.py │ ├── test_two_characters.py │ ├── test_two_sum.py │ ├── test_two_sum_ii_input_array_is_sorted.py │ ├── test_univalued_binary_tree.py │ ├── test_valid_anagram.py │ ├── test_valid_palindrome.py │ ├── test_valid_parentheses.py │ └── test_validate_binary_search_tree.py ├── third_maximum_number.py ├── three_sum.py ├── top_k_frequent_elements.py ├── trapping_rain_water.py ├── tree_height_of_a_binary_tree.py ├── tree_top_view.py ├── two_characters.py ├── two_sum.py ├── two_sum_ii_input_array_is_sorted.py ├── univalued_binary_tree.py ├── utils │ ├── __init__.py │ └── leetcode.py ├── valid_anagram.py ├── valid_palindrome.py ├── valid_parentheses.py └── validate_binary_search_tree.py ├── pyproject.toml ├── pytest.ini └── requirements-dev.txt /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | branch = True 3 | omit = 4 | */tests/* 5 | problems/array_sum.py 6 | problems/bfs_shortest_path_in_a_graph.py 7 | problems/clone_graph.py 8 | problems/course_schedule.py 9 | problems/delete_node_in_a_linked_list.py 10 | problems/dijkstra_shortest_reach_2.py 11 | problems/hash_tables_ransom_note.py 12 | problems/kruskal_mst_really_special_subtree.py 13 | problems/linked_list_cycle.py 14 | problems/maximum_element.py 15 | problems/prim_mst_special_subtree.py 16 | problems/simple_text_editor.py 17 | problems/tree_height_of_a_binary_tree.py 18 | problems/tree_top_view.py 19 | 20 | [report] 21 | exclude_lines = 22 | if __name__ == '__main__': 23 | pragma: no cover 24 | __repr__ 25 | __str__ 26 | \.\.\. 27 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: CI 3 | 4 | on: [push, pull_request] 5 | 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | 10 | strategy: 11 | matrix: 12 | python-version: [3.6, 3.7, 3.8] 13 | 14 | steps: 15 | - name: Checkout code 16 | uses: actions/checkout@v2 17 | 18 | - name: Set up Python ${{ matrix.python-version }} 19 | uses: actions/setup-python@v2 20 | with: 21 | python-version: ${{ matrix.python-version }} 22 | 23 | - name: Install dependencies 24 | run: | 25 | python -m pip install --upgrade pip 26 | python -m pip install -r requirements-dev.txt 27 | 28 | # python -m xxx will put the current directory into sys.path 29 | - name: Run tests 30 | run: python -m pytest --benchmark-skip --cov=algorithms --cov=data_structures --cov=problems 31 | 32 | - name: Upload test reports 33 | run: bash <(curl -s https://codecov.io/bash) 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Vinta Chen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /algorithms/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinta/fuck-coding-interviews/dfff746353781cf0fe8adbc886ff2dfd65e66d37/algorithms/__init__.py -------------------------------------------------------------------------------- /algorithms/hashing/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinta/fuck-coding-interviews/dfff746353781cf0fe8adbc886ff2dfd65e66d37/algorithms/hashing/__init__.py -------------------------------------------------------------------------------- /algorithms/hashing/mad_compression.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import random 3 | 4 | 5 | PRIME = 109345121 6 | SCALE = 1 + random.randrange(PRIME - 1) 7 | SHIFT = random.randrange(PRIME) 8 | 9 | 10 | def mad(hash_code, array_size): 11 | """ 12 | It is common to view a hash function, h(k), as consisting of two parts: 13 | 1. A hash code that maps a key k to an integer. 14 | 2. A compression function that maps the hash code to an index within [0, N − 1], for a bucket array. 15 | 16 | We use Python's built-in hash() to produce hash code for key, 17 | and a randomized Multiply-Add-and-Divide (MAD) formula as compression function: 18 | 19 | ((hash_code * scale + shift) mod P) mod N 20 | 21 | where N is the size of the bucket array, 22 | P is a prime number larger than N, 23 | and scale and shift are random integers from the [0, p – 1], with scale > 0. 24 | """ 25 | return ((hash_code * SCALE + SHIFT) % PRIME) % array_size 26 | -------------------------------------------------------------------------------- /algorithms/math/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinta/fuck-coding-interviews/dfff746353781cf0fe8adbc886ff2dfd65e66d37/algorithms/math/__init__.py -------------------------------------------------------------------------------- /algorithms/math/factorial.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://en.wikipedia.org/wiki/Factorial 4 | 5 | 0! = 1 6 | 1! = 1 7 | n! = n * (n - 1) * (n - 2) * (n - 3) * ... * 3 * 2 * 1 8 | """ 9 | 10 | 11 | def factorial(n): 12 | if not isinstance(n, int) or n < 0: 13 | raise ValueError('n is invalid') 14 | 15 | # Base case 16 | if n <= 1: 17 | return 1 18 | 19 | # Recursive case 20 | return n * factorial(n - 1) 21 | 22 | 23 | def factorial_for_loop(n): 24 | ans = 1 25 | for i in range(1, n + 1): 26 | ans = ans * i 27 | return ans 28 | -------------------------------------------------------------------------------- /algorithms/math/fibonacci.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://en.wikipedia.org/wiki/Fibonacci_number 4 | 5 | fib(0) = 0 6 | fib(1) = 1 7 | fib(n) = fib(n-1) + fib(n-2) 8 | """ 9 | 10 | 11 | def fib(n): 12 | if not isinstance(n, int) or n < 0: 13 | raise ValueError('n is invalid') 14 | 15 | # Base case 16 | if n <= 1: 17 | return n 18 | 19 | # Recursive case 20 | return fib(n - 1) + fib(n - 2) 21 | 22 | 23 | def fib_for_loop(n): 24 | seq = [0, 1] 25 | for i in range(2, n + 1): 26 | num = seq[i - 1] + seq[i - 2] 27 | seq.append(num) 28 | 29 | return seq[n] 30 | -------------------------------------------------------------------------------- /algorithms/math/tests/test_fibonacci.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from algorithms.math.fibonacci import fib 5 | from algorithms.math.fibonacci import fib_for_loop 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def test(self): 10 | with self.assertRaises(ValueError): 11 | fib(-1) 12 | 13 | with self.assertRaises(ValueError): 14 | fib(0.5) 15 | 16 | with self.assertRaises(ValueError): 17 | fib('abc') 18 | 19 | self.assertEqual(fib(0), 0) 20 | self.assertEqual(fib(1), 1) 21 | self.assertEqual(fib(2), 1) 22 | self.assertEqual(fib(3), 2) 23 | self.assertEqual(fib(4), 3) 24 | self.assertEqual(fib(5), 5) 25 | self.assertEqual(fib(6), 8) 26 | self.assertEqual(fib(7), 13) 27 | self.assertEqual(fib(8), 21) 28 | self.assertEqual(fib(9), 34) 29 | self.assertEqual(fib(10), 55) 30 | 31 | 32 | class TestCase2(unittest.TestCase): 33 | def test(self): 34 | self.assertEqual(fib_for_loop(0), 0) 35 | self.assertEqual(fib_for_loop(1), 1) 36 | self.assertEqual(fib_for_loop(2), 1) 37 | self.assertEqual(fib_for_loop(3), 2) 38 | self.assertEqual(fib_for_loop(4), 3) 39 | self.assertEqual(fib_for_loop(5), 5) 40 | self.assertEqual(fib_for_loop(6), 8) 41 | self.assertEqual(fib_for_loop(7), 13) 42 | self.assertEqual(fib_for_loop(8), 21) 43 | self.assertEqual(fib_for_loop(9), 34) 44 | self.assertEqual(fib_for_loop(10), 55) 45 | 46 | self.assertEqual(fib_for_loop(100), 354224848179261915075) 47 | 48 | 49 | if __name__ == '__main__': 50 | unittest.main() 51 | -------------------------------------------------------------------------------- /algorithms/searching/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinta/fuck-coding-interviews/dfff746353781cf0fe8adbc886ff2dfd65e66d37/algorithms/searching/__init__.py -------------------------------------------------------------------------------- /algorithms/searching/linear_search.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | Linear Search 4 | https://en.wikipedia.org/wiki/Linear_search 5 | 6 | Worst-case performance: O(n) 7 | Best-case performance: O(1) 8 | Average performance: O(n) 9 | """ 10 | 11 | 12 | def linear_search(array, target): 13 | for i, item in enumerate(array): 14 | if item == target: 15 | return i 16 | 17 | return -1 18 | -------------------------------------------------------------------------------- /algorithms/searching/tests/test_linear_search.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import random 3 | import unittest 4 | 5 | from algorithms.searching.linear_search import linear_search 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def test(self): 10 | array = [random.randint(-100, 100) for i in range(10000)] 11 | target = random.choice(array) 12 | expected = array.index(target) 13 | self.assertEqual(linear_search(array, target), expected) 14 | 15 | def test2(self): 16 | array = [random.randint(-100, 100) for i in range(10000)] 17 | target = 999 18 | expected = -1 19 | self.assertEqual(linear_search(array, target), expected) 20 | 21 | def test3(self): 22 | array = [] 23 | target = 0 24 | expected = -1 25 | self.assertEqual(linear_search(array, target), expected) 26 | 27 | 28 | if __name__ == '__main__': 29 | unittest.main() 30 | -------------------------------------------------------------------------------- /algorithms/sorting/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinta/fuck-coding-interviews/dfff746353781cf0fe8adbc886ff2dfd65e66d37/algorithms/sorting/__init__.py -------------------------------------------------------------------------------- /algorithms/sorting/bubble_sort.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | Bubble Sort 4 | https://en.wikipedia.org/wiki/Bubble_sort 5 | 6 | Worst-case performance: O(n^2) 7 | Best-case performance: O(n) (the input array is already sorted) 8 | Average performance: O(n^2) 9 | """ 10 | 11 | 12 | def bubble_sort(arr): 13 | length = len(arr) 14 | 15 | swapped = True 16 | while swapped: 17 | swapped = False 18 | 19 | # We check i and i + 1 in each loop, 20 | # so we only need length - 1 loops to cover all items 21 | for i in range(0, length - 1): 22 | if arr[i] > arr[i + 1]: 23 | arr[i], arr[i + 1] = arr[i + 1], arr[i] 24 | swapped = True 25 | 26 | # We sort one item in each iteration, 27 | # so the length of remaining unsorted items is reduced by 1 28 | length = length - 1 29 | 30 | return arr 31 | -------------------------------------------------------------------------------- /algorithms/sorting/counting_sort.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | Counting Sort 4 | https://en.wikipedia.org/wiki/Counting_sort 5 | 6 | Worst-case performance: О(n) 7 | Best-case performance: О(n) 8 | Average performance: О(n) 9 | """ 10 | 11 | 12 | # NOTE: This implementation can only sort an array which contains only non-negative integers. 13 | def counting_sort(arr, max_num_in_array=None): 14 | if not arr: 15 | return arr 16 | 17 | if max_num_in_array is None: 18 | max_num_in_array = max(arr) 19 | 20 | counts = [0, ] * (max_num_in_array + 1) 21 | for num in arr: 22 | counts[num] += 1 23 | 24 | i = 0 25 | for num, count in enumerate(counts): 26 | for _ in range(count): 27 | arr[i] = num 28 | i += 1 29 | 30 | return arr 31 | -------------------------------------------------------------------------------- /algorithms/sorting/insertion_sort.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | Insertion Sort 4 | https://en.wikipedia.org/wiki/Insertion_sort 5 | 6 | Worst-case performance: О(n^2) 7 | Best-case performance: O(n) 8 | Average performance: О(n^2) 9 | """ 10 | 11 | 12 | def insertion_sort(arr): 13 | # Assume that arr[0] is already sorted, so start from arr[1] 14 | for i in range(1, len(arr)): 15 | # Iterate "the sorted part" backward, and find the correct position for arr[i] 16 | while (i > 0) and (arr[i] < arr[i - 1]): 17 | # If we use for loop above, we will have to run `i` steps for every unsorted element 18 | # However, arr[i] > arr[i - 1] means arr[i] is already in the right position 19 | # No need to check remaining elements of the sorted part 20 | arr[i], arr[i - 1] = arr[i - 1], arr[i] 21 | i = i - 1 22 | 23 | return arr 24 | -------------------------------------------------------------------------------- /algorithms/sorting/mergesort.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | Merge Sort 4 | https://en.wikipedia.org/wiki/mergesort 5 | 6 | Worst-case performance: O(n * log n) 7 | Best-case performance: O(n * log n) 8 | Average performance: O(n * log n) 9 | """ 10 | 11 | 12 | # We could replace this function with `heapq.merge()`. 13 | def merge(sorted_arr1, sorted_arr2): 14 | sorted_arr = [] 15 | i1 = 0 16 | i2 = 0 17 | while True: 18 | # Since there is no item to process in `sorted_arr1`, 19 | # we simply merge the remainder of `sorted_arr2` into the result. 20 | try: 21 | current1 = sorted_arr1[i1] 22 | except IndexError: 23 | sorted_arr.extend(sorted_arr2[i2:]) # NOTE: Only merge the remainder. 24 | break 25 | 26 | try: 27 | current2 = sorted_arr2[i2] 28 | except IndexError: 29 | sorted_arr.extend(sorted_arr1[i1:]) 30 | break 31 | 32 | if current1 <= current2: 33 | sorted_arr.append(current1) 34 | i1 += 1 35 | else: 36 | sorted_arr.append(current2) 37 | i2 += 1 38 | 39 | return sorted_arr 40 | 41 | 42 | def mergesort(arr): 43 | # Base case: 44 | # The list is considered sorted if it's empty or there is only one item. 45 | if len(arr) <= 1: 46 | return arr 47 | 48 | # Recursive case: 49 | # Divide the list in half, sort both sublists recursively, then merge two sorted lists. 50 | middle_index = len(arr) // 2 51 | sorted_left_list = mergesort(arr[:middle_index]) 52 | sorted_right_list = mergesort(arr[middle_index:]) 53 | return merge(sorted_left_list, sorted_right_list) 54 | -------------------------------------------------------------------------------- /algorithms/sorting/selection_sort.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | Selection Sort 4 | https://en.wikipedia.org/wiki/Selection_sort 5 | 6 | Worst-case performance: О(n^2) 7 | Best-case performance: О(n^2) 8 | Average performance: О(n^2) 9 | """ 10 | 11 | 12 | # Select the smallest item each round. 13 | def selection_sort(arr): 14 | sorted_arr = [] 15 | 16 | def find_min_index(arr): 17 | if not arr: 18 | raise ValueError('array is empty') 19 | 20 | min_index = 0 21 | for i, item in enumerate(arr): 22 | if item <= arr[min_index]: 23 | min_index = i 24 | return min_index 25 | 26 | # The length of arr is reduced by 1 every loop because of arr.pop() 27 | for _ in range(len(arr)): 28 | # Find the smallest item in the unsorted list, 29 | index = find_min_index(arr) 30 | # Move it to the sorted list 31 | sorted_arr.append(arr.pop(index)) 32 | 33 | return sorted_arr 34 | 35 | 36 | def selection_sort_in_place(arr): 37 | length = len(arr) 38 | for i in range(length - 1): 39 | # Find the smallest item in the unsorted sublist 40 | min_index = i 41 | for j in range(i + 1, length): 42 | if arr[j] < arr[min_index]: 43 | min_index = j 44 | 45 | # Swap the smallest item with the leftmost item of the unsorted sublist 46 | if min_index != i: 47 | # arr[i] belongs to the sorted sublist 48 | arr[i], arr[min_index] = arr[min_index], arr[i] 49 | 50 | return arr 51 | -------------------------------------------------------------------------------- /algorithms/sorting/tests/benchmark_quicksort.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import random 3 | 4 | import pytest 5 | 6 | from algorithms.sorting.quicksort import quicksort 7 | from algorithms.sorting.quicksort import quicksort_in_place 8 | 9 | 10 | array = [random.randint(-100, 100) for i in range(1000)] 11 | expected = sorted(array.copy()) 12 | 13 | 14 | @pytest.mark.benchmark(group='quicksort', disable_gc=True, warmup=False) 15 | def test_benchmark_quicksort(benchmark): 16 | assert benchmark(quicksort, array.copy()) == expected 17 | 18 | 19 | @pytest.mark.benchmark(group='quicksort', disable_gc=True, warmup=False) 20 | def test_benchmark_quicksort_in_place(benchmark): 21 | assert benchmark(quicksort_in_place, array.copy()) == expected 22 | -------------------------------------------------------------------------------- /algorithms/sorting/tests/test_bubble_sort.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import random 3 | import unittest 4 | 5 | from algorithms.sorting.bubble_sort import bubble_sort 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def test(self): 10 | test_lists = [ 11 | [5, 7, 1, 9, 5, 5, -4, 3, 0, 2], 12 | [], 13 | [1, ], 14 | [1, 2], 15 | [1, 2, 3], 16 | [3, 2, 1], 17 | [1, 2, 3, 4], 18 | [4, 3, 2, 1], 19 | [1, 1, 1, 1], 20 | [-2, 3, -5], 21 | [-1, 2, -8, -10], 22 | [random.randint(-100, 100) for i in range(1000)], 23 | ] 24 | for array in test_lists: 25 | with self.subTest(array=array): 26 | self.assertEqual(bubble_sort(array.copy()), sorted(array)) 27 | 28 | 29 | if __name__ == '__main__': 30 | unittest.main() 31 | -------------------------------------------------------------------------------- /algorithms/sorting/tests/test_counting_sort.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import random 3 | import unittest 4 | 5 | from algorithms.sorting.counting_sort import counting_sort 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def test(self): 10 | test_lists = [ 11 | [5, 7, 1, 9, 5, 5, 3, 0, 2, 3, 6, 3, 8], 12 | [], 13 | [1, ], 14 | [1, 2], 15 | [1, 2, 3], 16 | [3, 2, 1], 17 | [1, 2, 3, 4], 18 | [4, 3, 2, 1], 19 | [1, 1, 1, 1], 20 | [random.randint(0, 100) for i in range(1000)], 21 | ] 22 | for array in test_lists: 23 | with self.subTest(array=array): 24 | self.assertEqual(counting_sort(array.copy()), sorted(array)) 25 | 26 | 27 | if __name__ == '__main__': 28 | unittest.main() 29 | -------------------------------------------------------------------------------- /algorithms/sorting/tests/test_heapsort.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import random 3 | import unittest 4 | 5 | from algorithms.sorting.heapsort import heapsort 6 | from algorithms.sorting.heapsort import heap_sort_heapq 7 | 8 | 9 | class TestCase(unittest.TestCase): 10 | def test(self): 11 | test_lists = [ 12 | [5, 7, 1, 9, 5, 5, -4, 3, 0, 2], 13 | [], 14 | [1, ], 15 | [1, 2], 16 | [1, 2, 3], 17 | [3, 2, 1], 18 | [1, 2, 3, 4], 19 | [4, 3, 2, 1], 20 | [1, 1, 1, 1], 21 | [-2, 3, -5], 22 | [-1, 2, -8, -10], 23 | [random.randint(-100, 100) for i in range(1000)], 24 | ] 25 | for array in test_lists: 26 | with self.subTest(array=array): 27 | self.assertEqual(heapsort(array.copy()), sorted(array)) 28 | 29 | 30 | class TestCase2(unittest.TestCase): 31 | def test(self): 32 | test_lists = [ 33 | [5, 7, 1, 9, 5, 5, -4, 3, 0, 2], 34 | [], 35 | [1, ], 36 | [1, 2], 37 | [1, 2, 3], 38 | [3, 2, 1], 39 | [1, 2, 3, 4], 40 | [4, 3, 2, 1], 41 | [1, 1, 1, 1], 42 | [-2, 3, -5], 43 | [-1, 2, -8, -10], 44 | [random.randint(-100, 100) for i in range(1000)], 45 | ] 46 | for array in test_lists: 47 | with self.subTest(array=array): 48 | self.assertEqual(heap_sort_heapq(array.copy()), sorted(array)) 49 | 50 | 51 | if __name__ == '__main__': 52 | unittest.main() 53 | -------------------------------------------------------------------------------- /algorithms/sorting/tests/test_insertion_sort.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import random 3 | import unittest 4 | 5 | from algorithms.sorting.insertion_sort import insertion_sort 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def test(self): 10 | test_lists = [ 11 | [5, 7, 1, 9, 5, 5, -4, 3, 0, 2], 12 | [], 13 | [1, ], 14 | [1, 2], 15 | [1, 2, 3], 16 | [3, 2, 1], 17 | [1, 2, 3, 4], 18 | [4, 3, 2, 1], 19 | [1, 1, 1, 1], 20 | [-2, 3, -5], 21 | [-1, 2, -8, -10], 22 | [random.randint(-100, 100) for i in range(1000)], 23 | ] 24 | for array in test_lists: 25 | with self.subTest(array=array): 26 | self.assertEqual(insertion_sort(array.copy()), sorted(array)) 27 | 28 | 29 | if __name__ == '__main__': 30 | unittest.main() 31 | -------------------------------------------------------------------------------- /algorithms/sorting/tests/test_mergesort.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import random 3 | import unittest 4 | 5 | from algorithms.sorting.mergesort import mergesort 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def test(self): 10 | test_lists = [ 11 | [5, 7, 1, 9, 5, 5, -4, 3, 0, 2], 12 | [], 13 | [1, ], 14 | [1, 2], 15 | [1, 2, 3], 16 | [3, 2, 1], 17 | [1, 2, 3, 4], 18 | [4, 3, 2, 1], 19 | [1, 1, 1, 1], 20 | [-2, 3, -5], 21 | [-1, 2, -8, -10], 22 | [random.randint(-100, 100) for i in range(1000)], 23 | ] 24 | for array in test_lists: 25 | with self.subTest(array=array): 26 | self.assertEqual(mergesort(array.copy()), sorted(array)) 27 | 28 | 29 | if __name__ == '__main__': 30 | unittest.main() 31 | -------------------------------------------------------------------------------- /algorithms/sorting/tests/test_quicksort.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import random 3 | import unittest 4 | 5 | from algorithms.sorting.quicksort import quicksort 6 | from algorithms.sorting.quicksort import quicksort_in_place 7 | 8 | 9 | class TestCase(unittest.TestCase): 10 | def test(self): 11 | test_lists = [ 12 | [5, 7, 1, 9, 5, 5, -4, 3, 0, 2], 13 | [], 14 | [1, ], 15 | [1, 2], 16 | [1, 2, 3], 17 | [3, 2, 1], 18 | [1, 2, 3, 4], 19 | [4, 3, 2, 1], 20 | [1, 1, 1, 1], 21 | [-2, 3, -5], 22 | [-1, 2, -8, -10], 23 | [random.randint(-100, 100) for i in range(1000)], 24 | ] 25 | for array in test_lists: 26 | with self.subTest(array=array): 27 | self.assertEqual(quicksort(array.copy()), sorted(array)) 28 | 29 | 30 | class TestCase2(unittest.TestCase): 31 | def test(self): 32 | test_lists = [ 33 | [5, 7, 1, 9, 5, 5, -4, 3, 0, 2], 34 | [], 35 | [1, ], 36 | [1, 2], 37 | [1, 2, 3], 38 | [3, 2, 1], 39 | [1, 2, 3, 4], 40 | [4, 3, 2, 1], 41 | [1, 1, 1, 1], 42 | [-2, 3, -5], 43 | [-1, 2, -8, -10], 44 | [random.randint(-100, 100) for i in range(1000)], 45 | ] 46 | for array in test_lists: 47 | with self.subTest(array=array): 48 | self.assertEqual(quicksort_in_place(array.copy()), sorted(array)) 49 | 50 | 51 | if __name__ == '__main__': 52 | unittest.main() 53 | -------------------------------------------------------------------------------- /algorithms/sorting/tests/test_selection_sort.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import random 3 | import unittest 4 | 5 | 6 | from algorithms.sorting.selection_sort import selection_sort 7 | from algorithms.sorting.selection_sort import selection_sort_in_place 8 | 9 | 10 | class TestCase(unittest.TestCase): 11 | def test(self): 12 | test_lists = [ 13 | [5, 7, 1, 9, 5, 5, -4, 3, 0, 2], 14 | [], 15 | [1, ], 16 | [1, 2], 17 | [1, 2, 3], 18 | [3, 2, 1], 19 | [1, 2, 3, 4], 20 | [4, 3, 2, 1], 21 | [1, 1, 1, 1], 22 | [-2, 3, -5], 23 | [-1, 2, -8, -10], 24 | [random.randint(-100, 100) for i in range(1000)], 25 | ] 26 | for array in test_lists: 27 | with self.subTest(array=array): 28 | self.assertEqual(selection_sort(array.copy()), sorted(array)) 29 | 30 | 31 | class TestCase2(unittest.TestCase): 32 | def test(self): 33 | test_lists = [ 34 | [5, 7, 1, 9, 5, 5, -4, 3, 0, 2], 35 | [], 36 | [1, ], 37 | [1, 2], 38 | [1, 2, 3], 39 | [3, 2, 1], 40 | [1, 2, 3, 4], 41 | [4, 3, 2, 1], 42 | [1, 1, 1, 1], 43 | [-2, 3, -5], 44 | [-1, 2, -8, -10], 45 | [random.randint(-100, 100) for i in range(1000)], 46 | ] 47 | for array in test_lists: 48 | with self.subTest(array=array): 49 | self.assertEqual(selection_sort_in_place(array.copy()), sorted(array)) 50 | 51 | 52 | if __name__ == '__main__': 53 | unittest.main() 54 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: 5 | target: auto 6 | threshold: 50% 7 | patch: no 8 | -------------------------------------------------------------------------------- /data_structures/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinta/fuck-coding-interviews/dfff746353781cf0fe8adbc886ff2dfd65e66d37/data_structures/__init__.py -------------------------------------------------------------------------------- /data_structures/arrays/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinta/fuck-coding-interviews/dfff746353781cf0fe8adbc886ff2dfd65e66d37/data_structures/arrays/__init__.py -------------------------------------------------------------------------------- /data_structures/b_trees/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinta/fuck-coding-interviews/dfff746353781cf0fe8adbc886ff2dfd65e66d37/data_structures/b_trees/__init__.py -------------------------------------------------------------------------------- /data_structures/graphs/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinta/fuck-coding-interviews/dfff746353781cf0fe8adbc886ff2dfd65e66d37/data_structures/graphs/__init__.py -------------------------------------------------------------------------------- /data_structures/hash_maps/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinta/fuck-coding-interviews/dfff746353781cf0fe8adbc886ff2dfd65e66d37/data_structures/hash_maps/__init__.py -------------------------------------------------------------------------------- /data_structures/hash_maps/base_map.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from abc import abstractmethod 3 | from collections.abc import MutableMapping 4 | 5 | from algorithms.hashing.mad_compression import mad 6 | 7 | 8 | class Item: 9 | def __init__(self, key, value): 10 | self.key = key 11 | self.value = value 12 | 13 | 14 | class BaseMap(MutableMapping): 15 | ITEM_CLASS = Item 16 | 17 | @abstractmethod 18 | def __init__(self): 19 | ... 20 | 21 | @abstractmethod 22 | def __len__(self): 23 | ... 24 | 25 | @abstractmethod 26 | def __iter__(self): 27 | ... 28 | 29 | @abstractmethod 30 | def __setitem__(self, key, value): 31 | ... 32 | 33 | @abstractmethod 34 | def __getitem__(self, key): 35 | ... 36 | 37 | @abstractmethod 38 | def __delitem__(self, key): 39 | ... 40 | 41 | 42 | class BaseHashMap(BaseMap): 43 | def __init__(self, capacity=None, lf_threshold=None): 44 | # Setting capacity to a prime number can slightly reduce collision. 45 | self._bucket_array = [None, ] * (capacity if capacity else 11) 46 | self._size = 0 47 | self._load_factor_threshold = lf_threshold if lf_threshold else 0.5 48 | 49 | # O(1) 50 | def __len__(self): 51 | return self._size 52 | 53 | # O(1) 54 | def _hash_func(self, key): 55 | return mad(hash(key), len(self._bucket_array)) 56 | 57 | # O(1) 58 | def _load_factor(self): 59 | return self._size / len(self._bucket_array) 60 | 61 | # O(n) 62 | def _resize(self, new_capacity): 63 | old_items = list(self.items()) 64 | self._bucket_array = [None, ] * new_capacity 65 | self._size = 0 66 | for key, value in old_items: 67 | # __setitem__() will re-hash items and re-calculate _size 68 | # according to the new capacity of the bucket array. 69 | self[key] = value 70 | 71 | def _auto_resize(self): 72 | if self._load_factor() > self._load_factor_threshold: 73 | self._resize(len(self._bucket_array) * 2 - 1) 74 | -------------------------------------------------------------------------------- /data_structures/hash_maps/unsorted_table_map.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from data_structures.hash_maps.base_map import BaseMap 3 | 4 | 5 | class UnsortedTableMap(BaseMap): 6 | def __init__(self): 7 | self._table = [] 8 | 9 | # O(1) 10 | def __len__(self): 11 | return len(self._table) 12 | 13 | # O(n) 14 | def __iter__(self): 15 | for item in self._table: 16 | yield item.key 17 | 18 | # O(n) 19 | def __setitem__(self, key, value): 20 | for item in self._table: 21 | if key == item.key: 22 | item.value = value 23 | return 24 | 25 | self._table.append(self.ITEM_CLASS(key, value)) 26 | 27 | # O(n) 28 | def __getitem__(self, key): 29 | for item in self._table: 30 | if item.key == key: 31 | return item.value 32 | 33 | raise KeyError 34 | 35 | # O(n) 36 | def __delitem__(self, key): 37 | for i, item in enumerate(self._table): 38 | if item.key == key: 39 | self._table.pop(i) 40 | return 41 | 42 | raise KeyError 43 | -------------------------------------------------------------------------------- /data_structures/heaps/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinta/fuck-coding-interviews/dfff746353781cf0fe8adbc886ff2dfd65e66d37/data_structures/heaps/__init__.py -------------------------------------------------------------------------------- /data_structures/heaps/tests/test_array_based_binary_heap.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import heapq 3 | import random 4 | import unittest 5 | 6 | from data_structures.heaps.array_based_binary_heap import ArrayBasedBinaryHeap 7 | 8 | 9 | class TestCase(unittest.TestCase): 10 | def setUp(self): 11 | self.empty_heap = ArrayBasedBinaryHeap() 12 | self.heap = ArrayBasedBinaryHeap() 13 | self.heapq_heap = [] 14 | 15 | self.values = [random.randint(-100, 100) for _ in range(random.randint(1, 100))] 16 | for value in self.values: 17 | self.heap.push(value) 18 | heapq.heappush(self.heapq_heap, value) 19 | 20 | def test__len__(self): 21 | self.assertEqual(len(self.empty_heap), 0) 22 | self.assertEqual(len(self.heap), len(self.values)) 23 | 24 | def test__iter__(self): 25 | self.assertEqual(list(self.empty_heap), []) 26 | self.assertEqual(list(self.heap), sorted(self.values)) 27 | 28 | def test_push(self): 29 | self.empty_heap.push(42) 30 | self.assertEqual(len(self.empty_heap), 1) 31 | self.assertEqual(self.empty_heap.pop_min(), 42) 32 | self.assertEqual(len(self.empty_heap), 0) 33 | 34 | def test_pop_min(self): 35 | for _ in range(len(self.values)): 36 | self.assertEqual(self.heap.pop_min(), heapq.heappop(self.heapq_heap)) 37 | 38 | self.assertEqual(len(self.heap), 0) 39 | 40 | def test_peek_min(self): 41 | with self.assertRaises(ValueError): 42 | self.empty_heap.peek_min() 43 | 44 | self.assertEqual(self.heap.peek_min(), self.heapq_heap[0]) 45 | 46 | 47 | if __name__ == '__main__': 48 | unittest.main() 49 | -------------------------------------------------------------------------------- /data_structures/linked_lists/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinta/fuck-coding-interviews/dfff746353781cf0fe8adbc886ff2dfd65e66d37/data_structures/linked_lists/__init__.py -------------------------------------------------------------------------------- /data_structures/queues/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinta/fuck-coding-interviews/dfff746353781cf0fe8adbc886ff2dfd65e66d37/data_structures/queues/__init__.py -------------------------------------------------------------------------------- /data_structures/queues/array_based_queue.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | class ArrayBasedQueue: 3 | def __init__(self): 4 | self.array = [] 5 | 6 | def __len__(self): 7 | return len(self.array) 8 | 9 | def __iter__(self): 10 | for item in self.array: 11 | yield item 12 | 13 | # O(1) 14 | def enqueue(self, value): 15 | self.array.append(value) 16 | 17 | # O(n) 18 | def dequeue(self): 19 | try: 20 | return self.array.pop(0) 21 | except IndexError: 22 | raise ValueError('queue is empty') 23 | -------------------------------------------------------------------------------- /data_structures/queues/heap_based_priority_queue.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from data_structures.heaps.array_based_binary_heap import ArrayBasedBinaryHeap 3 | 4 | 5 | class HeapBasedPriorityQueue: 6 | def __init__(self): 7 | self.heap = ArrayBasedBinaryHeap() 8 | 9 | def __len__(self): 10 | return len(self.heap) 11 | 12 | def __iter__(self): 13 | return self.heap.__iter__() 14 | 15 | def enqueue(self, value): 16 | self.heap.push(value) 17 | 18 | def dequeue(self): 19 | try: 20 | return self.heap.pop_min() 21 | except ValueError: 22 | raise ValueError('queue is empty') 23 | -------------------------------------------------------------------------------- /data_structures/queues/linked_list_based_queue.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | class ListNode: 3 | def __init__(self, value, next=None): 4 | self.value = value 5 | self.next = next 6 | 7 | 8 | # Also see: https://github.com/vinta/fuck-coding-interviews/blob/master/data_structures/linked_lists/singly_linked_list.py 9 | # This implementation is more simplified, however, with specific modifications 10 | class LinkedList: 11 | def __init__(self, head=None, tail=None): 12 | self.head = None 13 | self.tail = None 14 | self.size = 0 15 | 16 | def __len__(self): 17 | return self.size 18 | 19 | def __iter__(self): 20 | node = self.head 21 | while node: 22 | yield node.value 23 | node = node.next 24 | 25 | def append(self, value): 26 | self.size += 1 27 | new_node = ListNode(value) 28 | 29 | if not self.head: 30 | self.head = new_node 31 | self.tail = new_node 32 | return 33 | 34 | self.tail.next = new_node 35 | self.tail = new_node 36 | 37 | def pop_left(self): 38 | if not self.head: 39 | raise IndexError 40 | 41 | self.size -= 1 42 | deleted_value = self.head.value 43 | self.head = self.head.next 44 | if not self.head: 45 | self.tail = None 46 | 47 | return deleted_value 48 | 49 | 50 | class LinkedListBasedQueue: 51 | def __init__(self): 52 | self.linked_list = LinkedList() 53 | 54 | # O(1) 55 | def __len__(self): 56 | return len(self.linked_list) 57 | 58 | # O(n) 59 | def __iter__(self): 60 | return self.linked_list.__iter__() 61 | 62 | # O(1) 63 | def enqueue(self, value): 64 | self.linked_list.append(value) 65 | 66 | # O(1) 67 | def dequeue(self): 68 | try: 69 | return self.linked_list.pop_left() 70 | except IndexError: 71 | raise ValueError('queue is empty') 72 | -------------------------------------------------------------------------------- /data_structures/queues/tests/test_array_based_queue.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from data_structures.queues.array_based_queue import ArrayBasedQueue 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def setUp(self): 9 | self.queue = ArrayBasedQueue() 10 | 11 | def test_enqueue(self): 12 | self.queue.enqueue(0) 13 | self.queue.enqueue(1) 14 | self.queue.enqueue(2) 15 | self.assertEqual(len(self.queue), 3) 16 | self.assertEqual(list(self.queue), [0, 1, 2]) 17 | 18 | def test_dequeue(self): 19 | with self.assertRaises(ValueError): 20 | print(self.queue.dequeue()) 21 | 22 | self.queue.enqueue(0) 23 | self.queue.enqueue(1) 24 | self.queue.enqueue(2) 25 | self.assertEqual(self.queue.dequeue(), 0) 26 | self.assertEqual(self.queue.dequeue(), 1) 27 | self.assertEqual(self.queue.dequeue(), 2) 28 | self.assertEqual(len(self.queue), 0) 29 | self.assertEqual(list(self.queue), []) 30 | 31 | with self.assertRaises(ValueError): 32 | print(self.queue.dequeue()) 33 | 34 | 35 | if __name__ == '__main__': 36 | unittest.main() 37 | -------------------------------------------------------------------------------- /data_structures/queues/tests/test_circular_array_based_queue.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | 5 | from data_structures.queues.circular_array_based_queue import CircularArrayBasedQueue 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def setUp(self): 10 | self.queue = CircularArrayBasedQueue(capacity=4) 11 | 12 | def test_enqueue(self): 13 | self.queue.enqueue(0) 14 | self.queue.enqueue(1) 15 | self.queue.enqueue(2) 16 | self.queue.enqueue(3) 17 | self.queue.enqueue(4) 18 | self.assertEqual(len(self.queue), 5) 19 | self.assertEqual(list(self.queue), [0, 1, 2, 3, 4]) 20 | 21 | def test_dequeue(self): 22 | with self.assertRaises(ValueError): 23 | print(self.queue.dequeue()) 24 | 25 | self.queue.enqueue(0) 26 | self.queue.enqueue(1) 27 | self.queue.enqueue(2) 28 | self.assertEqual(self.queue.dequeue(), 0) 29 | self.assertEqual(self.queue.dequeue(), 1) 30 | self.queue.enqueue(3) 31 | self.queue.enqueue(4) 32 | self.queue.enqueue(5) 33 | self.assertEqual(self.queue.dequeue(), 2) 34 | self.assertEqual(len(self.queue), 3) 35 | self.assertEqual(list(self.queue), [3, 4, 5]) 36 | self.assertEqual(self.queue.dequeue(), 3) 37 | self.assertEqual(self.queue.dequeue(), 4) 38 | self.assertEqual(self.queue.dequeue(), 5) 39 | self.assertEqual(len(self.queue), 0) 40 | self.assertEqual(list(self.queue), []) 41 | 42 | with self.assertRaises(ValueError): 43 | print(self.queue.dequeue()) 44 | 45 | 46 | if __name__ == '__main__': 47 | unittest.main() 48 | -------------------------------------------------------------------------------- /data_structures/queues/tests/test_heap_based_priority_queue.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from data_structures.queues.heap_based_priority_queue import HeapBasedPriorityQueue 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def setUp(self): 9 | self.queue = HeapBasedPriorityQueue() 10 | 11 | def test_enqueue(self): 12 | self.queue.enqueue(1) 13 | self.queue.enqueue(0) 14 | self.queue.enqueue(2) 15 | self.assertEqual(len(self.queue), 3) 16 | self.assertEqual(list(self.queue), [0, 1, 2]) 17 | 18 | def test_dequeue(self): 19 | with self.assertRaises(ValueError): 20 | self.queue.dequeue() 21 | 22 | self.queue.enqueue(1) 23 | self.queue.enqueue(0) 24 | self.queue.enqueue(2) 25 | self.assertEqual(self.queue.dequeue(), 0) 26 | self.assertEqual(self.queue.dequeue(), 1) 27 | self.assertEqual(self.queue.dequeue(), 2) 28 | self.assertEqual(len(self.queue), 0) 29 | self.assertEqual(list(self.queue), []) 30 | 31 | with self.assertRaises(ValueError): 32 | self.queue.dequeue() 33 | 34 | 35 | if __name__ == '__main__': 36 | unittest.main() 37 | -------------------------------------------------------------------------------- /data_structures/queues/tests/test_linked_list_based_queue.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from data_structures.queues.linked_list_based_queue import LinkedListBasedQueue 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def setUp(self): 9 | self.queue = LinkedListBasedQueue() 10 | 11 | def test_enqueue(self): 12 | self.queue.enqueue(0) 13 | self.queue.enqueue(1) 14 | self.queue.enqueue(2) 15 | self.assertEqual(self.queue.linked_list.head.value, 0) 16 | self.assertEqual(self.queue.linked_list.tail.value, 2) 17 | self.assertEqual(len(self.queue), 3) 18 | self.assertEqual(list(self.queue), [0, 1, 2]) 19 | 20 | def test_dequeue(self): 21 | with self.assertRaises(ValueError): 22 | print(self.queue.dequeue()) 23 | 24 | self.queue.enqueue(0) 25 | self.queue.enqueue(1) 26 | self.queue.enqueue(2) 27 | self.assertEqual(self.queue.dequeue(), 0) 28 | self.assertEqual(self.queue.linked_list.head.value, 1) 29 | self.assertEqual(self.queue.linked_list.tail.value, 2) 30 | self.assertEqual(self.queue.dequeue(), 1) 31 | self.assertEqual(self.queue.linked_list.head.value, 2) 32 | self.assertEqual(self.queue.linked_list.tail.value, 2) 33 | self.assertEqual(self.queue.dequeue(), 2) 34 | self.assertEqual(self.queue.linked_list.head, None) 35 | self.assertEqual(self.queue.linked_list.tail, None) 36 | self.assertEqual(len(self.queue), 0) 37 | self.assertEqual(list(self.queue), []) 38 | 39 | with self.assertRaises(ValueError): 40 | print(self.queue.dequeue()) 41 | 42 | 43 | if __name__ == '__main__': 44 | unittest.main() 45 | -------------------------------------------------------------------------------- /data_structures/sets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinta/fuck-coding-interviews/dfff746353781cf0fe8adbc886ff2dfd65e66d37/data_structures/sets/__init__.py -------------------------------------------------------------------------------- /data_structures/sets/hash_map_based_multiset.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | Multiset 4 | https://en.wikipedia.org/wiki/Multiset 5 | 6 | A multiset (also known as a bag) is a set which allows duplicates, and keeps track of how many times each elements appear. 7 | 8 | Actually, a multiset is more like a hash map which keys are elements and values are counts of each elements. 9 | """ 10 | from collections import defaultdict 11 | 12 | 13 | class Multiset: 14 | def __init__(self, iterable=()): 15 | self.dict = defaultdict(int) 16 | self.size = 0 17 | for elem in iterable: 18 | self.add(elem) 19 | 20 | def __len__(self): 21 | return self.size 22 | 23 | def __contains__(self, elem): 24 | return elem in self.dict 25 | 26 | def __iter__(self): 27 | for elem, count in self.dict.items(): 28 | for _ in range(count): 29 | yield elem 30 | 31 | def add(self, elem): 32 | self.dict[elem] += 1 33 | self.size += 1 34 | 35 | def discard(self, elem): 36 | count = self.dict[elem] 37 | if count > 0: 38 | self.dict[elem] -= 1 39 | self.size -= 1 40 | 41 | if count <= 0: 42 | del self.dict[elem] 43 | 44 | def discard_all(self, elem): 45 | count = self.dict[elem] 46 | self.size = self.size - count 47 | del self.dict[elem] 48 | 49 | def num_unique_elements(self): 50 | return len(self.dict) 51 | -------------------------------------------------------------------------------- /data_structures/sets/quick_find_union_find.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | Union-Find (Disjoint Set) 4 | https://en.wikipedia.org/wiki/Disjoint-set_data_structure 5 | """ 6 | 7 | 8 | class QuickFindUnionFind: 9 | def __init__(self, union_pairs=()): 10 | self.num_groups = 0 11 | self.auto_increment_id = 1 12 | self.element_groups = { 13 | # element: group_id, 14 | } 15 | 16 | for p, q in union_pairs: 17 | self.union(p, q) 18 | 19 | def __len__(self): 20 | return self.num_groups 21 | 22 | # O(1) 23 | def make_group(self, element): 24 | # Initially, every element is in its own group which contains only itself. 25 | group_id = self.element_groups.get(element) 26 | if group_id is None: 27 | # Group id could be arbitrary as long as each group has an unique one. 28 | group_id = self.auto_increment_id 29 | self.element_groups[element] = group_id 30 | self.num_groups += 1 31 | self.auto_increment_id += 1 32 | 33 | return group_id 34 | 35 | # O(1) 36 | def find(self, p): 37 | try: 38 | return self.element_groups[p] 39 | except KeyError: 40 | # We implicitly create a new group for the new element `p`. 41 | return self.make_group(p) 42 | 43 | # O(n) 44 | def union(self, p, q): 45 | p_group_id = self.find(p) 46 | q_group_id = self.find(q) 47 | if p_group_id != q_group_id: 48 | for element, group_id in self.element_groups.items(): 49 | # Merge p into q. 50 | if group_id == p_group_id: 51 | self.element_groups[element] = q_group_id 52 | self.num_groups -= 1 53 | 54 | # O(1) 55 | def is_connected(self, p, q): 56 | return self.find(p) == self.find(q) 57 | -------------------------------------------------------------------------------- /data_structures/sets/tests/test_hash_map_based_multiset.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from collections import Counter 3 | import unittest 4 | 5 | from data_structures.sets.hash_map_based_multiset import Multiset 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def setUp(self): 10 | self.empty_multiset = Multiset() 11 | 12 | self.elements = [1, 5, 1, -8, 2, 3, 3, 1, 9] 13 | self.multiset = Multiset(self.elements) 14 | self.counter = Counter(self.elements) 15 | 16 | def test__len__(self): 17 | self.assertEqual(len(self.empty_multiset), 0) 18 | self.assertEqual(len(self.multiset), sum(self.counter.values())) 19 | 20 | def test__iter__(self): 21 | self.assertEqual(list(self.empty_multiset), []) 22 | self.assertCountEqual(list(self.multiset), self.counter.elements()) 23 | 24 | def test__contains__(self): 25 | self.assertEqual(1 in self.multiset, True) 26 | self.assertEqual(2 in self.multiset, True) 27 | self.assertEqual(0 in self.multiset, False) 28 | self.assertEqual(4 in self.multiset, False) 29 | 30 | def test_add(self): 31 | self.multiset.add(1) 32 | self.counter.update({1: 1}) 33 | self.multiset.add(100) 34 | self.counter.update({100: 1}) 35 | self.assertEqual(len(self.multiset), sum(self.counter.values())) 36 | self.assertCountEqual(list(self.multiset), self.counter.elements()) 37 | 38 | def test_discard(self): 39 | self.multiset.discard(1) 40 | self.counter.update({1: -1}) 41 | self.assertEqual(len(self.multiset), sum(self.counter.values())) 42 | self.assertCountEqual(list(self.multiset), self.counter.elements()) 43 | 44 | def test_num_unique_elements(self): 45 | self.assertEqual(self.multiset.num_unique_elements(), len(self.counter)) 46 | 47 | 48 | if __name__ == '__main__': 49 | unittest.main() 50 | -------------------------------------------------------------------------------- /data_structures/sets/weighted_quick_union_union_find.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://learning.oreilly.com/library/view/Data+Structures+and+Algorithms+in+Python/9781118290279/19_chap14.html#ch014-sec051 4 | """ 5 | 6 | 7 | class Node: 8 | def __init__(self, element): 9 | self.element = element 10 | self.parent = self # NOTE: We treat the node instance as the node id. 11 | self.size = 1 12 | 13 | def __len__(self): 14 | return self.size 15 | 16 | 17 | # There is another implementation: 18 | # https://github.com/vinta/fuck-coding-interviews/blob/master/problems/kruskal_mst_really_special_subtree.py 19 | class WeightedQuickUnionUnionFind: 20 | def __init__(self, union_pairs=()): 21 | self.num_groups = 0 22 | self.element_groups = { 23 | # element: node_instance 24 | } 25 | 26 | for p, q in union_pairs: 27 | self.union(p, q) 28 | 29 | def __len__(self): 30 | return self.num_groups 31 | 32 | def make_group(self, element): 33 | node = self.element_groups.get(element) 34 | if node is None: 35 | node = Node(element) 36 | self.element_groups[element] = node 37 | self.num_groups += 1 38 | 39 | return node 40 | 41 | def find(self, p): 42 | try: 43 | node = self.element_groups[p] 44 | except KeyError: 45 | node = self.make_group(p) 46 | else: 47 | while node.parent != node: 48 | node = node.parent 49 | 50 | return node.parent 51 | 52 | def union(self, p, q): 53 | p_group = self.find(p) 54 | q_group = self.find(q) 55 | if len(p_group) < len(q_group): 56 | # Merge p into q. 57 | p_group.parent = q_group.parent 58 | q_group.size += p_group.size 59 | else: 60 | # Merge q into p. 61 | q_group.parent = p_group.parent 62 | p_group.size += q_group.size 63 | self.num_groups -= 1 64 | 65 | def is_connected(self, p, q): 66 | return self.find(p) == self.find(q) 67 | -------------------------------------------------------------------------------- /data_structures/stacks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinta/fuck-coding-interviews/dfff746353781cf0fe8adbc886ff2dfd65e66d37/data_structures/stacks/__init__.py -------------------------------------------------------------------------------- /data_structures/stacks/array_based_stack.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | class ArrayBasedStack: 3 | def __init__(self): 4 | self.array = [] 5 | 6 | def __len__(self): 7 | return len(self.array) 8 | 9 | def __iter__(self): 10 | for item in reversed(self.array): 11 | yield item 12 | 13 | # O(1) 14 | def push(self, value): 15 | self.array.append(value) 16 | 17 | # O(1) 18 | def pop(self): 19 | try: 20 | return self.array.pop() 21 | except IndexError: 22 | raise ValueError('stack is empty') 23 | 24 | # O(1) 25 | def peek(self): 26 | try: 27 | return self.array[-1] 28 | except IndexError: 29 | raise ValueError('stack is empty') 30 | -------------------------------------------------------------------------------- /data_structures/stacks/tests/test_array_based_stack.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from data_structures.stacks.array_based_stack import ArrayBasedStack 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def setUp(self): 9 | self.stack = ArrayBasedStack() 10 | 11 | def test_push(self): 12 | self.stack.push(0) 13 | self.stack.push(1) 14 | self.stack.push(2) 15 | self.assertEqual(len(self.stack), 3) 16 | self.assertEqual(list(self.stack), [2, 1, 0]) 17 | 18 | def test_pop(self): 19 | with self.assertRaises(ValueError): 20 | print(self.stack.pop()) 21 | 22 | self.stack.push(0) 23 | self.stack.push(1) 24 | self.stack.push(2) 25 | self.assertEqual(self.stack.pop(), 2) 26 | self.assertEqual(self.stack.pop(), 1) 27 | self.assertEqual(self.stack.pop(), 0) 28 | self.assertEqual(len(self.stack), 0) 29 | self.assertEqual(list(self.stack), []) 30 | 31 | with self.assertRaises(ValueError): 32 | print(self.stack.pop()) 33 | 34 | def test_peek(self): 35 | with self.assertRaises(ValueError): 36 | print(self.stack.peek()) 37 | 38 | self.stack.push(0) 39 | self.stack.push(1) 40 | self.stack.push(2) 41 | self.assertEqual(self.stack.peek(), 2) 42 | 43 | 44 | if __name__ == '__main__': 45 | unittest.main() 46 | -------------------------------------------------------------------------------- /data_structures/stacks/tests/test_linked_list_based_stack.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from data_structures.stacks.linked_list_based_stack import LinkedListBasedStack 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def setUp(self): 9 | self.stack = LinkedListBasedStack() 10 | 11 | def test__len__(self): 12 | self.assertEqual(len(self.stack), 0) 13 | 14 | self.stack.push(0) 15 | self.assertEqual(len(self.stack), 1) 16 | 17 | def test_push(self): 18 | self.stack.push(0) 19 | self.stack.push(1) 20 | self.stack.push(2) 21 | self.assertEqual(len(self.stack), 3) 22 | self.assertEqual(list(self.stack), [2, 1, 0]) 23 | 24 | def test_pop(self): 25 | with self.assertRaises(ValueError): 26 | print(self.stack.pop()) 27 | 28 | self.stack.push(0) 29 | self.stack.push(1) 30 | self.stack.push(2) 31 | self.assertEqual(self.stack.pop(), 2) 32 | self.assertEqual(self.stack.pop(), 1) 33 | self.assertEqual(self.stack.pop(), 0) 34 | self.assertEqual(len(self.stack), 0) 35 | self.assertEqual(list(self.stack), []) 36 | 37 | with self.assertRaises(ValueError): 38 | print(self.stack.pop()) 39 | 40 | def test_peek(self): 41 | with self.assertRaises(ValueError): 42 | print(self.stack.peek()) 43 | 44 | self.stack.push(0) 45 | self.stack.push(1) 46 | self.stack.push(2) 47 | self.assertEqual(self.stack.peek(), 2) 48 | 49 | 50 | if __name__ == '__main__': 51 | unittest.main() 52 | -------------------------------------------------------------------------------- /data_structures/trees/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinta/fuck-coding-interviews/dfff746353781cf0fe8adbc886ff2dfd65e66d37/data_structures/trees/__init__.py -------------------------------------------------------------------------------- /data_structures/trees/tests/test_treap.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import random 3 | import unittest 4 | 5 | from data_structures.trees.treap import Treap 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def setUp(self): 10 | self.empty_treap = Treap() 11 | self.treap = Treap() 12 | 13 | k = random.randint(10, 100) 14 | self.values = random.sample(range(-1000, 1000), k) 15 | for value in self.values: 16 | self.treap.insert(value) 17 | 18 | def test__len__(self): 19 | self.assertEqual(len(self.empty_treap), 0) 20 | self.assertEqual(len(self.treap), len(self.values)) 21 | 22 | def test__iter__(self): 23 | self.assertEqual(list(self.empty_treap), []) 24 | self.assertEqual(list(self.treap), sorted(self.values)) 25 | 26 | def test_search(self): 27 | value = random.choice(self.values) 28 | node = self.treap.search(value) 29 | self.assertEqual(node.value, value) 30 | 31 | self.assertEqual(self.empty_treap.search(99999), None) 32 | 33 | def test_insert(self): 34 | self.empty_treap.insert(99999) 35 | self.assertEqual(self.empty_treap.root.value, 99999) 36 | 37 | def test_delete(self): 38 | for value in random.sample(self.values, len(self.values)): 39 | self.treap.delete(value) 40 | 41 | self.assertEqual(len(self.treap), 0) 42 | 43 | with self.assertRaises(ValueError): 44 | self.treap.delete(99999) 45 | 46 | def test_check_validation(self): 47 | priorities = [] 48 | for node in self.treap.levelorder_traverse_nodes(): 49 | node.check_validation() 50 | priorities.append(node.priority) 51 | 52 | min_priority = min(priorities) 53 | self.assertEqual(self.treap.root.priority, min_priority) 54 | 55 | 56 | if __name__ == '__main__': 57 | unittest.main() 58 | -------------------------------------------------------------------------------- /data_structures/trees/tests/test_trie.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from data_structures.trees.trie import Trie 5 | 6 | 7 | class TrieNodeTest(unittest.TestCase): 8 | def setUp(self): 9 | self.trie = Trie() 10 | 11 | def test__len__(self): 12 | self.assertEqual(len(self.trie), 0) 13 | 14 | def test_insert(self): 15 | with self.assertRaises(ValueError): 16 | self.trie.insert('') 17 | 18 | def test_search(self): 19 | self.assertEqual(self.trie.search(''), False) 20 | 21 | def test_startsWith(self): 22 | self.assertEqual(self.trie.startsWith(''), True) 23 | 24 | def test_integration(self): 25 | self.trie.insert('apple') 26 | self.assertEqual(len(self.trie), 1) 27 | self.assertEqual(self.trie.search('apple'), True) 28 | self.assertEqual(self.trie.search('app'), False) 29 | self.assertEqual(self.trie.startsWith('app'), True) 30 | 31 | self.trie.insert('app') 32 | self.assertEqual(len(self.trie), 2) 33 | self.assertEqual(self.trie.search('app'), True) 34 | self.assertEqual(self.trie.startsWith('app'), True) 35 | 36 | self.trie.insert('hammer') 37 | self.assertEqual(len(self.trie), 3) 38 | self.assertEqual(self.trie.search('hammers'), False) 39 | self.assertEqual(self.trie.startsWith('hammers'), False) 40 | 41 | 42 | if __name__ == '__main__': 43 | unittest.main() 44 | -------------------------------------------------------------------------------- /data_structures/trees/trie.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | Trie 4 | https://en.wikipedia.org/wiki/Trie 5 | """ 6 | 7 | 8 | class Trie: 9 | def __init__(self): 10 | self.root = {} 11 | self.size = 0 12 | 13 | def __len__(self): 14 | return self.size 15 | 16 | def insert(self, word: str) -> None: 17 | if not word: 18 | raise ValueError('word cannot be empty') 19 | 20 | node = self.root 21 | for char in word: 22 | node = node.setdefault(char, {}) 23 | 24 | # Since the searched word might be shorter than the word in Trie, 25 | # search() needs a way to determine whether the searching matches the exact word, 26 | # For instance, we have `hammer`in Trie and we are searching for `hammers` which should return False. 27 | node['$word_end'] = True 28 | self.size += 1 29 | 30 | def search(self, word: str) -> bool: 31 | node = self.root 32 | for char in word: 33 | try: 34 | node = node[char] 35 | except KeyError: 36 | return False 37 | 38 | if '$word_end' in node: 39 | return True 40 | else: 41 | return False 42 | 43 | def startsWith(self, prefix: str) -> bool: 44 | node = self.root 45 | for char in prefix: 46 | try: 47 | node = node[char] 48 | except KeyError: 49 | return False 50 | 51 | return True 52 | -------------------------------------------------------------------------------- /problems/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinta/fuck-coding-interviews/dfff746353781cf0fe8adbc886ff2dfd65e66d37/problems/__init__.py -------------------------------------------------------------------------------- /problems/add_two_numbers.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/add-two-numbers/ 4 | """ 5 | 6 | 7 | class ListNode: # pragma: no cover 8 | def __init__(self, val=0, next=None): 9 | self.val = val 10 | self.next = next 11 | 12 | 13 | class Solution: 14 | def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode: 15 | result_node = ListNode() 16 | dummy_head_result_node = result_node 17 | 18 | carry = 0 19 | while l1 or l2: 20 | # the length of `l1` and `l2` might be different 21 | if l1: 22 | value1 = l1.val 23 | next1 = l1.next 24 | else: 25 | value1 = 0 26 | next1 = None 27 | if l2: 28 | value2 = l2.val 29 | next2 = l2.next 30 | else: 31 | value2 = 0 32 | next2 = None 33 | 34 | val = value1 + value2 + carry 35 | if val >= 10: 36 | val = val - 10 37 | carry = 1 38 | else: 39 | carry = 0 40 | 41 | # in the first loop, `result_node` is currently `dummy_head_result_node` 42 | next_result_node = ListNode(val) 43 | result_node.next = next_result_node 44 | 45 | # prepare for the next loop 46 | result_node = next_result_node 47 | l1 = next1 48 | l2 = next2 49 | 50 | if carry >= 1: 51 | result_node.next = ListNode(carry) 52 | 53 | return dummy_head_result_node.next 54 | -------------------------------------------------------------------------------- /problems/array_intersection.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://algodaily.com/challenges/array-intersection/ 3 | """ 4 | 5 | 6 | def intersection(nums1, nums2): 7 | return list(set(nums1) & set(nums2)) 8 | -------------------------------------------------------------------------------- /problems/array_sum.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://www.hackerearth.com/practice/basic-programming/implementation/basics-of-implementation/practice-problems/algorithm/array-sum-2-725368ac/description/ 4 | """ 5 | 6 | 7 | def run_solution(): 8 | lines = [] 9 | while True: 10 | try: 11 | line = input() 12 | except EOFError: 13 | break 14 | else: 15 | lines.append(line) 16 | 17 | numbers = [int(num_str) for num_str in lines[1].split()] 18 | print(sum(numbers)) 19 | -------------------------------------------------------------------------------- /problems/balanced_binary_tree.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/balanced-binary-tree/ 4 | """ 5 | 6 | 7 | class TreeNode: # pragma: no cover 8 | def __init__(self, val=0, left=None, right=None): 9 | self.val = val 10 | self.left = left 11 | self.right = right 12 | 13 | 14 | class Solution: 15 | def isBalanced(self, root: TreeNode) -> bool: 16 | tree = {'is_balanced': True} 17 | 18 | def height(node): 19 | if not node or not tree['is_balanced']: 20 | return 0 21 | 22 | left_h = height(node.left) 23 | right_h = height(node.right) 24 | if abs(left_h - right_h) > 1: 25 | tree['is_balanced'] = False 26 | 27 | return 1 + max(left_h, right_h) 28 | 29 | height(root) 30 | return tree['is_balanced'] 31 | -------------------------------------------------------------------------------- /problems/best_time_to_buy_and_sell_stock.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/best-time-to-buy-and-sell-stock/ 4 | """ 5 | from typing import List 6 | 7 | 8 | class Solution: 9 | def maxProfit(self, prices: List[int]) -> int: 10 | max_profit = 0 11 | for day, buy_price in enumerate(prices): 12 | for sell_price in prices[day + 1:]: 13 | profit = sell_price - buy_price 14 | if profit > max_profit: 15 | max_profit = profit 16 | return max_profit 17 | 18 | 19 | # The Two-Pointer way. 20 | class Solution2: 21 | def maxProfit(self, prices: List[int]) -> int: 22 | max_profit = 0 23 | length = len(prices) 24 | buy = 0 25 | sell = 1 26 | while buy < length and sell < length: 27 | if prices[sell] > prices[buy]: 28 | # sell price is higher than buy price 29 | profit = prices[sell] - prices[buy] 30 | if profit > max_profit: 31 | max_profit = profit 32 | 33 | sell += 1 34 | else: 35 | # sell price is lower than or equeal to buy price 36 | buy = sell 37 | sell += 1 38 | 39 | return max_profit 40 | 41 | 42 | class Solution3: 43 | def maxProfit(self, prices: List[int]) -> int: 44 | if len(prices) <= 1: 45 | return 0 46 | 47 | max_profit = 0 48 | buy_price = prices[0] 49 | for sell_price in prices[1:]: 50 | if sell_price > buy_price: 51 | profit = sell_price - buy_price 52 | if profit > max_profit: 53 | max_profit = profit 54 | else: 55 | buy_price = sell_price 56 | 57 | return max_profit 58 | -------------------------------------------------------------------------------- /problems/bfs_shortest_path_in_a_graph.py: -------------------------------------------------------------------------------- 1 | #!/bin/python3 2 | """ 3 | https://www.hackerrank.com/challenges/ctci-bfs-shortest-reach/problem 4 | """ 5 | from collections import defaultdict 6 | from collections import deque 7 | 8 | 9 | class Graph: 10 | def __init__(self, num_nodes): 11 | self.num_nodes = num_nodes 12 | self.outgoing_edges = defaultdict(dict) 13 | 14 | def connect(self, u, v): 15 | self.outgoing_edges[u][v] = 6 16 | self.outgoing_edges[v][u] = 6 17 | 18 | def find_all_distances(self, s): 19 | distances = {} 20 | for n in range(self.num_nodes): 21 | distances[n] = float('inf') 22 | distances[s] = 0 23 | 24 | visited = set([s, ]) 25 | queue = deque([s, ]) 26 | while queue: 27 | n = queue.popleft() 28 | for des, weight in self.outgoing_edges[n].items(): 29 | if des not in visited: 30 | visited.add(des) 31 | distance_to_des = distances[n] + weight 32 | if distance_to_des < distances[des]: 33 | distances[des] = distance_to_des 34 | queue.append(des) 35 | 36 | def output(): 37 | for n in range(self.num_nodes): 38 | if n != s: 39 | distance = distances[n] 40 | yield '-1' if distance == float('inf') else str(distance) 41 | 42 | print(' '.join(output())) 43 | 44 | 45 | t = int(input()) # There are t graphs. 46 | for _ in range(t): 47 | n, m = [int(value) for value in input().split()] 48 | graph = Graph(n) # There are n nodes. 49 | for _ in range(m): # There are m undirected edges. 50 | x, y = [int(x) for x in input().split()] 51 | graph.connect(x - 1, y - 1) 52 | 53 | s = int(input()) # Find shortest paths from vertex s. 54 | graph.find_all_distances(s - 1) 55 | -------------------------------------------------------------------------------- /problems/big_countries.sql: -------------------------------------------------------------------------------- 1 | -- https://leetcode.com/problems/big-countries/ 2 | 3 | SELECT name, population, area 4 | FROM World 5 | WHERE 6 | area > 3000000 OR 7 | population > 25000000; 8 | -------------------------------------------------------------------------------- /problems/binary_search_tree_iterator.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/binary-search-tree-iterator/ 4 | """ 5 | import itertools 6 | 7 | 8 | class TreeNode: # pragma: no cover 9 | def __init__(self, val=0, left=None, right=None): 10 | self.val = val 11 | self.left = left 12 | self.right = right 13 | 14 | 15 | class BSTIterator: 16 | def __init__(self, root: TreeNode): 17 | def inorder_traverse(node): 18 | if not node: 19 | return 20 | 21 | yield from inorder_traverse(node.left) 22 | yield node.val 23 | yield from inorder_traverse(node.right) 24 | 25 | self.generator = inorder_traverse(root) 26 | 27 | def next(self) -> int: 28 | """ 29 | @return the next smallest number 30 | """ 31 | try: 32 | return next(self.generator) 33 | except StopIteration: 34 | return 35 | 36 | def hasNext(self) -> bool: 37 | """ 38 | @return whether we have a next smallest number 39 | """ 40 | used_generator, checked_generator = itertools.tee(self.generator) 41 | self.generator = used_generator 42 | try: 43 | next(checked_generator) 44 | except StopIteration: 45 | return False 46 | 47 | return True 48 | 49 | 50 | # Your BSTIterator object will be instantiated and called as such: 51 | # obj = BSTIterator(root) 52 | # param_1 = obj.next() 53 | # param_2 = obj.hasNext() 54 | -------------------------------------------------------------------------------- /problems/binary_tree_inorder_traversal.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/binary-tree-inorder-traversal/ 4 | """ 5 | from typing import List 6 | 7 | 8 | class TreeNode: # pragma: no cover 9 | def __init__(self, val=0, left=None, right=None): 10 | self.val = val 11 | self.left = left 12 | self.right = right 13 | 14 | 15 | class Solution: 16 | def inorderTraversal(self, root: TreeNode) -> List[int]: 17 | def inorder_traverse(node): 18 | if not node: 19 | return 20 | 21 | yield from inorder_traverse(node.left) 22 | yield node.val 23 | yield from inorder_traverse(node.right) 24 | 25 | return inorder_traverse(root) 26 | -------------------------------------------------------------------------------- /problems/binary_tree_level_order_traversal.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/binary-tree-level-order-traversal/ 4 | """ 5 | from typing import List 6 | 7 | 8 | class TreeNode: # pragma: no cover 9 | def __init__(self, val=0, left=None, right=None): 10 | self.val = val 11 | self.left = left 12 | self.right = right 13 | 14 | 15 | class Solution: 16 | def levelOrder(self, root: TreeNode) -> List[List[int]]: 17 | current_level = [root, ] 18 | output = [] 19 | while current_level: 20 | level = [] 21 | next_level = [] 22 | for node in current_level: 23 | if node: 24 | level.append(node.val) 25 | next_level.extend([node.left, node.right]) 26 | 27 | if level: 28 | output.append(level) 29 | 30 | current_level = next_level 31 | 32 | return output 33 | -------------------------------------------------------------------------------- /problems/binary_tree_maximum_path_sum.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/binary-tree-maximum-path-sum/ 4 | """ 5 | 6 | 7 | class TreeNode: # pragma: no cover 8 | def __init__(self, val=0, left=None, right=None): 9 | self.val = val 10 | self.left = left 11 | self.right = right 12 | 13 | 14 | class Solution: 15 | # The meaning of "path" in this problem: 16 | # https://leetcode.com/problems/binary-tree-maximum-path-sum/discuss/39811/What-is-the-meaning-of-path-in-this-problem 17 | def maxPathSum(self, root: TreeNode) -> int: 18 | self.max_sum = float('-inf') 19 | 20 | def max_path_sum(node): 21 | if not node: 22 | return 0 23 | 24 | val = node.val 25 | 26 | # If the branch's sum is negative, ignore it. 27 | left_sum = max(max_path_sum(node.left), 0) 28 | right_sum = max(max_path_sum(node.right), 0) 29 | 30 | # Check whether this is the possible root node. 31 | current_sum = max(val, val + left_sum + right_sum) 32 | if current_sum > self.max_sum: 33 | self.max_sum = current_sum 34 | 35 | # You can only choose 1 branch, go left or go right. 36 | return max(val + left_sum, val + right_sum) 37 | 38 | max_path_sum(root) 39 | 40 | return self.max_sum 41 | -------------------------------------------------------------------------------- /problems/binary_tree_postorder_traversal.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/binary-tree-postorder-traversal/ 4 | """ 5 | from typing import List 6 | 7 | 8 | class TreeNode: # pragma: no cover 9 | def __init__(self, val=0, left=None, right=None): 10 | self.val = val 11 | self.left = left 12 | self.right = right 13 | 14 | 15 | class Solution: 16 | def postorderTraversal(self, root: TreeNode) -> List[int]: 17 | def postorder_traverse(node): 18 | if not node: 19 | return 20 | 21 | yield from postorder_traverse(node.left) 22 | yield from postorder_traverse(node.right) 23 | yield node.val 24 | 25 | return postorder_traverse(root) 26 | -------------------------------------------------------------------------------- /problems/binary_tree_preorder_traversal.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/binary-tree-preorder-traversal/ 4 | """ 5 | from typing import List 6 | 7 | 8 | class TreeNode: # pragma: no cover 9 | def __init__(self, val=0, left=None, right=None): 10 | self.val = val 11 | self.left = left 12 | self.right = right 13 | 14 | 15 | class Solution: 16 | def preorderTraversal(self, root: TreeNode) -> List[int]: 17 | def preorder_traverse(node): 18 | if not node: 19 | return 20 | 21 | yield node.val 22 | yield from preorder_traverse(node.left) 23 | yield from preorder_traverse(node.right) 24 | 25 | return preorder_traverse(root) 26 | -------------------------------------------------------------------------------- /problems/camel_case.py: -------------------------------------------------------------------------------- 1 | #!/bin/python3 2 | """ 3 | https://www.hackerrank.com/challenges/camelcase/problem 4 | """ 5 | import os 6 | 7 | 8 | def camelcase(s): 9 | word_count = 0 10 | for char in s: 11 | if char.isupper(): 12 | word_count += 1 13 | 14 | if s and s[0].islower(): 15 | word_count += 1 16 | 17 | return word_count 18 | 19 | 20 | if __name__ == '__main__': 21 | fptr = open(os.environ['OUTPUT_PATH'], 'w') 22 | s = input() 23 | result = camelcase(s) 24 | fptr.write(str(result) + '\n') 25 | fptr.close() 26 | -------------------------------------------------------------------------------- /problems/check_completeness_of_a_binary_tree.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/check-completeness-of-a-binary-tree/ 4 | """ 5 | from collections import deque 6 | 7 | 8 | class TreeNode: # pragma: no cover 9 | def __init__(self, val=0, left=None, right=None): 10 | self.val = val 11 | self.left = left 12 | self.right = right 13 | 14 | 15 | class Solution: 16 | def isCompleteTree(self, root: TreeNode) -> bool: 17 | queue = deque([root, ]) 18 | has_none = False 19 | while queue: 20 | node = queue.popleft() 21 | if node: 22 | if has_none: 23 | return False 24 | queue.extend([node.left, node.right]) 25 | else: 26 | has_none = True 27 | 28 | return True 29 | -------------------------------------------------------------------------------- /problems/combinations.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/combinations/ 4 | """ 5 | from typing import List 6 | import itertools 7 | 8 | 9 | class Solution: 10 | def combine(self, n: int, k: int) -> List[List[int]]: 11 | nums = range(1, n + 1) 12 | return itertools.combinations(nums, k) 13 | 14 | 15 | class Solution2: 16 | def combine(self, n: int, k: int) -> List[List[int]]: 17 | nums = range(1, n + 1) 18 | results = [] 19 | 20 | def build_results(items, result): 21 | if len(result) == k: 22 | # NOTE: We cannot add `result` directly since it's mutable. 23 | results.append(result[:]) 24 | return 25 | 26 | for i, item in enumerate(items): 27 | result.append(item) 28 | 29 | # It's combinations, so we don't need to consider visited items. 30 | pool_items = items[i + 1:] 31 | build_results(pool_items, result) 32 | 33 | result.pop() 34 | 35 | build_results(nums, []) 36 | return results 37 | -------------------------------------------------------------------------------- /problems/container_with_most_water.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/container-with-most-water/ 4 | """ 5 | from typing import List 6 | 7 | 8 | class Solution: 9 | def maxArea(self, height: List[int]) -> int: 10 | max_area = 0 11 | for i, h1 in enumerate(height): 12 | for w, h2 in enumerate(height[i + 1:], 1): 13 | h = min(h1, h2) 14 | area = w * h 15 | if area > max_area: 16 | max_area = area 17 | 18 | return max_area 19 | 20 | 21 | class Solution2: 22 | def maxArea(self, height: List[int]) -> int: 23 | max_area = 0 24 | 25 | # We use two cursors, one starts from the left, 26 | # another starts from the right 27 | left = 0 28 | right = len(height) - 1 29 | 30 | while left < right: 31 | # The width is fixed in this loop 32 | ww = right - left 33 | 34 | # The valid area is (width, the smaller height) 35 | # Since we already found the valid area for the smaller height, 36 | # the corresponding cursor can move to the next one 37 | if height[left] < height[right]: 38 | hh = height[left] 39 | left = left + 1 40 | else: 41 | hh = height[right] 42 | right = right - 1 43 | 44 | area = ww * hh 45 | max_area = max(max_area, area) 46 | 47 | return max_area 48 | -------------------------------------------------------------------------------- /problems/contains_duplicate.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/contains-duplicate/ 4 | """ 5 | from typing import List 6 | 7 | 8 | class Solution: 9 | def containsDuplicate(self, nums: List[int]) -> bool: 10 | dedup_list = set(nums) 11 | if nums and (len(nums) != len(dedup_list)): 12 | return True 13 | 14 | return False 15 | 16 | 17 | class Solution2: 18 | def containsDuplicate(self, nums: List[int]) -> bool: 19 | dedup_set = set() 20 | for num in nums: 21 | if num in dedup_set: 22 | return True 23 | dedup_set.add(num) 24 | 25 | return False 26 | -------------------------------------------------------------------------------- /problems/counting_valleys.py: -------------------------------------------------------------------------------- 1 | #!/bin/python3 2 | """ 3 | https://www.hackerrank.com/challenges/counting-valleys/problem 4 | """ 5 | import math 6 | import os 7 | import random 8 | import re 9 | import sys 10 | 11 | 12 | def countingValleys(steps, path): 13 | mapping = { 14 | 'U': 1, 15 | 'D': -1, 16 | } 17 | level = 0 18 | velley_count = 0 19 | for walk in path: 20 | level += mapping[walk] 21 | if level == 0 and walk == 'U': 22 | velley_count += 1 23 | 24 | return velley_count 25 | 26 | 27 | if __name__ == '__main__': 28 | fptr = open(os.environ['OUTPUT_PATH'], 'w') 29 | steps = int(input().strip()) 30 | path = input() 31 | result = countingValleys(steps, path) 32 | fptr.write(str(result) + '\n') 33 | fptr.close() 34 | -------------------------------------------------------------------------------- /problems/course_schedule.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/course-schedule/ 4 | """ 5 | from collections import defaultdict 6 | from typing import List 7 | 8 | 9 | class Graph: 10 | def __init__(self): 11 | self.vertices = set() 12 | self.outgoing_edges = defaultdict(dict) 13 | 14 | def add_edge(self, u, v): 15 | self.outgoing_edges[u][v] = 1 16 | self.vertices.add(u) 17 | self.vertices.add(v) 18 | 19 | def has_cycles(self): 20 | global_visited = set() 21 | 22 | def has_cycles_dfs(v, visited): 23 | if v in global_visited: 24 | return False 25 | 26 | global_visited.add(v) 27 | visited.add(v) 28 | for des in self.outgoing_edges[v].keys(): 29 | # If there is any visited vertex in the call stack, the graph has cycles. 30 | if des in visited: 31 | return True 32 | else: 33 | if has_cycles_dfs(des, visited): 34 | return True 35 | visited.remove(v) 36 | return False 37 | 38 | for v in self.vertices: 39 | visited = {v, } 40 | if has_cycles_dfs(v, visited): 41 | return True 42 | return False 43 | 44 | 45 | class Solution: 46 | def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool: 47 | # If there is any cycle in the graph, 48 | # it's impossible to finish all courses. 49 | graph = Graph() 50 | for u, v in prerequisites: 51 | graph.add_edge(v, u) 52 | 53 | return not graph.has_cycles() 54 | -------------------------------------------------------------------------------- /problems/delete_node_in_a_linked_list.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/delete-node-in-a-linked-list/ 4 | """ 5 | 6 | 7 | class ListNode: # pragma: no cover 8 | def __init__(self, x): 9 | self.val = x 10 | self.next = None 11 | 12 | 13 | class Solution: 14 | def deleteNode(self, node): 15 | """ 16 | :type node: ListNode 17 | :rtype: void Do not return anything, modify node in-place instead. 18 | """ 19 | 20 | # It is guaranteed that the node to be deleted is not a tail node in the list. 21 | node.val = node.next.val 22 | node.next = node.next.next 23 | -------------------------------------------------------------------------------- /problems/equality_in_a_array.py: -------------------------------------------------------------------------------- 1 | #!/bin/python3 2 | """ 3 | https://www.hackerrank.com/challenges/equality-in-a-array/problem 4 | """ 5 | from collections import Counter 6 | import math 7 | import os 8 | import random 9 | import re 10 | import sys 11 | 12 | 13 | def equalizeArray(arr): 14 | counter = Counter(arr) 15 | delete_count = 0 16 | for i, data in enumerate(counter.most_common(len(arr))): 17 | if i == 0: 18 | continue 19 | 20 | _, count = data 21 | delete_count += count 22 | 23 | return delete_count 24 | 25 | 26 | if __name__ == '__main__': 27 | fptr = open(os.environ['OUTPUT_PATH'], 'w') 28 | n = int(input()) 29 | arr = list(map(int, input().rstrip().split())) 30 | result = equalizeArray(arr) 31 | fptr.write(str(result) + '\n') 32 | fptr.close() 33 | -------------------------------------------------------------------------------- /problems/fibonacci_number.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/fibonacci-number/ 4 | """ 5 | from functools import lru_cache 6 | 7 | 8 | class Solution: 9 | @lru_cache() 10 | def fib(self, N: int) -> int: 11 | if N <= 1: 12 | return N 13 | 14 | return self.fib(N - 1) + self.fib(N - 2) 15 | 16 | 17 | class Solution2: 18 | caches = {} 19 | 20 | def fib(self, N: int) -> int: 21 | if N <= 1: 22 | return N 23 | 24 | if (N - 1) not in self.caches: 25 | self.caches[N - 1] = self.fib(N - 1) 26 | 27 | if (N - 2) not in self.caches: 28 | self.caches[N - 2] = self.fib(N - 2) 29 | 30 | return self.caches[N - 1] + self.caches[N - 2] 31 | -------------------------------------------------------------------------------- /problems/find_minimum_in_rotated_sorted_array.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/ 4 | """ 5 | from typing import List 6 | import sys 7 | 8 | 9 | class Solution: 10 | def findMin(self, nums: List[int]) -> int: 11 | last_num = -sys.maxsize 12 | for num in nums: 13 | if num < last_num: 14 | return num 15 | else: 16 | last_num = num 17 | 18 | return nums[0] 19 | 20 | 21 | class Solution2: 22 | def findMin(self, nums: List[int]) -> int: 23 | length = len(nums) 24 | if length == 1: 25 | return nums[0] 26 | 27 | low = 0 28 | high = len(nums) - 1 29 | first_value = nums[0] 30 | while low <= high: 31 | # The array is not roated 32 | if nums[low] < nums[high]: 33 | return first_value 34 | 35 | mid = int((low + high) / 2) 36 | mid_value = nums[mid] 37 | 38 | # ex: [3, 4, 5, 1, 2] 39 | if mid_value > nums[mid + 1]: 40 | return nums[mid + 1] 41 | 42 | # ex: [3, 1, 2] 43 | if mid_value < nums[mid - 1]: 44 | return mid_value 45 | 46 | # The left side of the middle is sorted, 47 | # so we should check the right side of the middle 48 | # ex: [1, 2, 4, 5, 6, 7, 0] 49 | if first_value < mid_value: 50 | low = mid + 1 51 | 52 | # The right side of the middle is sorted, 53 | # so we should check the left side of the middle 54 | # ex: [7, 0, 1, 2, 4, 5, 6] 55 | if first_value > mid_value: 56 | high = mid - 1 57 | -------------------------------------------------------------------------------- /problems/find_mode_in_binary_search_tree.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/find-mode-in-binary-search-tree/ 4 | """ 5 | from collections import Counter 6 | from typing import List 7 | 8 | 9 | class TreeNode: # pragma: no cover 10 | def __init__(self, val=0, left=None, right=None): 11 | self.val = val 12 | self.left = left 13 | self.right = right 14 | 15 | 16 | class Solution: 17 | def findMode(self, root: TreeNode) -> List[int]: 18 | def inorder_traverse(node): 19 | if not node: 20 | return 21 | 22 | yield from inorder_traverse(node.left) 23 | yield node.val 24 | yield from inorder_traverse(node.right) 25 | 26 | results = [] 27 | max_count = 0 28 | counter = Counter(val for val in inorder_traverse(root)) 29 | for key, count in counter.most_common(): 30 | # Counter.most_common(1) would return only 1 item 31 | # even if there are more than 1 items which have the same count. 32 | if count >= max_count: 33 | results.append(key) 34 | max_count = count 35 | else: 36 | break 37 | 38 | return results 39 | -------------------------------------------------------------------------------- /problems/find_the_duplicate_number.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/find-the-duplicate-number/ 4 | """ 5 | from typing import List 6 | 7 | 8 | class Solution: 9 | def findDuplicate(self, nums: List[int]) -> int: 10 | n = len(nums) + 1 11 | counts = [0, ] * n 12 | for num in nums: 13 | counts[num] += 1 14 | if counts[num] > 1: 15 | return num 16 | -------------------------------------------------------------------------------- /problems/fizz_buzz.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/fizz-buzz/ 4 | """ 5 | from typing import List 6 | 7 | 8 | class Solution: 9 | def fizzBuzz(self, n: int) -> List[str]: 10 | def gen_fizz_buzz(n): 11 | for num in range(1, n + 1): 12 | if num % 15 == 0: 13 | yield 'FizzBuzz' 14 | elif num % 3 == 0: 15 | yield 'Fizz' 16 | elif num % 5 == 0: 17 | yield 'Buzz' 18 | else: 19 | yield str(num) 20 | 21 | return gen_fizz_buzz(n) 22 | -------------------------------------------------------------------------------- /problems/group_anagrams.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/group-anagrams/ 4 | """ 5 | from collections import defaultdict 6 | from typing import List 7 | 8 | 9 | class Solution: 10 | def groupAnagrams(self, strs: List[str]) -> List[List[str]]: 11 | sorted_words = defaultdict(list) 12 | for word in strs: 13 | sorted_word = str(sorted(word)) 14 | sorted_words[sorted_word].append(word) 15 | 16 | output = [] 17 | for word_list in sorted_words.values(): 18 | output.append(word_list) 19 | 20 | return output 21 | -------------------------------------------------------------------------------- /problems/hackerrank_in_a_string.py: -------------------------------------------------------------------------------- 1 | #!/bin/python3 2 | """ 3 | https://www.hackerrank.com/challenges/hackerrank-in-a-string/problem 4 | """ 5 | from collections import defaultdict 6 | import os 7 | 8 | 9 | def hackerrankInString(s): 10 | target = 'hackerrank' 11 | 12 | char_positions = defaultdict(list) # {char: [position_index_1, position_index_2, ]} 13 | for i, char in enumerate(s): 14 | if char in target: 15 | char_positions[char].append(i) 16 | 17 | last_index = -1 18 | for char in target: 19 | index = None 20 | for i in char_positions[char]: 21 | if i > last_index: 22 | index = i 23 | break 24 | 25 | if index is None: 26 | return 'NO' 27 | else: 28 | last_index = index 29 | 30 | return 'YES' 31 | 32 | 33 | if __name__ == '__main__': 34 | fptr = open(os.environ['OUTPUT_PATH'], 'w') 35 | 36 | q = int(input()) 37 | for _ in range(q): 38 | s = input() 39 | result = hackerrankInString(s) 40 | fptr.write(result + '\n') 41 | 42 | fptr.close() 43 | -------------------------------------------------------------------------------- /problems/hash_tables_ransom_note.py: -------------------------------------------------------------------------------- 1 | #!/bin/python3 2 | """ 3 | https://www.hackerrank.com/challenges/ctci-ransom-note/problem 4 | """ 5 | from collections import Counter 6 | 7 | 8 | def checkMagazine(magazine, note): 9 | m_counter = Counter(magazine) 10 | n_counter = Counter(note) 11 | for word in note: 12 | if m_counter.get(word, 0) < n_counter.get(word, 0): 13 | print('No') 14 | return 15 | 16 | print('Yes') 17 | 18 | 19 | if __name__ == '__main__': 20 | mn = input().split() 21 | m = int(mn[0]) 22 | n = int(mn[1]) 23 | 24 | magazine = input().rstrip().split() 25 | note = input().rstrip().split() 26 | 27 | checkMagazine(magazine, note) 28 | -------------------------------------------------------------------------------- /problems/implement_strstr.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/implement-strstr/ 4 | """ 5 | 6 | 7 | class Solution: 8 | def strStr(self, haystack: str, needle: str) -> int: 9 | if not needle: 10 | return 0 11 | 12 | n_length = len(needle) 13 | for i in range(len(haystack)): 14 | if haystack[i:i + n_length] == needle: 15 | return i 16 | 17 | return -1 18 | 19 | 20 | class Solution2: 21 | def strStr(self, haystack: str, needle: str) -> int: 22 | if not needle: 23 | return 0 24 | 25 | n_length = len(needle) 26 | h_length = len(haystack) 27 | 28 | if h_length < n_length: 29 | return -1 30 | 31 | for i in range(h_length - n_length + 1): 32 | if haystack[i:i + n_length] == needle: 33 | return i 34 | 35 | return -1 36 | -------------------------------------------------------------------------------- /problems/invert_binary_tree.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/invert-binary-tree/ 4 | """ 5 | from collections import deque 6 | 7 | 8 | class TreeNode: # pragma: no cover 9 | def __init__(self, val=0, left=None, right=None): 10 | self.val = val 11 | self.left = left 12 | self.right = right 13 | 14 | 15 | class Solution: 16 | def invertTree(self, root: TreeNode) -> TreeNode: 17 | if not root: 18 | return None 19 | 20 | new_left = self.invertTree(root.right) 21 | new_right = self.invertTree(root.left) 22 | root.left = new_left 23 | root.right = new_right 24 | 25 | return root 26 | 27 | 28 | class Solution2: 29 | def invertTree(self, root: TreeNode) -> TreeNode: 30 | queue = deque([root, ]) 31 | while queue: 32 | node = queue.popleft() 33 | if node: 34 | queue.extend((node.left, node.right)) 35 | node.left, node.right = node.right, node.left 36 | 37 | return root 38 | -------------------------------------------------------------------------------- /problems/is_subsequence.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/is-subsequence/ 4 | """ 5 | 6 | 7 | class Solution: 8 | def isSubsequence(self, s: str, t: str) -> bool: 9 | if not s: 10 | return True 11 | 12 | s_len = len(s) 13 | char_hits = 0 14 | t_start_index = 0 15 | for s_char in s: 16 | for i, t_char in enumerate(t[t_start_index:]): 17 | if s_char == t_char: 18 | char_hits = char_hits + 1 19 | if char_hits == s_len: 20 | return True 21 | 22 | # Found the matching character for `s_char`, so break to the next character of `s` 23 | # Start from the next index instead of t[0] 24 | t_start_index = t_start_index + i + 1 25 | break 26 | 27 | return False 28 | -------------------------------------------------------------------------------- /problems/jumping_on_the_clouds.py: -------------------------------------------------------------------------------- 1 | #!/bin/python3 2 | """ 3 | https://www.hackerrank.com/challenges/jumping-on-the-clouds/problem 4 | """ 5 | import math 6 | import os 7 | import random 8 | import re 9 | import sys 10 | 11 | 12 | def jumpingOnClouds(c): 13 | steps = 0 14 | i = 0 15 | length = len(c) 16 | while i < length - 1: 17 | # We can jump by either 1 or 2 clouds. 18 | if (i + 2) < length: 19 | if c[i + 2] == 0: 20 | steps += 1 21 | i += 2 22 | continue 23 | 24 | steps += 1 25 | i += 1 26 | 27 | return steps 28 | 29 | 30 | if __name__ == '__main__': 31 | fptr = open(os.environ['OUTPUT_PATH'], 'w') 32 | n = int(input()) 33 | c = list(map(int, input().rstrip().split())) 34 | result = jumpingOnClouds(c) 35 | fptr.write(str(result) + '\n') 36 | fptr.close() 37 | -------------------------------------------------------------------------------- /problems/kth_largest_element_in_an_array.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/kth-largest-element-in-an-array/ 4 | """ 5 | from typing import List 6 | import heapq 7 | 8 | 9 | class Solution: 10 | def findKthLargest(self, nums: List[int], k: int) -> int: 11 | sorted_nums = sorted(nums) 12 | return sorted_nums[len(sorted_nums) - k] 13 | 14 | 15 | class Solution2: 16 | def findKthLargest(self, nums: List[int], k: int) -> int: 17 | max_heap = [] 18 | for num in nums: 19 | heapq.heappush(max_heap, -num) 20 | 21 | kth_largest = None 22 | for _ in range(k): 23 | kth_largest = heapq.heappop(max_heap) 24 | return -kth_largest 25 | 26 | 27 | class Solution3: 28 | def findKthLargest(self, nums: List[int], k: int) -> int: 29 | k_largests = heapq.nlargest(k, nums) 30 | return k_largests[-1] 31 | -------------------------------------------------------------------------------- /problems/kth_smallest_element_in_a_bst.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/kth-smallest-element-in-a-bst/ 4 | """ 5 | 6 | 7 | class TreeNode: # pragma: no cover 8 | def __init__(self, val=0, left=None, right=None): 9 | self.val = val 10 | self.left = left 11 | self.right = right 12 | 13 | 14 | class Solution: 15 | def kthSmallest(self, root: TreeNode, k: int) -> int: 16 | def inorder_traverse(node): 17 | if not node: 18 | return 19 | 20 | yield from inorder_traverse(node.left) 21 | yield node.val 22 | yield from inorder_traverse(node.right) 23 | 24 | count = 1 25 | for value in inorder_traverse(root): 26 | if count == k: 27 | return value 28 | 29 | count += 1 30 | -------------------------------------------------------------------------------- /problems/linked_list_cycle.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/linked-list-cycle/ 4 | """ 5 | 6 | 7 | class ListNode: # pragma: no cover 8 | def __init__(self, x): 9 | self.val = x 10 | self.next = None 11 | 12 | 13 | class Solution: 14 | def hasCycle(self, head: ListNode) -> bool: 15 | visted_ids = set() 16 | 17 | node = head 18 | while node: 19 | node_id = id(node) 20 | if node_id in visted_ids: 21 | return True 22 | else: 23 | visted_ids.add(node_id) 24 | 25 | node = node.next 26 | 27 | return False 28 | 29 | 30 | class Solution2: 31 | def hasCycle(self, head: ListNode) -> bool: 32 | if not head: 33 | return False 34 | 35 | slow = head 36 | fast = head 37 | while fast and fast.next: 38 | slow = slow.next 39 | fast = fast.next.next 40 | if slow == fast: 41 | return True 42 | 43 | return False 44 | -------------------------------------------------------------------------------- /problems/mars_exploration.py: -------------------------------------------------------------------------------- 1 | #!/bin/python3 2 | """ 3 | https://www.hackerrank.com/challenges/mars-exploration/problem 4 | """ 5 | import os 6 | 7 | 8 | def marsExploration(s): 9 | count = 0 10 | for i in range(0, len(s), 3): # The length of s will be a multiple of 3. 11 | if s[i] != 'S': 12 | count += 1 13 | if s[i + 1] != 'O': 14 | count += 1 15 | if s[i + 2] != 'S': 16 | count += 1 17 | 18 | return count 19 | 20 | 21 | if __name__ == '__main__': 22 | fptr = open(os.environ['OUTPUT_PATH'], 'w') 23 | s = input() 24 | result = marsExploration(s) 25 | fptr.write(str(result) + '\n') 26 | fptr.close() 27 | -------------------------------------------------------------------------------- /problems/maximum_depth_of_binary_tree.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/maximum-depth-of-binary-tree/ 4 | """ 5 | 6 | 7 | class TreeNode: # pragma: no cover 8 | def __init__(self, val=0, left=None, right=None): 9 | self.val = val 10 | self.left = left 11 | self.right = right 12 | 13 | 14 | class Solution: 15 | def maxDepth(self, root: TreeNode) -> int: 16 | max_depth = 0 17 | current_level = [root, ] 18 | while current_level: 19 | next_level = [] 20 | for node in current_level: 21 | if node: 22 | next_level.extend([node.left, node.right]) 23 | 24 | if next_level: 25 | max_depth += 1 26 | 27 | current_level = next_level 28 | 29 | return max_depth 30 | 31 | 32 | class Solution2: 33 | def maxDepth(self, root: TreeNode) -> int: 34 | # LeetCode's definition: 35 | # The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node. 36 | if not root: 37 | return 0 38 | 39 | return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right)) 40 | -------------------------------------------------------------------------------- /problems/maximum_element.py: -------------------------------------------------------------------------------- 1 | #!/bin/python3 2 | """ 3 | https://www.hackerrank.com/challenges/maximum-element/problem 4 | """ 5 | _ = input() # The total lines. 6 | 7 | stack = [] 8 | track_stack = [] 9 | while True: 10 | try: 11 | line = input().split() 12 | except EOFError: 13 | break 14 | 15 | if line[0] == '1': # Push the element x into the stack. 16 | num = int(line[1]) 17 | stack.append(num) 18 | try: 19 | current_max = track_stack[-1] 20 | except IndexError: 21 | track_stack.append(num) 22 | else: 23 | if num > current_max: 24 | current_max = num 25 | track_stack.append(current_max) 26 | elif line[0] == '2': # Delete the element present at the top of the stack. 27 | stack.pop() 28 | track_stack.pop() 29 | elif line[0] == '3': # Print the maximum element in the stack. 30 | print(track_stack[-1]) 31 | -------------------------------------------------------------------------------- /problems/maximum_product_subarray.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/maximum-product-subarray/ 4 | """ 5 | from typing import List 6 | 7 | 8 | class Solution: 9 | def maxProduct(self, nums: List[int]) -> int: 10 | max_product = nums[0] 11 | 12 | current_product = 1 13 | for num in nums: 14 | current_product = current_product * num 15 | max_product = max(max_product, current_product) 16 | 17 | # when we encounter `0`, the product should be reset 18 | # however, `0` could still be the maximum product if all other numbers are negative 19 | if num == 0: 20 | current_product = 1 21 | 22 | current_product = 1 23 | for num in reversed(nums): 24 | current_product = current_product * num 25 | max_product = max(max_product, current_product, num) 26 | 27 | if num == 0: 28 | current_product = 1 29 | 30 | return max_product 31 | -------------------------------------------------------------------------------- /problems/maximum_subarray.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/maximum-subarray/ 4 | """ 5 | from typing import List 6 | 7 | 8 | class Solution: 9 | def maxSubArray(self, nums: List[int]) -> int: 10 | max_sum = current_sum = nums[0] 11 | for num in nums[1:]: 12 | current_sum = current_sum + num 13 | 14 | # if the current sum is less than the current num 15 | # there is no reason to continue to sum 16 | if current_sum < num: 17 | current_sum = num 18 | 19 | if current_sum > max_sum: 20 | max_sum = current_sum 21 | 22 | return max_sum 23 | -------------------------------------------------------------------------------- /problems/merge_intervals.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/merge-intervals/ 4 | """ 5 | from typing import List 6 | 7 | 8 | class Solution: 9 | def merge(self, intervals: List[List[int]]) -> List[List[int]]: 10 | if len(intervals) <= 1: 11 | return intervals 12 | 13 | intervals.sort(key=lambda x: x[0]) 14 | 15 | first_pair = intervals[0] 16 | output = [first_pair, ] 17 | for pair in intervals[1:]: 18 | last_merged_pair = output[-1] 19 | 20 | # if the current pair's low is greater than the last merged pair's high 21 | # it must be a new interval 22 | if pair[0] > last_merged_pair[1]: 23 | output.append(pair) 24 | continue 25 | 26 | if pair[1] > last_merged_pair[1]: 27 | last_merged_pair[1] = pair[1] 28 | 29 | return output 30 | -------------------------------------------------------------------------------- /problems/merge_k_sorted_lists.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/merge-k-sorted-lists/ 4 | """ 5 | from typing import List 6 | import heapq 7 | 8 | 9 | class ListNode: # pragma: no cover 10 | def __init__(self, val=0, next=None): 11 | self.val = val 12 | self.next = next 13 | 14 | 15 | class Solution: 16 | def mergeKLists(self, lists: List[ListNode]) -> ListNode: 17 | def gen_nodes(node): 18 | while node: 19 | yield node 20 | node = node.next 21 | 22 | linked_lists = [gen_nodes(head) for head in lists] 23 | sorted_nodes = heapq.merge(*linked_lists, key=lambda node: node.val) 24 | dummy_head = last_node = ListNode() 25 | for node in sorted_nodes: 26 | last_node.next = node 27 | last_node = node 28 | 29 | return dummy_head.next 30 | -------------------------------------------------------------------------------- /problems/middle_of_the_linked_list.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/middle-of-the-linked-list/ 4 | """ 5 | 6 | 7 | class ListNode: # pragma: no cover 8 | def __init__(self, val=0, next=None): 9 | self.val = val 10 | self.next = next 11 | 12 | 13 | class Solution: 14 | def middleNode(self, head: ListNode) -> ListNode: 15 | def to_list(node): 16 | arr = [] 17 | while node: 18 | arr.append(node.val) 19 | node = node.next 20 | return arr 21 | 22 | def to_node(arr): 23 | node = dummy_head = ListNode() 24 | for val in arr: 25 | node.next = ListNode(val) 26 | node = node.next 27 | return dummy_head.next 28 | 29 | arr = to_list(head) 30 | middle_index = len(arr) // 2 31 | return to_node(arr[middle_index:]) 32 | 33 | 34 | # The Two-Pointers way. 35 | class Solution2: 36 | def middleNode(self, head: ListNode) -> ListNode: 37 | slow = fast = head 38 | # `slow` traverses one node at a time, and `fast` traverses two nodes at a time. 39 | # When `fast` reaches the end, `slow` would be in the middle. 40 | while fast and fast.next: 41 | slow = slow.next 42 | fast = fast.next.next 43 | return slow 44 | -------------------------------------------------------------------------------- /problems/minimum_depth_of_binary_tree.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/maximum-depth-of-binary-tree/ 4 | """ 5 | from collections import deque 6 | 7 | 8 | class TreeNode: # pragma: no cover 9 | def __init__(self, val=0, left=None, right=None): 10 | self.val = val 11 | self.left = left 12 | self.right = right 13 | 14 | 15 | class Solution: 16 | def minDepth(self, root: TreeNode) -> int: 17 | queue = deque([(root, 1), ]) 18 | while queue: 19 | node, depth = queue.popleft() 20 | if node: 21 | if (not node.left) and (not node.right): # The node is a leaf. 22 | # Since we do level traversal, 23 | # the depth of the first leaf node we found is the minimum depth. 24 | return depth 25 | 26 | if node.left: 27 | queue.append((node.left, depth + 1)) 28 | if node.right: 29 | queue.append((node.right, depth + 1)) 30 | 31 | return 0 32 | -------------------------------------------------------------------------------- /problems/missing_number.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/missing-number/ 4 | """ 5 | from typing import List 6 | 7 | 8 | class Solution: 9 | def missingNumber(self, nums: List[int]) -> int: 10 | n = len(nums) 11 | occurences = [0, ] * (n + 1) 12 | for num in nums: 13 | occurences[num] = 1 14 | 15 | for i, occur in enumerate(occurences): 16 | if occur == 0: 17 | return i 18 | 19 | 20 | class Solution2: 21 | def missingNumber(self, nums: List[int]) -> int: 22 | return sum(range(0, len(nums) + 1)) - sum(nums) 23 | -------------------------------------------------------------------------------- /problems/nth_highest_salary.sql: -------------------------------------------------------------------------------- 1 | -- https://leetcode.com/problems/nth-highest-salary/ 2 | 3 | -- Solution 1 4 | CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT 5 | BEGIN 6 | DECLARE M INT; 7 | SET M = N - 1; 8 | RETURN ( 9 | SELECT DISTINCT Salary 10 | FROM Employee 11 | ORDER BY Salary DESC 12 | LIMIT 1 OFFSET M 13 | ); 14 | END 15 | 16 | -- Solution 2 17 | CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT 18 | BEGIN 19 | DECLARE M INT; 20 | SET M = N - 1; 21 | RETURN ( 22 | SELECT DISTINCT Salary 23 | FROM Employee 24 | ORDER BY Salary DESC 25 | LIMIT M, 1 26 | ); 27 | END 28 | -------------------------------------------------------------------------------- /problems/pangrams.py: -------------------------------------------------------------------------------- 1 | #!/bin/python3 2 | """ 3 | https://www.hackerrank.com/challenges/pangrams/problem 4 | """ 5 | import math 6 | import os 7 | import random 8 | import re 9 | import sys 10 | 11 | 12 | def pangrams(s): 13 | alphabet = set() 14 | for char in s.lower(): 15 | if char != ' ': 16 | alphabet.add(char) 17 | 18 | if len(alphabet) == 26: 19 | return 'pangram' 20 | else: 21 | return 'not pangram' 22 | 23 | 24 | if __name__ == '__main__': 25 | fptr = open(os.environ['OUTPUT_PATH'], 'w') 26 | s = input() 27 | result = pangrams(s) 28 | fptr.write(result + '\n') 29 | fptr.close() 30 | -------------------------------------------------------------------------------- /problems/path_sum.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/path-sum/ 4 | """ 5 | 6 | 7 | class TreeNode: # pragma: no cover 8 | def __init__(self, val=0, left=None, right=None): 9 | self.val = val 10 | self.left = left 11 | self.right = right 12 | 13 | 14 | class Solution: 15 | def hasPathSum(self, root: TreeNode, sum: int) -> bool: 16 | class ReturnTrue(Exception): 17 | pass 18 | 19 | def is_leaf(node): 20 | return not node.left and not node.right 21 | 22 | def inorder_traverse(node, parent_sum=0): 23 | if not node: 24 | return 25 | 26 | node.current_sum = node.val + parent_sum 27 | if is_leaf(node) and node.current_sum == sum: 28 | raise ReturnTrue 29 | 30 | inorder_traverse(node.left, node.current_sum) 31 | node 32 | inorder_traverse(node.right, node.current_sum) 33 | 34 | try: 35 | inorder_traverse(root) 36 | except ReturnTrue: 37 | return True 38 | return False 39 | -------------------------------------------------------------------------------- /problems/permutations.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/permutations/ 4 | """ 5 | from typing import List 6 | import itertools 7 | 8 | 9 | class Solution: 10 | def permute(self, nums: List[int]) -> List[List[int]]: 11 | return itertools.permutations(nums) 12 | 13 | 14 | class Solution2: 15 | def permute(self, nums: List[int]) -> List[List[int]]: 16 | def gen_results(elements): 17 | # Base case 18 | if len(elements) <= 1: 19 | yield elements # elements is a list. 20 | 21 | # Recursive case 22 | else: 23 | for i, first in enumerate(elements): 24 | other_elements = elements[:i] + elements[i + 1:] 25 | for arr in gen_results(other_elements): 26 | yield [first, ] + arr 27 | 28 | return gen_results(nums) 29 | 30 | 31 | class Solution3: 32 | def permute(self, nums: List[int]) -> List[List[int]]: 33 | results = [] 34 | length = len(nums) 35 | 36 | def build_results(items, result): 37 | if len(result) == length: 38 | results.append(result[:]) 39 | return 40 | 41 | for i, item in enumerate(items): 42 | result.append(item) 43 | 44 | pool_items = items[:i] + items[i + 1:] 45 | build_results(pool_items, result) 46 | 47 | result.pop() 48 | 49 | build_results(nums, []) 50 | return results 51 | -------------------------------------------------------------------------------- /problems/power_of_two.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/power-of-two/ 4 | """ 5 | 6 | 7 | class Solution: 8 | def isPowerOfTwo(self, n: int) -> bool: 9 | if n == 0: 10 | return False 11 | 12 | if n == 1: 13 | return True 14 | 15 | while n % 2 == 0: 16 | n = n / 2 17 | if n == 1: 18 | return True 19 | 20 | return False 21 | 22 | 23 | class Solution2: 24 | def isPowerOfTwo(self, n: int) -> bool: 25 | while n > 1: 26 | n = n / 2 27 | return True if n == 1 else False 28 | 29 | 30 | class Solution3: 31 | def isPowerOfTwo(self, n: int) -> bool: 32 | return (n & (n - 1) == 0) and (n != 0) 33 | -------------------------------------------------------------------------------- /problems/prim_mst_special_subtree.py: -------------------------------------------------------------------------------- 1 | #!/bin/python3 2 | """ 3 | https://www.hackerrank.com/challenges/primsmstsub/problem 4 | """ 5 | from collections import defaultdict 6 | import heapq 7 | import os 8 | import sys 9 | 10 | 11 | class UndirectedGraph: 12 | def __init__(self, num_vertices): 13 | self.num_vertices = num_vertices 14 | 15 | def find_minimum_spanning_tree_weight(self, start): 16 | total_weight = 0 17 | num_edges = 0 18 | 19 | min_heap = [(0, start, start), ] # (weight, source, destination) 20 | visited = set() 21 | while min_heap or (num_edges < self.num_vertices - 1): 22 | # The minimum-weight edge which connects to a new vertex. 23 | weight, u, v = heapq.heappop(min_heap) 24 | if v not in visited: 25 | total_weight += weight 26 | num_edges += 1 27 | visited.add(v) 28 | for neighbor, weight in self.outgoing_edges[v].items(): 29 | if neighbor not in visited: 30 | heapq.heappush(min_heap, (weight, v, neighbor)) 31 | 32 | return total_weight 33 | 34 | 35 | def prims(n, edges, start): 36 | graph = UndirectedGraph(n) 37 | graph.outgoing_edges = edges 38 | return graph.find_minimum_spanning_tree_weight(start) 39 | 40 | 41 | if __name__ == '__main__': 42 | fptr = open(os.environ['OUTPUT_PATH'], 'w') 43 | 44 | nm = input().split() 45 | n = int(nm[0]) 46 | m = int(nm[1]) 47 | 48 | edges = defaultdict(dict) 49 | for _ in range(m): 50 | src, des, weight = list(map(int, sys.stdin.readline().split())) 51 | 52 | # Node indexes are 1-based. 53 | src = src - 1 54 | des = des - 1 55 | 56 | # the graph is undirected. 57 | edges[src][des] = weight 58 | edges[des][src] = weight 59 | 60 | start = int(input()) 61 | 62 | result = prims(n, edges, start - 1) 63 | 64 | fptr.write(str(result) + '\n') 65 | fptr.close() 66 | -------------------------------------------------------------------------------- /problems/product_of_array_except_self.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/product-of-array-except-self/ 4 | """ 5 | from typing import List 6 | 7 | 8 | class Solution: 9 | def productExceptSelf(self, nums: List[int]) -> List[int]: 10 | output = [] 11 | for i in range(len(nums)): 12 | product = 1 13 | for num in nums[0:i] + nums[i + 1:]: 14 | product = product * num 15 | output.append(product) 16 | 17 | return output 18 | 19 | 20 | class Solution2: 21 | def productExceptSelf(self, nums: List[int]) -> List[int]: 22 | length = len(nums) 23 | output = [] 24 | 25 | left_products = [1, ] * length 26 | right_products = [1, ] * length 27 | 28 | for i in range(1, length): 29 | # start from the second leftmost index to right 30 | left_products[i] = nums[i - 1] * left_products[i - 1] 31 | 32 | # start from the second rightmost index to left 33 | right_products[-(i + 1)] = nums[-i] * right_products[-i] 34 | 35 | for i in range(length): 36 | output.append(left_products[i] * right_products[i]) 37 | 38 | return output 39 | -------------------------------------------------------------------------------- /problems/rank_scores.sql: -------------------------------------------------------------------------------- 1 | -- https://leetcode.com/problems/rank-scores/ 2 | 3 | -- https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html#function_rank 4 | SELECT score, DENSE_RANK() OVER w AS 'Rank' 5 | FROM Scores 6 | WINDOW w AS (ORDER BY score DESC); 7 | -------------------------------------------------------------------------------- /problems/remove_nth_node_from_end_of_list.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/remove-nth-node-from-end-of-list/ 4 | """ 5 | 6 | 7 | class ListNode: # pragma: no cover 8 | def __init__(self, val=0, next=None): 9 | self.val = val 10 | self.next = next 11 | 12 | 13 | class Solution: 14 | def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode: 15 | array = [] 16 | node = head 17 | while node: 18 | array.append(node) 19 | node = node.next 20 | 21 | removed_node = array[-n] 22 | 23 | # If a node has no previous, it means the node is the head 24 | try: 25 | previous_node = array[-(n + 1)] 26 | except IndexError: 27 | head = removed_node.next 28 | else: 29 | previous_node.next = removed_node.next 30 | 31 | return head 32 | 33 | 34 | class Solution2: 35 | def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode: 36 | # Calculate the length of the LinkedList in a full while loop 37 | length = 0 38 | node = head 39 | while node: 40 | length += 1 41 | node = node.next 42 | 43 | if length <= 1: 44 | return None 45 | 46 | # Convert the negative index to the 0-based index 47 | deleted_index = length - n 48 | 49 | if deleted_index == 0: 50 | head = head.next 51 | return head 52 | 53 | # Start from the head, and find the previous node of the node we're going to delete 54 | index = 0 55 | node = head 56 | while node: 57 | if index == deleted_index - 1: 58 | previous_node = node 59 | deleted_node = node.next 60 | previous_node.next = deleted_node.next 61 | return head 62 | 63 | index += 1 64 | node = node.next 65 | 66 | return head 67 | -------------------------------------------------------------------------------- /problems/repeated_string.py: -------------------------------------------------------------------------------- 1 | #!/bin/python3 2 | """ 3 | https://www.hackerrank.com/challenges/repeated-string/problem 4 | """ 5 | import math 6 | import os 7 | import random 8 | import re 9 | import sys 10 | 11 | 12 | def repeatedString(s, n): 13 | word_length = len(s) 14 | a_count_in_word = 0 15 | for char in s: 16 | if char == 'a': 17 | a_count_in_word += 1 18 | 19 | # To reach the length of n, the word s at least needs to 20 | # repeat (n // word_length) times. 21 | repeated_times = n // word_length 22 | total_a = repeated_times * a_count_in_word 23 | for char in s[:n - (repeated_times * word_length)]: 24 | if char == 'a': 25 | total_a += 1 26 | 27 | return total_a 28 | 29 | 30 | if __name__ == '__main__': 31 | fptr = open(os.environ['OUTPUT_PATH'], 'w') 32 | s = input() 33 | n = int(input()) 34 | result = repeatedString(s, n) 35 | fptr.write(str(result) + '\n') 36 | fptr.close() 37 | -------------------------------------------------------------------------------- /problems/reverse_integer.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/reverse-integer/ 4 | """ 5 | 6 | 7 | class Solution: 8 | MIN_INT = -2 ** 31 9 | MAX_INT = 2 ** 31 - 1 10 | 11 | def reverse(self, x: int) -> int: 12 | reversed_x = int(''.join(reversed(str(abs(x))))) 13 | if x < 0: 14 | reversed_x = reversed_x * -1 15 | if reversed_x < self.MIN_INT: 16 | return 0 17 | else: 18 | if reversed_x > self.MAX_INT: 19 | return 0 20 | return reversed_x 21 | -------------------------------------------------------------------------------- /problems/reverse_linked_list.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/reverse-linked-list/ 4 | """ 5 | 6 | 7 | class ListNode: # pragma: no cover 8 | def __init__(self, val=0, next=None): 9 | self.val = val 10 | self.next = next 11 | 12 | 13 | class Solution: 14 | def reverseList(self, head: ListNode) -> ListNode: 15 | node = head 16 | previous_node = None 17 | while node: 18 | next_node = node.next 19 | node.next = previous_node 20 | previous_node = node 21 | node = next_node 22 | 23 | return previous_node 24 | 25 | 26 | class Solution2: 27 | def reverseList(self, head: ListNode) -> ListNode: 28 | def reverse(node, previous_node): 29 | if not node: 30 | return previous_node 31 | next_node = node.next 32 | node.next = previous_node 33 | return reverse(next_node, node) 34 | 35 | return reverse(head, previous_node=None) 36 | -------------------------------------------------------------------------------- /problems/reverse_only_alphabetical.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://algodaily.com/challenges/reverse-only-alphabetical 4 | """ 5 | 6 | 7 | # The Two-Pointer way. 8 | def reverse_only_alpha(s): 9 | left = 0 10 | right = len(s) - 1 11 | s_list = list(s) 12 | while left < right: 13 | if not s_list[left].isalpha(): 14 | left += 1 15 | continue 16 | 17 | if not s_list[right].isalpha(): 18 | right -= 1 19 | continue 20 | 21 | s_list[left], s_list[right] = s_list[right], s_list[left] 22 | left += 1 23 | right -= 1 24 | 25 | return ''.join(s_list) 26 | -------------------------------------------------------------------------------- /problems/reverse_string.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/reverse-string/ 4 | """ 5 | from typing import List 6 | 7 | 8 | class Solution: 9 | def reverseString(self, s: List[str]) -> None: 10 | """ 11 | Do not return anything, modify s in-place instead. 12 | """ 13 | if s: 14 | left = 0 15 | right = len(s) - 1 16 | while left < right: 17 | s[left], s[right] = s[right], s[left] 18 | left += 1 19 | right -= 1 20 | -------------------------------------------------------------------------------- /problems/same_tree.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/same-tree/ 4 | """ 5 | 6 | 7 | class TreeNode: # pragma: no cover 8 | def __init__(self, val=0, left=None, right=None): 9 | self.val = val 10 | self.left = left 11 | self.right = right 12 | 13 | 14 | class Solution: 15 | def isSameTree(self, p: TreeNode, q: TreeNode) -> bool: 16 | def is_same_node(p, q): 17 | if not p and not q: 18 | return True 19 | if p and q: 20 | return (p.val == q.val) and is_same_node(p.left, q.left) and is_same_node(p.right, q.right) 21 | 22 | return False 23 | 24 | return is_same_node(p, q) 25 | -------------------------------------------------------------------------------- /problems/search_in_a_binary_search_tree.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/search-in-a-binary-search-tree/ 4 | """ 5 | 6 | 7 | class TreeNode: # pragma: no cover 8 | def __init__(self, val=0, left=None, right=None): 9 | self.val = val 10 | self.left = left 11 | self.right = right 12 | 13 | 14 | class Solution: 15 | def searchBST(self, root: TreeNode, val: int) -> TreeNode: 16 | if not root: 17 | return root 18 | 19 | def search_node(node, value): 20 | node_val = node.val 21 | if value == node_val: 22 | return node 23 | elif value < node_val: 24 | if node.left: 25 | return search_node(node.left, value) 26 | elif value > node_val: 27 | if node.right: 28 | return search_node(node.right, value) 29 | return None 30 | 31 | return search_node(root, val) 32 | 33 | 34 | class Solution2: 35 | def searchBST(self, root: TreeNode, val: int) -> TreeNode: 36 | def search_node(node, value): 37 | if not node: 38 | return None 39 | node_val = node.val 40 | if value == node_val: 41 | return node 42 | elif value < node_val: 43 | return search_node(node.left, value) 44 | elif value > node_val: 45 | return search_node(node.right, value) 46 | 47 | return search_node(root, val) 48 | -------------------------------------------------------------------------------- /problems/search_in_rotated_sorted_array.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/search-in-rotated-sorted-array/ 4 | """ 5 | from typing import List 6 | 7 | 8 | class Solution: 9 | def search(self, nums: List[int], target: int) -> int: 10 | # The simple brute-force way is quick enough. 11 | for i, num in enumerate(nums): 12 | if num == target: 13 | return i 14 | return -1 15 | 16 | 17 | class Solution2: 18 | def search(self, nums: List[int], target: int) -> int: 19 | low = 0 20 | high = len(nums) - 1 21 | while low <= high: 22 | m = (low + high) // 2 23 | if target == nums[m]: 24 | return m 25 | 26 | # The left side is sorted. 27 | if nums[low] <= nums[m]: 28 | # The left side has target which is the case of a normal binary search. 29 | if nums[low] <= target < nums[m]: 30 | high = m - 1 31 | # Since the left side doesn't have target, we don't need to check the left side anymore. 32 | # So reset the low pointer to m + 1. 33 | else: 34 | low = m + 1 35 | # The right side is sorted. 36 | elif nums[m] <= nums[high]: 37 | if nums[m] < target <= nums[high]: 38 | low = m + 1 39 | else: 40 | high = m - 1 41 | 42 | return -1 43 | -------------------------------------------------------------------------------- /problems/second_highest_salary.sql: -------------------------------------------------------------------------------- 1 | -- https://leetcode.com/problems/second-highest-salary/ 2 | 3 | -- Solution 1 4 | SELECT 5 | IFNULL( 6 | ( 7 | SELECT DISTINCT Salary 8 | FROM Employee 9 | ORDER BY Salary DESC 10 | LIMIT 1 OFFSET 1 11 | ), 12 | NULL 13 | ) AS SecondHighestSalary; 14 | 15 | -- Solution 2 16 | SELECT 17 | ( 18 | SELECT DISTINCT Salary 19 | FROM Employee 20 | ORDER BY Salary DESC 21 | LIMIT 1 OFFSET 1 22 | ) AS SecondHighestSalary; 23 | 24 | -- Solution 3 25 | SELECT max(Salary) AS SecondHighestSalary 26 | FROM Employee 27 | WHERE Salary < (SELECT max(Salary) FROM Employee); 28 | -------------------------------------------------------------------------------- /problems/shuffle_the_array.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/shuffle-the-array/ 4 | """ 5 | from typing import List 6 | 7 | 8 | class Solution: 9 | def shuffle(self, nums: List[int], n: int) -> List[int]: 10 | if not n: 11 | return nums 12 | 13 | def gen_list(): 14 | nums1 = nums[:n] 15 | nums2 = nums[n:] 16 | for i, num in enumerate(nums1): 17 | yield num 18 | yield nums2[i] 19 | 20 | return list(gen_list()) 21 | 22 | 23 | class Solution2: 24 | def shuffle(self, nums: List[int], n: int) -> List[int]: 25 | if not n: 26 | return nums 27 | 28 | def gen_list(): 29 | for i in range(n): 30 | yield nums[i] 31 | yield nums[n + i] 32 | 33 | return list(gen_list()) 34 | -------------------------------------------------------------------------------- /problems/simple_text_editor.py: -------------------------------------------------------------------------------- 1 | #!/bin/python3 2 | """ 3 | https://www.hackerrank.com/challenges/simple-text-editor/problem 4 | """ 5 | 6 | 7 | class SimpleTextEditor: 8 | def __init__(self): 9 | self.s = '' 10 | 11 | # It works as a stack for storing full copies of previous s. 12 | # However, it might take too much memory resource if s is huge. 13 | self.s_history = [] 14 | 15 | def add_history(self): 16 | # TODO: Other implementations: 17 | # https://stackoverflow.com/questions/1915907/best-practice-for-undo-redo-implementation 18 | self.s_history.append(self.s) 19 | 20 | # 1: Append string w to the end of s. 21 | def append(self, w): 22 | self.s += w 23 | 24 | # 2: Delete the last k characters of s. 25 | def delete(self, k): 26 | self.s = self.s[:len(self.s) - k] 27 | 28 | # 3: Print the k-th character of s. 29 | def print_(self, k): 30 | print(self.s[k - 1]) 31 | 32 | # 4: Undo the last (not previously undone) operation of type 1 or 2, 33 | # reverting s to the state it was in prior to that operation. 34 | def undo(self): 35 | self.s = self.s_history.pop() 36 | 37 | 38 | _ = input() 39 | editor = SimpleTextEditor() 40 | 41 | while True: 42 | try: 43 | line = input().split() 44 | except EOFError: 45 | break 46 | 47 | operation = line[0] 48 | if operation == '1': 49 | w = line[1] 50 | editor.add_history() 51 | editor.append(w) 52 | elif operation == '2': 53 | k = int(line[1]) 54 | editor.add_history() 55 | editor.delete(k) 56 | elif operation == '3': 57 | k = int(line[1]) 58 | editor.print_(k) 59 | elif operation == '4': 60 | editor.undo() 61 | -------------------------------------------------------------------------------- /problems/single_number.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/single-number/ 4 | """ 5 | from typing import List 6 | 7 | 8 | class Solution: 9 | def singleNumber(self, nums: List[int]) -> int: 10 | counter = {} 11 | for num in nums: 12 | if num not in counter: 13 | counter[num] = 1 14 | else: 15 | counter[num] += 1 16 | 17 | for num, count in counter.items(): 18 | if count == 1: 19 | return num 20 | -------------------------------------------------------------------------------- /problems/sock_merchant.py: -------------------------------------------------------------------------------- 1 | #!/bin/python3 2 | """ 3 | https://www.hackerrank.com/challenges/sock-merchant/problem 4 | """ 5 | import os 6 | 7 | from collections import Counter 8 | 9 | 10 | def sockMerchant(n, ar): 11 | if n <= 1: 12 | return 0 13 | 14 | counter = Counter(ar) 15 | total_pair = 0 16 | for count in counter.values(): 17 | total_pair += count // 2 18 | 19 | return total_pair 20 | 21 | 22 | if __name__ == '__main__': 23 | fptr = open(os.environ['OUTPUT_PATH'], 'w') 24 | n = int(input()) 25 | ar = list(map(int, input().rstrip().split())) 26 | result = sockMerchant(n, ar) 27 | fptr.write(str(result) + '\n') 28 | fptr.close() 29 | -------------------------------------------------------------------------------- /problems/sort_colors.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/sort-colors/ 4 | """ 5 | from typing import List 6 | 7 | 8 | class Solution: 9 | def sortColors(self, nums: List[int]) -> None: 10 | def counting_sort(arr, max_num_in_array): 11 | counts = [0, ] * (max_num_in_array + 1) 12 | for num in arr: 13 | counts[num] += 1 14 | 15 | i = 0 16 | for num, count in enumerate(counts): 17 | for _ in range(count): 18 | arr[i] = num 19 | i += 1 20 | 21 | counting_sort(nums, 2) 22 | -------------------------------------------------------------------------------- /problems/subsets.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/subsets/ 4 | """ 5 | from itertools import combinations 6 | from typing import List 7 | 8 | 9 | class Solution: 10 | def subsets(self, nums: List[int]) -> List[List[int]]: 11 | output = [] 12 | for i in range(0, len(nums) + 1): 13 | output.extend([list(p) for p in combinations(nums, i)]) 14 | 15 | return output 16 | 17 | 18 | class Solution2: 19 | def subsets(self, nums: List[int]) -> List[List[int]]: 20 | def gen_results(arr): 21 | # Base case 22 | if len(arr) <= 0: 23 | yield [] 24 | 25 | # Recursive case 26 | else: 27 | for p in gen_results(arr[1:]): 28 | yield [arr[0], ] + p 29 | yield p 30 | 31 | return gen_results(nums) 32 | 33 | 34 | class Solution3: 35 | def subsets(self, nums: List[int]) -> List[List[int]]: 36 | results = [] 37 | 38 | def build_results(items, result): 39 | results.append(result[:]) 40 | 41 | for i, item in enumerate(items): 42 | result.append(item) 43 | 44 | pool_items = items[i + 1:] 45 | build_results(pool_items, result) 46 | 47 | result.pop() 48 | 49 | build_results(nums, []) 50 | return results 51 | -------------------------------------------------------------------------------- /problems/task_scheduler.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/task-scheduler/ 4 | """ 5 | from collections import Counter 6 | from typing import List 7 | import heapq 8 | 9 | 10 | class Solution: 11 | def leastInterval(self, tasks: List[str], n: int) -> int: 12 | if n == 0: 13 | return len(tasks) 14 | 15 | recorded_tasks = [] 16 | queue = [] 17 | for task, count in Counter(tasks).items(): 18 | # heapq is min heap, so make count negative. 19 | heapq.heappush(queue, (-count, task)) 20 | 21 | # We should schedule the most frequent tasks as frequently as possible. 22 | while queue: 23 | put_backs = [] 24 | for _ in range(n + 1): 25 | if queue: 26 | # Pop the current most frequent task. 27 | count, task = heapq.heappop(queue) 28 | # We don't need to check whether the popped task is in recorded_tasks[-n:] or not. 29 | recorded_tasks.append(task) 30 | count += 1 31 | if count < 0: 32 | put_backs.append((count, task)) 33 | else: 34 | if put_backs: 35 | recorded_tasks.append('idle') 36 | else: 37 | break 38 | 39 | for task_data in put_backs: 40 | heapq.heappush(queue, task_data) 41 | 42 | # print(recorded_tasks) 43 | 44 | return len(recorded_tasks) 45 | -------------------------------------------------------------------------------- /problems/tests/test_add_two_numbers.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.add_two_numbers import Solution 5 | from problems.utils.leetcode import list_to_listnode 6 | from problems.utils.leetcode import listnode_to_list 7 | 8 | 9 | class TestCase(unittest.TestCase): 10 | def setUp(self): 11 | self.solution = Solution() 12 | 13 | def test(self): 14 | l1 = list_to_listnode([2, 4, 3]) 15 | l2 = list_to_listnode([5, 6, 4]) 16 | expected_head = self.solution.addTwoNumbers(l1, l2) 17 | expected = [7, 0, 8] 18 | self.assertEqual(listnode_to_list(expected_head), expected) 19 | 20 | def test2(self): 21 | l1 = list_to_listnode([0, 1, 0, 9]) 22 | l2 = list_to_listnode([1, 9, 9]) 23 | expected_head = self.solution.addTwoNumbers(l1, l2) 24 | expected = [1, 0, 0, 0, 1] 25 | self.assertEqual(listnode_to_list(expected_head), expected) 26 | 27 | 28 | if __name__ == '__main__': 29 | unittest.main() 30 | -------------------------------------------------------------------------------- /problems/tests/test_array_intersection.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from problems.array_intersection import intersection 3 | 4 | 5 | def test_intersection(): 6 | assert intersection([6, 0, 12, 10, 16], [3, 15, 18, 20, 15]) == [] 7 | assert intersection([1, 5, 2, 12, 6], [13, 10, 9, 5, 8]) == [5] 8 | assert intersection([3], [15]) == [] 9 | assert intersection([2, 16, 8, 9], [14, 15, 2, 20]) == [2] 10 | assert intersection([6, 0, 12, 10, 16], [3, 15, 18, 20, 15]) == [] 11 | assert intersection([1, 5, 2, 12, 6], [13, 10, 9, 5, 8]) == [5] 12 | assert intersection([3], [15]) == [] 13 | assert intersection([2, 16, 8, 9], [14, 15, 2, 20]) == [2] 14 | 15 | 16 | if __name__ == '__main__': 17 | test_intersection() 18 | -------------------------------------------------------------------------------- /problems/tests/test_balanced_binary_tree.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.balanced_binary_tree import Solution 5 | from problems.utils.leetcode import deserialize_tree_str 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def setUp(self): 10 | self.solution = Solution() 11 | 12 | def test(self): 13 | test_data = [ 14 | {'input': '[]', 'expected': True}, 15 | {'input': '[3,9,20,null,null,15,7]', 'expected': True}, 16 | {'input': '[1,2,2,3,3,null,null,4,4]', 'expected': False}, 17 | {'input': '[1,null,2,null,3]', 'expected': False}, 18 | ] 19 | for data in test_data: 20 | tree_str = data['input'] 21 | expected = data['expected'] 22 | with self.subTest(tree_str=tree_str): 23 | root = deserialize_tree_str(tree_str) 24 | output = self.solution.isBalanced(root) 25 | self.assertEqual(output, expected) 26 | 27 | 28 | if __name__ == '__main__': 29 | unittest.main() 30 | -------------------------------------------------------------------------------- /problems/tests/test_binary_search_tree_iterator.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.binary_search_tree_iterator import BSTIterator 5 | from problems.utils.leetcode import deserialize_tree_str 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def setUp(self): 10 | root = deserialize_tree_str('[7,3,15,null,null,9,20]') 11 | self.bst_iterator = BSTIterator(root) 12 | 13 | def test(self): 14 | self.assertEqual(self.bst_iterator.next(), 3) 15 | self.assertEqual(self.bst_iterator.next(), 7) 16 | self.assertEqual(self.bst_iterator.hasNext(), True) 17 | self.assertEqual(self.bst_iterator.next(), 9) 18 | self.assertEqual(self.bst_iterator.hasNext(), True) 19 | self.assertEqual(self.bst_iterator.next(), 15) 20 | self.assertEqual(self.bst_iterator.hasNext(), True) 21 | self.assertEqual(self.bst_iterator.next(), 20) 22 | self.assertEqual(self.bst_iterator.hasNext(), False) 23 | 24 | 25 | if __name__ == '__main__': 26 | unittest.main() 27 | -------------------------------------------------------------------------------- /problems/tests/test_binary_tree_inorder_traversal.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.binary_tree_inorder_traversal import Solution 5 | from problems.utils.leetcode import deserialize_tree_str 6 | from problems.utils.leetcode import list_to_compact_str 7 | 8 | 9 | class TestCase(unittest.TestCase): 10 | def setUp(self): 11 | self.solution = Solution() 12 | 13 | def test(self): 14 | test_data = [ 15 | {'input': '[1,null,2,3]', 'expected': '[1,3,2]'}, 16 | {'input': '[3,2,null,1]', 'expected': '[1,2,3]'}, 17 | {'input': '[3,1,null,null,2]', 'expected': '[1,2,3]'}, 18 | {'input': '[2,1,3]', 'expected': '[1,2,3]'}, 19 | {'input': '[1,null,2,null,3]', 'expected': '[1,2,3]'}, 20 | {'input': '[1,2,3,null,null,4,5]', 'expected': '[2,1,4,3,5]'}, 21 | {'input': '[5,4,7,3,null,2,null,-1,null,9]', 'expected': '[-1,3,4,5,9,2,7]'}, 22 | {'input': '[8,3,10,1,6,null,14,null,null,4,7,13]', 'expected': '[1,3,4,6,7,8,10,13,14]'}, 23 | {'input': '[]', 'expected': '[]'}, 24 | ] 25 | for data in test_data: 26 | tree_str = data['input'] 27 | expected = data['expected'] 28 | with self.subTest(tree_str=tree_str): 29 | root = deserialize_tree_str(tree_str) 30 | output = list_to_compact_str(self.solution.inorderTraversal(root)) 31 | self.assertEqual(output, expected) 32 | 33 | 34 | if __name__ == '__main__': 35 | unittest.main() 36 | -------------------------------------------------------------------------------- /problems/tests/test_binary_tree_level_order_traversal.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.binary_tree_level_order_traversal import Solution 5 | from problems.utils.leetcode import deserialize_tree_str 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def setUp(self): 10 | self.solution = Solution() 11 | 12 | def test(self): 13 | test_data = [ 14 | {'tree_str': '[3,9,20,null,null,15,7]', 'expected': [[3], [9, 20], [15, 7]]}, 15 | ] 16 | for data in test_data: 17 | tree_str = data['tree_str'] 18 | expected = data['expected'] 19 | with self.subTest(tree_str=tree_str): 20 | root = deserialize_tree_str(tree_str) 21 | output = self.solution.levelOrder(root) 22 | self.assertEqual(output, expected) 23 | 24 | 25 | if __name__ == '__main__': 26 | unittest.main() 27 | -------------------------------------------------------------------------------- /problems/tests/test_binary_tree_maximum_path_sum.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.binary_tree_maximum_path_sum import Solution 5 | from problems.utils.leetcode import deserialize_tree_str 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def setUp(self): 10 | self.solution = Solution() 11 | 12 | def test(self): 13 | test_data = [ 14 | {'input': '[1,2,3]', 'expected': 6}, 15 | {'input': '[-10,9,20,null,null,15,7]', 'expected': 42}, 16 | {'input': '[-3]', 'expected': -3}, 17 | {'input': '[2,-1]', 'expected': 2}, 18 | {'input': '[1,-2,3]', 'expected': 4}, 19 | {'input': '[5,4,8,11,null,13,4,7,2,null,null,null,1]', 'expected': 48}, 20 | ] 21 | for data in test_data: 22 | tree_str = data['input'] 23 | expected = data['expected'] 24 | with self.subTest(tree_str=tree_str): 25 | root = deserialize_tree_str(tree_str) 26 | self.assertEqual(self.solution.maxPathSum(root), expected) 27 | 28 | 29 | if __name__ == '__main__': 30 | unittest.main() 31 | -------------------------------------------------------------------------------- /problems/tests/test_binary_tree_postorder_traversal.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.binary_tree_postorder_traversal import Solution 5 | from problems.utils.leetcode import deserialize_tree_str 6 | from problems.utils.leetcode import list_to_compact_str 7 | 8 | 9 | class TestCase(unittest.TestCase): 10 | def setUp(self): 11 | self.solution = Solution() 12 | 13 | def test(self): 14 | test_data = [ 15 | {'input': '[1,null,2,3]', 'expected': '[3,2,1]'}, 16 | {'input': '[3,2,null,1]', 'expected': '[1,2,3]'}, 17 | {'input': '[3,1,null,null,2]', 'expected': '[2,1,3]'}, 18 | {'input': '[2,1,3]', 'expected': '[1,3,2]'}, 19 | {'input': '[1,null,2,null,3]', 'expected': '[3,2,1]'}, 20 | {'input': '[1,2,3,null,null,4,5]', 'expected': '[2,4,5,3,1]'}, 21 | {'input': '[5,4,7,3,null,2,null,-1,null,9]', 'expected': '[-1,3,4,9,2,7,5]'}, 22 | {'input': '[8,3,10,1,6,null,14,null,null,4,7,13]', 'expected': '[1,4,7,6,3,13,14,10,8]'}, 23 | {'input': '[]', 'expected': '[]'}, 24 | ] 25 | for data in test_data: 26 | tree_str = data['input'] 27 | expected = data['expected'] 28 | with self.subTest(tree_str=tree_str): 29 | root = deserialize_tree_str(tree_str) 30 | output = list_to_compact_str(self.solution.postorderTraversal(root)) 31 | self.assertEqual(output, expected) 32 | 33 | 34 | if __name__ == '__main__': 35 | unittest.main() 36 | -------------------------------------------------------------------------------- /problems/tests/test_binary_tree_preorder_traversal.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.binary_tree_preorder_traversal import Solution 5 | from problems.utils.leetcode import deserialize_tree_str 6 | from problems.utils.leetcode import list_to_compact_str 7 | 8 | 9 | class TestCase(unittest.TestCase): 10 | def setUp(self): 11 | self.solution = Solution() 12 | 13 | def test(self): 14 | test_data = [ 15 | {'input': '[1,null,2,3]', 'expected': '[1,2,3]'}, 16 | {'input': '[3,2,null,1]', 'expected': '[3,2,1]'}, 17 | {'input': '[3,1,null,null,2]', 'expected': '[3,1,2]'}, 18 | {'input': '[2,1,3]', 'expected': '[2,1,3]'}, 19 | {'input': '[1,null,2,null,3]', 'expected': '[1,2,3]'}, 20 | {'input': '[1,2,3,null,null,4,5]', 'expected': '[1,2,3,4,5]'}, 21 | {'input': '[5,4,7,3,null,2,null,-1,null,9]', 'expected': '[5,4,3,-1,7,2,9]'}, 22 | {'input': '[8,3,10,1,6,null,14,null,null,4,7,13]', 'expected': '[8,3,1,6,4,7,10,14,13]'}, 23 | {'input': '[]', 'expected': '[]'}, 24 | ] 25 | for data in test_data: 26 | tree_str = data['input'] 27 | expected = data['expected'] 28 | with self.subTest(tree_str=tree_str): 29 | root = deserialize_tree_str(tree_str) 30 | output = list_to_compact_str(self.solution.preorderTraversal(root)) 31 | self.assertEqual(output, expected) 32 | 33 | 34 | if __name__ == '__main__': 35 | unittest.main() 36 | -------------------------------------------------------------------------------- /problems/tests/test_camel_case.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.camel_case import camelcase 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def test(self): 9 | test_data = [ 10 | {'input': 'saveChangesInTheEditor', 'expected': 5}, 11 | ] 12 | for data in test_data: 13 | s = data['input'] 14 | expected = data['expected'] 15 | with self.subTest(s=s): 16 | self.assertEqual(camelcase(s), expected) 17 | 18 | 19 | if __name__ == '__main__': 20 | unittest.main() 21 | -------------------------------------------------------------------------------- /problems/tests/test_check_completeness_of_a_binary_tree.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.check_completeness_of_a_binary_tree import Solution 5 | from problems.utils.leetcode import deserialize_tree_str 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def setUp(self): 10 | self.solution = Solution() 11 | 12 | def test(self): 13 | test_data = [ 14 | {'input': '[1,2,3,4,5,6]', 'expected': True}, 15 | {'input': '[1,2,3,4,5,null,7]', 'expected': False}, 16 | {'input': '[1,2,3,5,null,7,8]', 'expected': False}, 17 | ] 18 | for data in test_data: 19 | tree_str = data['input'] 20 | expected = data['expected'] 21 | with self.subTest(tree_str=tree_str): 22 | root = deserialize_tree_str(tree_str) 23 | output = self.solution.isCompleteTree(root) 24 | self.assertEqual(output, expected) 25 | 26 | 27 | if __name__ == '__main__': 28 | unittest.main() 29 | -------------------------------------------------------------------------------- /problems/tests/test_combinations.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.combinations import Solution 5 | from problems.combinations import Solution2 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def setUp(self): 10 | self.solution = Solution() 11 | 12 | def test(self): 13 | expected = [ 14 | [2, 4], 15 | [3, 4], 16 | [2, 3], 17 | [1, 2], 18 | [1, 3], 19 | [1, 4], 20 | ] 21 | results = [] 22 | for result in self.solution.combine(n=4, k=2): 23 | results.append(list(result)) 24 | self.assertCountEqual(results, expected) 25 | 26 | def test2(self): 27 | expected = [ 28 | [1], 29 | ] 30 | results = [] 31 | for result in self.solution.combine(n=1, k=1): 32 | results.append(list(result)) 33 | self.assertCountEqual(results, expected) 34 | 35 | 36 | class TestCase2(unittest.TestCase): 37 | def setUp(self): 38 | self.solution = Solution2() 39 | 40 | def test(self): 41 | expected = [ 42 | [2, 4], 43 | [3, 4], 44 | [2, 3], 45 | [1, 2], 46 | [1, 3], 47 | [1, 4], 48 | ] 49 | self.assertCountEqual(self.solution.combine(n=4, k=2), expected) 50 | 51 | def test2(self): 52 | expected = [ 53 | [1], 54 | ] 55 | self.assertCountEqual(self.solution.combine(n=1, k=1), expected) 56 | 57 | 58 | if __name__ == '__main__': 59 | unittest.main() 60 | -------------------------------------------------------------------------------- /problems/tests/test_container_with_most_water.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.container_with_most_water import Solution 5 | from problems.container_with_most_water import Solution2 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def setUp(self): 10 | self.solution = Solution() 11 | 12 | def test(self): 13 | self.assertEqual(self.solution.maxArea([1, 8, 6, 2, 5, 4, 8, 3, 7]), 49) 14 | self.assertEqual(self.solution.maxArea([2, 3, 4, 5, 18, 17, 6]), 17) 15 | self.assertEqual(self.solution.maxArea([10, 9, 8, 7, 6, 5, 4, 3, 2, 1]), 25) 16 | 17 | 18 | class TestCase2(unittest.TestCase): 19 | def setUp(self): 20 | self.solution = Solution2() 21 | 22 | def test(self): 23 | self.assertEqual(self.solution.maxArea([1, 8, 6, 2, 5, 4, 8, 3, 7]), 49) 24 | self.assertEqual(self.solution.maxArea([2, 3, 4, 5, 18, 17, 6]), 17) 25 | self.assertEqual(self.solution.maxArea([10, 9, 8, 7, 6, 5, 4, 3, 2, 1]), 25) 26 | 27 | 28 | if __name__ == '__main__': 29 | unittest.main() 30 | -------------------------------------------------------------------------------- /problems/tests/test_contains_duplicate.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.contains_duplicate import Solution 5 | from problems.contains_duplicate import Solution2 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def setUp(self): 10 | self.solution = Solution() 11 | 12 | def test(self): 13 | nums = [1, 2, 3, 1] 14 | self.assertEqual(self.solution.containsDuplicate(nums), True) 15 | 16 | def test2(self): 17 | nums = [1, 2, 3] 18 | self.assertEqual(self.solution.containsDuplicate(nums), False) 19 | 20 | 21 | class TestCase2(unittest.TestCase): 22 | def setUp(self): 23 | self.solution = Solution2() 24 | 25 | def test(self): 26 | nums = [1, 2, 3, 1] 27 | self.assertEqual(self.solution.containsDuplicate(nums), True) 28 | 29 | def test2(self): 30 | nums = [1, 2, 3] 31 | self.assertEqual(self.solution.containsDuplicate(nums), False) 32 | 33 | 34 | if __name__ == '__main__': 35 | unittest.main() 36 | -------------------------------------------------------------------------------- /problems/tests/test_counting_valleys.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.counting_valleys import countingValleys 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def test(self): 9 | array = [ 10 | {'path': 'UDDDUDUU', 'expected': 1}, 11 | {'path': 'DDUUDDUDUUUD', 'expected': 2}, 12 | ] 13 | for data in array: 14 | path = data['path'] 15 | expected = data['expected'] 16 | with self.subTest(path=path): 17 | self.assertEqual(countingValleys(len(path), path), expected) 18 | 19 | 20 | if __name__ == '__main__': 21 | unittest.main() 22 | -------------------------------------------------------------------------------- /problems/tests/test_equality_in_a_array.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.equality_in_a_array import equalizeArray 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def test(self): 9 | array = [ 10 | {'arr': [3, 3, 2, 1, 3], 'expected': 2}, 11 | ] 12 | for data in array: 13 | arr = data['arr'] 14 | expected = data['expected'] 15 | with self.subTest(arr=arr): 16 | self.assertEqual(equalizeArray(arr), expected) 17 | 18 | 19 | if __name__ == '__main__': 20 | unittest.main() 21 | -------------------------------------------------------------------------------- /problems/tests/test_fibonacci_number.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.fibonacci_number import Solution 5 | from problems.fibonacci_number import Solution2 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def setUp(self): 10 | self.solution = Solution() 11 | 12 | def test(self): 13 | self.assertEqual(self.solution.fib(0), 0) 14 | self.assertEqual(self.solution.fib(1), 1) 15 | self.assertEqual(self.solution.fib(2), 1) 16 | self.assertEqual(self.solution.fib(3), 2) 17 | self.assertEqual(self.solution.fib(4), 3) 18 | self.assertEqual(self.solution.fib(5), 5) 19 | self.assertEqual(self.solution.fib(6), 8) 20 | self.assertEqual(self.solution.fib(7), 13) 21 | self.assertEqual(self.solution.fib(8), 21) 22 | self.assertEqual(self.solution.fib(9), 34) 23 | self.assertEqual(self.solution.fib(10), 55) 24 | self.assertEqual(self.solution.fib(30), 832040) 25 | 26 | 27 | class TestCase2(unittest.TestCase): 28 | def setUp(self): 29 | self.solution = Solution2() 30 | 31 | def test(self): 32 | self.assertEqual(self.solution.fib(0), 0) 33 | self.assertEqual(self.solution.fib(1), 1) 34 | self.assertEqual(self.solution.fib(2), 1) 35 | self.assertEqual(self.solution.fib(3), 2) 36 | self.assertEqual(self.solution.fib(4), 3) 37 | self.assertEqual(self.solution.fib(5), 5) 38 | self.assertEqual(self.solution.fib(6), 8) 39 | self.assertEqual(self.solution.fib(7), 13) 40 | self.assertEqual(self.solution.fib(8), 21) 41 | self.assertEqual(self.solution.fib(9), 34) 42 | self.assertEqual(self.solution.fib(10), 55) 43 | self.assertEqual(self.solution.fib(30), 832040) 44 | 45 | 46 | if __name__ == '__main__': 47 | unittest.main() 48 | -------------------------------------------------------------------------------- /problems/tests/test_find_minimum_in_rotated_sorted_array.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.find_minimum_in_rotated_sorted_array import Solution 5 | from problems.find_minimum_in_rotated_sorted_array import Solution2 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def setUp(self): 10 | self.solution = Solution() 11 | 12 | def test(self): 13 | self.assertEqual(self.solution.findMin([4, 5, 6, 7, 0, 1, 2]), 0) 14 | self.assertEqual(self.solution.findMin([0, 1, 2, 4, 5, 6, 7]), 0) 15 | self.assertEqual(self.solution.findMin([1, 2, 4, 5, 6, 7, 0]), 0) 16 | self.assertEqual(self.solution.findMin([7, 0, 1, 2, 4, 5, 6]), 0) 17 | self.assertEqual(self.solution.findMin([3, 4, 5, 1, 2]), 1) 18 | self.assertEqual(self.solution.findMin([1, ]), 1) 19 | self.assertEqual(self.solution.findMin([2, 1]), 1) 20 | self.assertEqual(self.solution.findMin([3, 1, 2]), 1) 21 | 22 | 23 | class TestCase2(unittest.TestCase): 24 | def setUp(self): 25 | self.solution = Solution2() 26 | 27 | def test(self): 28 | self.assertEqual(self.solution.findMin([4, 5, 6, 7, 0, 1, 2]), 0) 29 | self.assertEqual(self.solution.findMin([0, 1, 2, 4, 5, 6, 7]), 0) 30 | self.assertEqual(self.solution.findMin([1, 2, 4, 5, 6, 7, 0]), 0) 31 | self.assertEqual(self.solution.findMin([7, 0, 1, 2, 4, 5, 6]), 0) 32 | self.assertEqual(self.solution.findMin([3, 4, 5, 1, 2]), 1) 33 | self.assertEqual(self.solution.findMin([1, ]), 1) 34 | self.assertEqual(self.solution.findMin([2, 1]), 1) 35 | self.assertEqual(self.solution.findMin([3, 1, 2]), 1) 36 | 37 | 38 | if __name__ == '__main__': 39 | unittest.main() 40 | -------------------------------------------------------------------------------- /problems/tests/test_find_mode_in_binary_search_tree.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.find_mode_in_binary_search_tree import Solution 5 | from problems.utils.leetcode import deserialize_tree_str 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def setUp(self): 10 | self.solution = Solution() 11 | 12 | def test(self): 13 | test_data = [ 14 | {'tree_str': '[1,null,2,2]', 'expected': [2, ]}, 15 | {'tree_str': '[1,null,2]', 'expected': [1, 2]}, 16 | ] 17 | for data in test_data: 18 | tree_str = data['tree_str'] 19 | expected = data['expected'] 20 | with self.subTest(tree_str=tree_str): 21 | root = deserialize_tree_str(tree_str) 22 | output = self.solution.findMode(root) 23 | self.assertCountEqual(output, expected) 24 | 25 | 26 | if __name__ == '__main__': 27 | unittest.main() 28 | -------------------------------------------------------------------------------- /problems/tests/test_find_the_duplicate_number.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.find_the_duplicate_number import Solution 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def setUp(self): 9 | self.solution = Solution() 10 | 11 | def test(self): 12 | array = [ 13 | {'nums': [1, 3, 4, 2, 2], 'expected': 2}, 14 | {'nums': [3, 1, 3, 4, 2], 'expected': 3}, 15 | {'nums': [1, 1], 'expected': 1}, 16 | {'nums': [1, 1, 2], 'expected': 1}, 17 | ] 18 | for data in array: 19 | nums = data['nums'] 20 | expected = data['expected'] 21 | with self.subTest(nums=nums): 22 | self.assertEqual(self.solution.findDuplicate(nums), expected) 23 | 24 | 25 | if __name__ == '__main__': 26 | unittest.main() 27 | -------------------------------------------------------------------------------- /problems/tests/test_fizz_buzz.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.fizz_buzz import Solution 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def setUp(self): 9 | self.solution = Solution() 10 | 11 | def test(self): 12 | test_data = [ 13 | {'n': 1, 'expected': ['1', ]}, 14 | {'n': 15, 'expected': ['1', '2', 'Fizz', '4', 'Buzz', 'Fizz', '7', '8', 'Fizz', 'Buzz', '11', 'Fizz', '13', '14', 'FizzBuzz']}, 15 | {'n': 31, 'expected': ['1', '2', 'Fizz', '4', 'Buzz', 'Fizz', '7', '8', 'Fizz', 'Buzz', '11', 'Fizz', '13', '14', 'FizzBuzz', '16', '17', 'Fizz', '19', 'Buzz', 'Fizz', '22', '23', 'Fizz', 'Buzz', '26', 'Fizz', '28', '29', 'FizzBuzz', '31']}, 16 | {'n': 0, 'expected': []}, 17 | {'n': -15, 'expected': []}, 18 | ] 19 | for data in test_data: 20 | n = data['n'] 21 | expected = data['expected'] 22 | with self.subTest(n=n): 23 | self.assertEqual(list(self.solution.fizzBuzz(n)), expected) 24 | 25 | 26 | if __name__ == '__main__': 27 | unittest.main() 28 | -------------------------------------------------------------------------------- /problems/tests/test_group_anagrams.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.group_anagrams import Solution 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def setUp(self): 9 | self.solution = Solution() 10 | 11 | def test(self): 12 | strs = ['eat', 'tea', 'tan', 'ate', 'nat', 'bat'] 13 | expected = [['eat', 'tea', 'ate'], ['tan', 'nat'], ['bat']] 14 | self.assertCountEqual(self.solution.groupAnagrams(strs), expected) 15 | 16 | 17 | if __name__ == '__main__': 18 | unittest.main() 19 | -------------------------------------------------------------------------------- /problems/tests/test_hackerrank_in_a_string.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.hackerrank_in_a_string import hackerrankInString 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def test(self): 9 | array = [ 10 | {'s': 'hereiamstackerrank', 'expected': 'YES'}, 11 | {'s': 'hackerworld', 'expected': 'NO'}, 12 | {'s': 'hhaacckkekraraannk', 'expected': 'YES'}, 13 | {'s': 'rhbaasdndfsdskgbfefdbrsdfhuyatrjtcrtyytktjjt', 'expected': 'NO'}, 14 | ] 15 | for data in array: 16 | s = data['s'] 17 | expected = data['expected'] 18 | with self.subTest(s=s): 19 | self.assertEqual(hackerrankInString(s), expected) 20 | 21 | 22 | if __name__ == '__main__': 23 | unittest.main() 24 | -------------------------------------------------------------------------------- /problems/tests/test_implement_trie_prefix_tree.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.implement_trie_prefix_tree import Trie 5 | 6 | 7 | class TrieNodeTest(unittest.TestCase): 8 | def setUp(self): 9 | self.trie = Trie() 10 | 11 | def test__len__(self): 12 | self.assertEqual(len(self.trie), 0) 13 | 14 | def test_insert(self): 15 | with self.assertRaises(ValueError): 16 | self.trie.insert('') 17 | 18 | def test_search(self): 19 | self.assertEqual(self.trie.search(''), False) 20 | 21 | def test_startsWith(self): 22 | self.assertEqual(self.trie.startsWith(''), True) 23 | 24 | def test_integration(self): 25 | self.trie.insert('apple') 26 | self.assertEqual(len(self.trie), 1) 27 | self.assertEqual(self.trie.search('apple'), True) 28 | self.assertEqual(self.trie.search('app'), False) 29 | self.assertEqual(self.trie.startsWith('app'), True) 30 | 31 | self.trie.insert('app') 32 | self.assertEqual(len(self.trie), 2) 33 | self.assertEqual(self.trie.search('app'), True) 34 | self.assertEqual(self.trie.startsWith('app'), True) 35 | 36 | self.trie.insert('hammer') 37 | self.assertEqual(len(self.trie), 3) 38 | self.assertEqual(self.trie.search('hammers'), False) 39 | self.assertEqual(self.trie.startsWith('hammers'), False) 40 | 41 | 42 | if __name__ == '__main__': 43 | unittest.main() 44 | -------------------------------------------------------------------------------- /problems/tests/test_invert_binary_tree.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.invert_binary_tree import Solution 5 | from problems.invert_binary_tree import Solution2 6 | from problems.utils.leetcode import deserialize_tree_str 7 | from problems.utils.leetcode import serialize_treenode 8 | 9 | 10 | class TestCase(unittest.TestCase): 11 | def setUp(self): 12 | self.solution = Solution() 13 | 14 | def test(self): 15 | test_data = [ 16 | {'input': '[4,2,7,1,3,6,9]', 'expected': '[4,7,2,9,6,3,1]'}, 17 | {'input': '[]', 'expected': '[]'}, 18 | ] 19 | for data in test_data: 20 | tree_str = data['input'] 21 | expected = data['expected'] 22 | with self.subTest(tree_str=tree_str): 23 | root = deserialize_tree_str(tree_str) 24 | output = self.solution.invertTree(root) 25 | self.assertEqual(serialize_treenode(output), expected) 26 | 27 | 28 | class TestCase2(unittest.TestCase): 29 | def setUp(self): 30 | self.solution = Solution2() 31 | 32 | def test(self): 33 | test_data = [ 34 | {'input': '[4,2,7,1,3,6,9]', 'expected': '[4,7,2,9,6,3,1]'}, 35 | {'input': '[]', 'expected': '[]'}, 36 | ] 37 | for data in test_data: 38 | tree_str = data['input'] 39 | expected = data['expected'] 40 | with self.subTest(tree_str=tree_str): 41 | root = deserialize_tree_str(tree_str) 42 | output = self.solution.invertTree(root) 43 | self.assertEqual(serialize_treenode(output), expected) 44 | 45 | 46 | if __name__ == '__main__': 47 | unittest.main() 48 | -------------------------------------------------------------------------------- /problems/tests/test_is_subsequence.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.is_subsequence import Solution 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def setUp(self): 9 | self.solution = Solution() 10 | 11 | def test(self): 12 | s = 'abc' 13 | t = 'ahbgdc' 14 | self.assertEqual(self.solution.isSubsequence(s, t), True) 15 | 16 | def test2(self): 17 | s = 'bale' 18 | t = 'abppplee' 19 | self.assertEqual(self.solution.isSubsequence(s, t), False) 20 | 21 | def test3(self): 22 | s = '' 23 | t = '' 24 | self.assertEqual(self.solution.isSubsequence(s, t), True) 25 | 26 | 27 | if __name__ == '__main__': 28 | unittest.main() 29 | -------------------------------------------------------------------------------- /problems/tests/test_jumping_on_the_clouds.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.jumping_on_the_clouds import jumpingOnClouds 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def test(self): 9 | array = [ 10 | {'c': [0, 0, 1, 0, 0, 1, 0], 'expected': 4}, 11 | {'c': [0, 0, 0, 1, 0, 0], 'expected': 3}, 12 | ] 13 | for data in array: 14 | c = data['c'] 15 | expected = data['expected'] 16 | with self.subTest(c=c): 17 | self.assertEqual(jumpingOnClouds(c), expected) 18 | 19 | 20 | if __name__ == '__main__': 21 | unittest.main() 22 | -------------------------------------------------------------------------------- /problems/tests/test_kth_smallest_element_in_a_bst.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.kth_smallest_element_in_a_bst import Solution 5 | from problems.utils.leetcode import deserialize_tree_str 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def setUp(self): 10 | self.solution = Solution() 11 | 12 | def test(self): 13 | test_data = [ 14 | {'tree_str': '[3,1,4,null,2]', 'k': 1, 'expected': 1}, 15 | {'tree_str': '[5,3,6,2,4,null,null,1]', 'k': 3, 'expected': 3}, 16 | ] 17 | for data in test_data: 18 | tree_str = data['tree_str'] 19 | k = data['k'] 20 | expected = data['expected'] 21 | with self.subTest(tree_str=tree_str, k=k): 22 | root = deserialize_tree_str(tree_str) 23 | output = self.solution.kthSmallest(root, k) 24 | self.assertEqual(output, expected) 25 | 26 | 27 | if __name__ == '__main__': 28 | unittest.main() 29 | -------------------------------------------------------------------------------- /problems/tests/test_mars_exploration.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.mars_exploration import marsExploration 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def test(self): 9 | array = [ 10 | {'message': 'SOSSPSSQSSOR', 'expected': 3}, 11 | {'message': 'SOSSOT', 'expected': 1}, 12 | {'message': 'SOSSOSSOS', 'expected': 0}, 13 | ] 14 | for item in array: 15 | message = item['message'] 16 | expected = item['expected'] 17 | with self.subTest(message=message): 18 | self.assertEqual(marsExploration(message), expected) 19 | 20 | 21 | if __name__ == '__main__': 22 | unittest.main() 23 | -------------------------------------------------------------------------------- /problems/tests/test_maximum_depth_of_binary_tree.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.maximum_depth_of_binary_tree import Solution 5 | from problems.maximum_depth_of_binary_tree import Solution2 6 | from problems.utils.leetcode import deserialize_tree_str 7 | 8 | 9 | class TestCase(unittest.TestCase): 10 | def setUp(self): 11 | self.solution = Solution() 12 | 13 | def test(self): 14 | test_data = [ 15 | {'tree_str': '[3,9,20,null,null,15,7]', 'expected': 3}, 16 | {'tree_str': '[1]', 'expected': 1}, 17 | {'tree_str': '[]', 'expected': 0}, 18 | ] 19 | for data in test_data: 20 | tree_str = data['tree_str'] 21 | expected = data['expected'] 22 | with self.subTest(tree_str=tree_str): 23 | root = deserialize_tree_str(tree_str) 24 | output = self.solution.maxDepth(root) 25 | self.assertEqual(output, expected) 26 | 27 | 28 | class TestCase2(unittest.TestCase): 29 | def setUp(self): 30 | self.solution = Solution2() 31 | 32 | def test(self): 33 | test_data = [ 34 | {'tree_str': '[3,9,20,null,null,15,7]', 'expected': 3}, 35 | {'tree_str': '[1]', 'expected': 1}, 36 | {'tree_str': '[]', 'expected': 0}, 37 | ] 38 | for data in test_data: 39 | tree_str = data['tree_str'] 40 | expected = data['expected'] 41 | with self.subTest(tree_str=tree_str): 42 | root = deserialize_tree_str(tree_str) 43 | output = self.solution.maxDepth(root) 44 | self.assertEqual(output, expected) 45 | 46 | 47 | if __name__ == '__main__': 48 | unittest.main() 49 | -------------------------------------------------------------------------------- /problems/tests/test_maximum_product_subarray.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.maximum_product_subarray import Solution 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def setUp(self): 9 | self.solution = Solution() 10 | 11 | def test(self): 12 | nums = [2, -5, -2, -4, 3] 13 | self.assertEqual(self.solution.maxProduct(nums), 24) 14 | 15 | def test2(self): 16 | nums = [-2, 0, -1] 17 | self.assertEqual(self.solution.maxProduct(nums), 0) 18 | 19 | def test3(self): 20 | nums = [3, -1, 4] 21 | self.assertEqual(self.solution.maxProduct(nums), 4) 22 | 23 | def test4(self): 24 | nums = [0, 2] 25 | self.assertEqual(self.solution.maxProduct(nums), 2) 26 | 27 | 28 | if __name__ == '__main__': 29 | unittest.main() 30 | -------------------------------------------------------------------------------- /problems/tests/test_maximum_subarray.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.maximum_subarray import Solution 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def setUp(self): 9 | self.solution = Solution() 10 | 11 | def test(self): 12 | nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4] 13 | self.assertEqual(self.solution.maxSubArray(nums), 6) 14 | 15 | 16 | if __name__ == '__main__': 17 | unittest.main() 18 | -------------------------------------------------------------------------------- /problems/tests/test_merge_intervals.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.merge_intervals import Solution 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def setUp(self): 9 | self.solution = Solution() 10 | 11 | def test(self): 12 | intervals = [[1, 3], [2, 6], [8, 10], [15, 18]] 13 | expected = [[1, 6], [8, 10], [15, 18]] 14 | self.assertEqual(self.solution.merge(intervals), expected) 15 | 16 | def test2(self): 17 | intervals = [[1, 4], [4, 5], [5, 6]] 18 | expected = [[1, 6]] 19 | self.assertEqual(self.solution.merge(intervals), expected) 20 | 21 | def test3(self): 22 | intervals = [[2, 3], [1, 4]] 23 | expected = [[1, 4]] 24 | self.assertEqual(self.solution.merge(intervals), expected) 25 | 26 | 27 | if __name__ == '__main__': 28 | unittest.main() 29 | -------------------------------------------------------------------------------- /problems/tests/test_merge_k_sorted_lists.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.merge_k_sorted_lists import Solution 5 | from problems.utils.leetcode import list_to_listnode 6 | from problems.utils.leetcode import listnode_to_list 7 | 8 | 9 | class TestCase(unittest.TestCase): 10 | def setUp(self): 11 | self.solution = Solution() 12 | 13 | def test(self): 14 | test_array = [ 15 | { 16 | 'lists': [ 17 | [1, 4, 5], 18 | [1, 3, 4], 19 | [2, 6], 20 | ], 21 | 'expected': [1, 1, 2, 3, 4, 4, 5, 6], 22 | }, 23 | ] 24 | for data in test_array: 25 | lists = [list_to_listnode(array) for array in data['lists']] 26 | expected = data['expected'] 27 | with self.subTest(lists=lists): 28 | head = self.solution.mergeKLists(lists) 29 | self.assertEqual(listnode_to_list(head), expected) 30 | 31 | 32 | if __name__ == '__main__': 33 | unittest.main() 34 | -------------------------------------------------------------------------------- /problems/tests/test_middle_of_the_linked_list.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.middle_of_the_linked_list import Solution 5 | from problems.middle_of_the_linked_list import Solution2 6 | from problems.utils.leetcode import list_to_listnode 7 | from problems.utils.leetcode import listnode_to_list 8 | 9 | 10 | class TestCase(unittest.TestCase): 11 | def setUp(self): 12 | self.solution = Solution() 13 | 14 | def test(self): 15 | test_array = [ 16 | {'arr': [1, 2, 3, 4, 5], 'expected': [3, 4, 5]}, 17 | {'arr': [1, 2, 3, 4, 5, 6], 'expected': [4, 5, 6]}, 18 | {'arr': [], 'expected': []}, 19 | ] 20 | for data in test_array: 21 | arr = data['arr'] 22 | expected = data['expected'] 23 | with self.subTest(arr=arr): 24 | head = list_to_listnode(arr) 25 | result = self.solution.middleNode(head) 26 | self.assertEqual(listnode_to_list(result), expected) 27 | 28 | 29 | class TestCase2(unittest.TestCase): 30 | def setUp(self): 31 | self.solution = Solution2() 32 | 33 | def test(self): 34 | test_array = [ 35 | {'arr': [1, 2, 3, 4, 5], 'expected': [3, 4, 5]}, 36 | {'arr': [1, 2, 3, 4, 5, 6], 'expected': [4, 5, 6]}, 37 | {'arr': [], 'expected': []}, 38 | ] 39 | for data in test_array: 40 | arr = data['arr'] 41 | expected = data['expected'] 42 | with self.subTest(arr=arr): 43 | head = list_to_listnode(arr) 44 | result = self.solution.middleNode(head) 45 | self.assertEqual(listnode_to_list(result), expected) 46 | 47 | 48 | if __name__ == '__main__': 49 | unittest.main() 50 | -------------------------------------------------------------------------------- /problems/tests/test_minimum_depth_of_binary_tree.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.minimum_depth_of_binary_tree import Solution 5 | from problems.utils.leetcode import deserialize_tree_str 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def setUp(self): 10 | self.solution = Solution() 11 | 12 | def test(self): 13 | test_data = [ 14 | {'tree_str': '[3,9,20,null,null,15,7]', 'expected': 2}, 15 | {'tree_str': '[1]', 'expected': 1}, 16 | {'tree_str': '[]', 'expected': 0}, 17 | ] 18 | for data in test_data: 19 | tree_str = data['tree_str'] 20 | expected = data['expected'] 21 | with self.subTest(tree_str=tree_str): 22 | root = deserialize_tree_str(tree_str) 23 | output = self.solution.minDepth(root) 24 | self.assertEqual(output, expected) 25 | 26 | 27 | if __name__ == '__main__': 28 | unittest.main() 29 | -------------------------------------------------------------------------------- /problems/tests/test_missing_number.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.missing_number import Solution 5 | from problems.missing_number import Solution2 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def setUp(self): 10 | self.solution = Solution() 11 | 12 | def test(self): 13 | test_array = [ 14 | {'nums': [3, 0, 1], 'expected': 2}, 15 | {'nums': [9, 6, 4, 2, 3, 5, 7, 0, 1], 'expected': 8}, 16 | ] 17 | for data in test_array: 18 | nums = data['nums'] 19 | expected = data['expected'] 20 | with self.subTest(nums=nums): 21 | self.assertEqual(self.solution.missingNumber(nums), expected) 22 | 23 | 24 | class TestCase2(unittest.TestCase): 25 | def setUp(self): 26 | self.solution = Solution2() 27 | 28 | def test(self): 29 | test_array = [ 30 | {'nums': [3, 0, 1], 'expected': 2}, 31 | {'nums': [9, 6, 4, 2, 3, 5, 7, 0, 1], 'expected': 8}, 32 | ] 33 | for data in test_array: 34 | nums = data['nums'] 35 | expected = data['expected'] 36 | with self.subTest(nums=nums): 37 | self.assertEqual(self.solution.missingNumber(nums), expected) 38 | 39 | 40 | if __name__ == '__main__': 41 | unittest.main() 42 | -------------------------------------------------------------------------------- /problems/tests/test_pangrams.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.pangrams import pangrams 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def test(self): 9 | test_array = [ 10 | {'s': 'We promptly judged antique ivory buckles for the next prize', 'expected': 'pangram'}, 11 | {'s': 'We promptly judged antique ivory buckles for the prize', 'expected': 'not pangram'}, 12 | ] 13 | for data in test_array: 14 | s = data['s'] 15 | expected = data['expected'] 16 | with self.subTest(s=s): 17 | self.assertEqual(pangrams(s), expected) 18 | 19 | 20 | if __name__ == '__main__': 21 | unittest.main() 22 | -------------------------------------------------------------------------------- /problems/tests/test_path_sum.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.path_sum import Solution 5 | from problems.utils.leetcode import deserialize_tree_str 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def setUp(self): 10 | self.solution = Solution() 11 | 12 | def test(self): 13 | test_data = [ 14 | {'tree_str': '[5,4,8,11,null,13,4,7,2,null,null,null,1]', 'path_sum': 22, 'expected': True}, 15 | ] 16 | for data in test_data: 17 | tree_str = data['tree_str'] 18 | path_sum = data['path_sum'] 19 | expected = data['expected'] 20 | with self.subTest(tree_str=tree_str, path_sum=path_sum): 21 | root = deserialize_tree_str(tree_str) 22 | self.assertEqual(self.solution.hasPathSum(root, path_sum), expected) 23 | 24 | 25 | if __name__ == '__main__': 26 | unittest.main() 27 | -------------------------------------------------------------------------------- /problems/tests/test_product_of_array_except_self.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.product_of_array_except_self import Solution 5 | from problems.product_of_array_except_self import Solution2 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def setUp(self): 10 | self.solution = Solution() 11 | 12 | def test(self): 13 | nums = [1, 2, 3, 4] 14 | expected_output = [24, 12, 8, 6] 15 | self.assertEqual(self.solution.productExceptSelf(nums), expected_output) 16 | 17 | 18 | class TestCase2(unittest.TestCase): 19 | def setUp(self): 20 | self.solution = Solution2() 21 | 22 | def test(self): 23 | nums = [1, 2, 3, 4] 24 | expected_output = [24, 12, 8, 6] 25 | self.assertEqual(self.solution.productExceptSelf(nums), expected_output) 26 | 27 | 28 | if __name__ == '__main__': 29 | unittest.main() 30 | -------------------------------------------------------------------------------- /problems/tests/test_repeated_string.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.repeated_string import repeatedString 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def test(self): 9 | array = [ 10 | {'s': 'aba', 'n': 10, 'expected': 7}, 11 | {'s': 'a', 'n': 1000000000000, 'expected': 1000000000000}, 12 | ] 13 | for data in array: 14 | s = data['s'] 15 | n = data['n'] 16 | expected = data['expected'] 17 | with self.subTest(s=s, n=n): 18 | self.assertEqual(repeatedString(s, n), expected) 19 | 20 | 21 | if __name__ == '__main__': 22 | unittest.main() 23 | -------------------------------------------------------------------------------- /problems/tests/test_reverse_integer.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.reverse_integer import Solution 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def setUp(self): 9 | self.solution = Solution() 10 | 11 | def test(self): 12 | test_lists = [ 13 | (123, 321), 14 | (120, 21), 15 | (-123, -321), 16 | (-120, -21), 17 | (0, 0), 18 | (1534236469, 0), 19 | (-2147483648, 0), 20 | ] 21 | 22 | for x, expected in test_lists: 23 | with self.subTest(x=x): 24 | self.assertEqual(self.solution.reverse(x), expected) 25 | 26 | 27 | if __name__ == '__main__': 28 | unittest.main() 29 | -------------------------------------------------------------------------------- /problems/tests/test_reverse_linked_list.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.reverse_linked_list import Solution 5 | from problems.reverse_linked_list import Solution2 6 | from problems.utils.leetcode import list_to_listnode 7 | from problems.utils.leetcode import listnode_to_list 8 | 9 | 10 | class TestCase(unittest.TestCase): 11 | def setUp(self): 12 | self.solution = Solution() 13 | 14 | def test(self): 15 | head = list_to_listnode([1, 2, 3, 4, 5]) 16 | expected_head = self.solution.reverseList(head) 17 | expected = [5, 4, 3, 2, 1] 18 | self.assertEqual(listnode_to_list(expected_head), expected) 19 | 20 | 21 | class TestCase2(unittest.TestCase): 22 | def setUp(self): 23 | self.solution = Solution2() 24 | 25 | def test(self): 26 | head = list_to_listnode([1, 2, 3, 4, 5]) 27 | expected_head = self.solution.reverseList(head) 28 | expected = [5, 4, 3, 2, 1] 29 | self.assertEqual(listnode_to_list(expected_head), expected) 30 | 31 | 32 | if __name__ == '__main__': 33 | unittest.main() 34 | -------------------------------------------------------------------------------- /problems/tests/test_reverse_only_alphabetical.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from problems.reverse_only_alphabetical import reverse_only_alpha 3 | 4 | 5 | def test_reverse_only_alpha(): 6 | assert reverse_only_alpha('sea!$hells3') == 'sll!$ehaes3' 7 | assert reverse_only_alpha('1kas90jda3') == '1adj90sak3' 8 | 9 | 10 | if __name__ == '__main__': 11 | test_reverse_only_alpha() 12 | -------------------------------------------------------------------------------- /problems/tests/test_reverse_string.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.reverse_string import Solution 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def setUp(self): 9 | self.solution = Solution() 10 | 11 | def test(self): 12 | test_data = [ 13 | {'s': ['h', 'e', 'l', 'l', 'o']}, 14 | {'s': ['H', 'a', 'n', 'n', 'a', 'h']}, 15 | ] 16 | for data in test_data: 17 | s = data['s'] 18 | expected = list(reversed(s)) 19 | with self.subTest(s=s): 20 | self.solution.reverseString(s) 21 | self.assertEqual(s, expected) 22 | 23 | 24 | if __name__ == '__main__': 25 | unittest.main() 26 | -------------------------------------------------------------------------------- /problems/tests/test_same_tree.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.same_tree import Solution 5 | from problems.utils.leetcode import deserialize_tree_str 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def setUp(self): 10 | self.solution = Solution() 11 | 12 | def test(self): 13 | test_data = [ 14 | {'p_tree_str': '[1,2,3]', 'q_tree_str': '[1,2,3]', 'expected': True}, 15 | {'p_tree_str': '[1,2]', 'q_tree_str': '[1,null,2]', 'expected': False}, 16 | {'p_tree_str': '[1,2,1]', 'q_tree_str': '[1,1,2]', 'expected': False}, 17 | ] 18 | for data in test_data: 19 | p_tree_str = data['p_tree_str'] 20 | q_tree_str = data['q_tree_str'] 21 | expected = data['expected'] 22 | with self.subTest(p_tree_str=p_tree_str, q_tree_str=q_tree_str): 23 | p = deserialize_tree_str(p_tree_str) 24 | q = deserialize_tree_str(q_tree_str) 25 | output = self.solution.isSameTree(p, q) 26 | self.assertEqual(output, expected) 27 | 28 | 29 | if __name__ == '__main__': 30 | unittest.main() 31 | -------------------------------------------------------------------------------- /problems/tests/test_search_in_rotated_sorted_array.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.search_in_rotated_sorted_array import Solution 5 | from problems.search_in_rotated_sorted_array import Solution2 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def setUp(self): 10 | self.solution = Solution() 11 | 12 | def test(self): 13 | test_data = [ 14 | {'nums': [4, 5, 6, 7, 0, 1, 2], 'target': 0, 'expected': 4}, 15 | {'nums': [4, 5, 6, 7, 0, 1, 2], 'target': 3, 'expected': -1}, 16 | {'nums': [3, 5, 7, 9, 11, 1], 'target': 9, 'expected': 3}, 17 | {'nums': [12, 5, 7, 9, 11], 'target': 12, 'expected': 0}, 18 | {'nums': [1, ], 'target': 1, 'expected': 0}, 19 | {'nums': [1, ], 'target': 0, 'expected': -1}, 20 | ] 21 | for data in test_data: 22 | nums = data['nums'] 23 | target = data['target'] 24 | expected = data['expected'] 25 | with self.subTest(nums=nums, target=target): 26 | self.assertEqual(self.solution.search(nums, target), expected) 27 | 28 | 29 | class TestCase2(unittest.TestCase): 30 | def setUp(self): 31 | self.solution = Solution2() 32 | 33 | def test(self): 34 | test_data = [ 35 | {'nums': [4, 5, 6, 7, 0, 1, 2], 'target': 0, 'expected': 4}, 36 | {'nums': [4, 5, 6, 7, 0, 1, 2], 'target': 3, 'expected': -1}, 37 | {'nums': [3, 5, 7, 9, 11, 1], 'target': 9, 'expected': 3}, 38 | {'nums': [12, 5, 7, 9, 11], 'target': 12, 'expected': 0}, 39 | {'nums': [1, ], 'target': 1, 'expected': 0}, 40 | {'nums': [1, ], 'target': 0, 'expected': -1}, 41 | ] 42 | for data in test_data: 43 | nums = data['nums'] 44 | target = data['target'] 45 | expected = data['expected'] 46 | with self.subTest(nums=nums, target=target): 47 | self.assertEqual(self.solution.search(nums, target), expected) 48 | 49 | 50 | if __name__ == '__main__': 51 | unittest.main() 52 | -------------------------------------------------------------------------------- /problems/tests/test_serialize_and_deserialize_binary_tree.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.serialize_and_deserialize_binary_tree import Codec 5 | from problems.utils.leetcode import deserialize_tree_str 6 | from problems.utils.leetcode import serialize_treenode 7 | 8 | 9 | class TestCase(unittest.TestCase): 10 | def test(self): 11 | test_data = [ 12 | {'input': '[]'}, 13 | {'input': '[-1,0,1]'}, 14 | {'input': '[1,2,3,null,null,4,5]'}, 15 | ] 16 | for data in test_data: 17 | tree_str = data['input'] 18 | with self.subTest(tree_str=tree_str): 19 | root = deserialize_tree_str(tree_str) 20 | codec = Codec() 21 | expected_root = codec.deserialize(codec.serialize(root)) 22 | self.assertEqual(tree_str, serialize_treenode(expected_root)) 23 | 24 | 25 | if __name__ == '__main__': 26 | unittest.main() 27 | -------------------------------------------------------------------------------- /problems/tests/test_shuffle_the_array.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.shuffle_the_array import Solution 5 | from problems.shuffle_the_array import Solution2 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def setUp(self): 10 | self.solution = Solution() 11 | 12 | def test(self): 13 | test_data = [ 14 | {'nums': [2, 5, 1, 3, 4, 7], 'n': 3, 'expected': [2, 3, 5, 4, 1, 7]}, 15 | {'nums': [1, 2, 3, 4, 4, 3, 2, 1], 'n': 4, 'expected': [1, 4, 2, 3, 3, 2, 4, 1]}, 16 | {'nums': [1, 1, 2, 2], 'n': 2, 'expected': [1, 2, 1, 2]}, 17 | ] 18 | for data in test_data: 19 | nums = data['nums'] 20 | n = data['n'] 21 | expected = data['expected'] 22 | with self.subTest(nums=nums, n=n): 23 | self.assertEqual(self.solution.shuffle(nums, n), expected) 24 | 25 | 26 | class TestCase2(unittest.TestCase): 27 | def setUp(self): 28 | self.solution = Solution2() 29 | 30 | def test(self): 31 | test_data = [ 32 | {'nums': [2, 5, 1, 3, 4, 7], 'n': 3, 'expected': [2, 3, 5, 4, 1, 7]}, 33 | {'nums': [1, 2, 3, 4, 4, 3, 2, 1], 'n': 4, 'expected': [1, 4, 2, 3, 3, 2, 4, 1]}, 34 | {'nums': [1, 1, 2, 2], 'n': 2, 'expected': [1, 2, 1, 2]}, 35 | ] 36 | for data in test_data: 37 | nums = data['nums'] 38 | n = data['n'] 39 | expected = data['expected'] 40 | with self.subTest(nums=nums, n=n): 41 | self.assertEqual(self.solution.shuffle(nums, n), expected) 42 | 43 | 44 | if __name__ == '__main__': 45 | unittest.main() 46 | -------------------------------------------------------------------------------- /problems/tests/test_single_number.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.single_number import Solution 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def setUp(self): 9 | self.solution = Solution() 10 | 11 | def test(self): 12 | test_data = [ 13 | {'nums': [2, 2, 1], 'expected': 1}, 14 | {'nums': [4, 1, 2, 1, 2], 'expected': 4}, 15 | ] 16 | for data in test_data: 17 | nums = data['nums'] 18 | expected = data['expected'] 19 | with self.subTest(nums=nums): 20 | self.assertEqual(self.solution.singleNumber(nums), expected) 21 | 22 | 23 | if __name__ == '__main__': 24 | unittest.main() 25 | -------------------------------------------------------------------------------- /problems/tests/test_sock_merchant.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.sock_merchant import sockMerchant 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def test(self): 9 | test_data = [ 10 | {'n': 9, 'ar': [10, 20, 20, 10, 10, 30, 50, 10, 20], 'expected': 3}, 11 | ] 12 | for data in test_data: 13 | n = data['n'] 14 | ar = data['ar'] 15 | expected = data['expected'] 16 | with self.subTest(n=n, ar=ar): 17 | self.assertEqual(sockMerchant(n, ar), expected) 18 | 19 | 20 | if __name__ == '__main__': 21 | unittest.main() 22 | -------------------------------------------------------------------------------- /problems/tests/test_sort_colors.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.sort_colors import Solution 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def setUp(self): 9 | self.solution = Solution() 10 | 11 | def test(self): 12 | test_data = [ 13 | {'nums': [2, 0, 2, 1, 1, 0]}, 14 | {'nums': [2, 0, 1]}, 15 | {'nums': [0, ]}, 16 | {'nums': [1, ]}, 17 | {'nums': []}, 18 | ] 19 | for data in test_data: 20 | nums = data['nums'] 21 | expected = sorted(nums.copy()) 22 | with self.subTest(nums=nums): 23 | self.solution.sortColors(nums) 24 | self.assertEqual(nums, expected) 25 | 26 | 27 | if __name__ == '__main__': 28 | unittest.main() 29 | -------------------------------------------------------------------------------- /problems/tests/test_three_sum.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.three_sum import Solution 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def setUp(self): 9 | self.solution = Solution() 10 | 11 | def test(self): 12 | nums = [-1, 0, 1, 2, -1, -4] 13 | expected = [[-1, 0, 1], [-1, -1, 2]] 14 | self.assertEqual(self.solution.threeSum(nums), expected) 15 | 16 | def test2(self): 17 | nums = [1, ] 18 | expected = [] 19 | self.assertEqual(self.solution.threeSum(nums), expected) 20 | 21 | def test3(self): 22 | nums = [0, 0, 0, 0] 23 | expected = [[0, 0, 0], ] 24 | self.assertEqual(self.solution.threeSum(nums), expected) 25 | 26 | 27 | if __name__ == '__main__': 28 | unittest.main() 29 | -------------------------------------------------------------------------------- /problems/tests/test_top_k_frequent_elements.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.top_k_frequent_elements import Solution 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def setUp(self): 9 | self.solution = Solution() 10 | 11 | def test(self): 12 | nums = [1, 1, 1, 2, 2, 3] 13 | k = 2 14 | expected = [1, 2] 15 | self.assertEqual(self.solution.topKFrequent(nums, k), expected) 16 | 17 | def test2(self): 18 | nums = [1, ] 19 | k = 1 20 | expected = [1, ] 21 | self.assertEqual(self.solution.topKFrequent(nums, k), expected) 22 | 23 | 24 | if __name__ == '__main__': 25 | unittest.main() 26 | -------------------------------------------------------------------------------- /problems/tests/test_trapping_rain_water.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.trapping_rain_water import Solution 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def setUp(self): 9 | self.solution = Solution() 10 | 11 | def test(self): 12 | test_data = [ 13 | {'height': [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1], 'expected': 6}, 14 | {'height': [4, 2, 0, 3, 2, 5], 'expected': 9}, 15 | {'height': [1, 1, 1], 'expected': 0}, 16 | ] 17 | for data in test_data: 18 | height = data['height'] 19 | expected = data['expected'] 20 | with self.subTest(height=height): 21 | self.assertEqual(self.solution.trap(height), expected) 22 | 23 | 24 | if __name__ == '__main__': 25 | unittest.main() 26 | -------------------------------------------------------------------------------- /problems/tests/test_two_characters.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.two_characters import alternate 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def test(self): 9 | test_data = [ 10 | {'s': 'beabeefeab', 'expected': 5}, 11 | {'s': 'asdcbsdcagfsdbgdfanfghbsfdab', 'expected': 8}, 12 | {'s': 'asvkugfiugsalddlasguifgukvsa', 'expected': 0}, 13 | ] 14 | for data in test_data: 15 | s = data['s'] 16 | expected = data['expected'] 17 | with self.subTest(s=s): 18 | self.assertEqual(alternate(s), expected) 19 | 20 | 21 | if __name__ == '__main__': 22 | unittest.main() 23 | -------------------------------------------------------------------------------- /problems/tests/test_two_sum_ii_input_array_is_sorted.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.two_sum_ii_input_array_is_sorted import Solution 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def setUp(self): 9 | self.solution = Solution() 10 | 11 | def test(self): 12 | test_data = [ 13 | {'numbers': [2, 7, 11, 15], 'target': 9, 'expected': [1, 2]}, 14 | {'numbers': [2, 3, 4], 'target': 6, 'expected': [1, 3]}, 15 | {'numbers': [-1, 0], 'target': -1, 'expected': [1, 2]}, 16 | {'numbers': [1, 2, 3, 4, 5, 6, 7, 19, 100, 222, 412], 'target': 13, 'expected': [6, 7]}, 17 | ] 18 | for data in test_data: 19 | numbers = data['numbers'] 20 | target = data['target'] 21 | expected = data['expected'] 22 | with self.subTest(numbers=numbers, target=target): 23 | self.assertEqual(self.solution.twoSum(numbers, target), expected) 24 | 25 | 26 | if __name__ == '__main__': 27 | unittest.main() 28 | -------------------------------------------------------------------------------- /problems/tests/test_univalued_binary_tree.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.univalued_binary_tree import Solution 5 | from problems.utils.leetcode import deserialize_tree_str 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def setUp(self): 10 | self.solution = Solution() 11 | 12 | def test(self): 13 | test_data = [ 14 | {'tree_str': '[1,1,1,1,1,null,1]', 'expected': True}, 15 | {'tree_str': '[2,2,2,5,2]', 'expected': False}, 16 | {'tree_str': '[1]', 'expected': True}, 17 | {'tree_str': '[]', 'expected': True}, 18 | ] 19 | for data in test_data: 20 | tree_str = data['tree_str'] 21 | expected = data['expected'] 22 | with self.subTest(tree_str=tree_str): 23 | root = deserialize_tree_str(tree_str) 24 | output = self.solution.isUnivalTree(root) 25 | self.assertEqual(output, expected) 26 | 27 | 28 | if __name__ == '__main__': 29 | unittest.main() 30 | -------------------------------------------------------------------------------- /problems/tests/test_valid_palindrome.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.valid_palindrome import Solution 5 | from problems.valid_palindrome import Solution2 6 | 7 | 8 | class TestCase(unittest.TestCase): 9 | def setUp(self): 10 | self.solution = Solution() 11 | 12 | def test(self): 13 | test_data = [ 14 | {'s': 'A man, a plan, a canal: Panama', 'expected': True}, 15 | {'s': 'race a car', 'expected': False}, 16 | {'s': '0P', 'expected': False}, 17 | {'s': '', 'expected': True}, 18 | ] 19 | for data in test_data: 20 | s = data['s'] 21 | expected = data['expected'] 22 | with self.subTest(s=s): 23 | self.assertEqual(self.solution.isPalindrome(s), expected) 24 | 25 | 26 | class TestCase2(unittest.TestCase): 27 | def setUp(self): 28 | self.solution = Solution2() 29 | 30 | def test(self): 31 | test_data = [ 32 | {'s': 'A man, a plan, a canal: Panama', 'expected': True}, 33 | {'s': 'race a car', 'expected': False}, 34 | {'s': '0P', 'expected': False}, 35 | {'s': '', 'expected': True}, 36 | ] 37 | for data in test_data: 38 | s = data['s'] 39 | expected = data['expected'] 40 | with self.subTest(s=s): 41 | self.assertEqual(self.solution.isPalindrome(s), expected) 42 | 43 | 44 | if __name__ == '__main__': 45 | unittest.main() 46 | -------------------------------------------------------------------------------- /problems/tests/test_valid_parentheses.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import unittest 3 | 4 | from problems.valid_parentheses import Solution 5 | 6 | 7 | class TestCase(unittest.TestCase): 8 | def setUp(self): 9 | self.solution = Solution() 10 | 11 | def test(self): 12 | test_data = [ 13 | {'s': '()[]{}', 'expected': True}, 14 | {'s': '{[]}', 'expected': True}, 15 | {'s': '([)]', 'expected': False}, 16 | {'s': ')(]', 'expected': False}, 17 | {'s': '){', 'expected': False}, 18 | {'s': '[', 'expected': False}, 19 | {'s': '}', 'expected': False}, 20 | ] 21 | for data in test_data: 22 | s = data['s'] 23 | expected = data['expected'] 24 | with self.subTest(s=s): 25 | self.assertEqual(self.solution.isValid(s), expected) 26 | 27 | 28 | if __name__ == '__main__': 29 | unittest.main() 30 | -------------------------------------------------------------------------------- /problems/third_maximum_number.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/third-maximum-number/ 4 | """ 5 | from typing import List 6 | import heapq 7 | 8 | 9 | class Solution: 10 | def thirdMax(self, nums: List[int]) -> int: 11 | sorted_nums = sorted(set(nums), reverse=True) 12 | third_max = None 13 | for i in range(3): 14 | try: 15 | third_max = sorted_nums[i] 16 | except IndexError: 17 | return sorted_nums[0] 18 | return third_max 19 | 20 | 21 | class Solution2: 22 | def thirdMax(self, nums: List[int]) -> int: 23 | max_heap = [] 24 | for num in nums: 25 | heapq.heappush(max_heap, -num) 26 | 27 | order = 0 28 | last_num = None 29 | for _ in range(len(nums)): 30 | num = -heapq.heappop(max_heap) 31 | if num != last_num: 32 | order += 1 33 | if order == 3: 34 | return num 35 | last_num = num 36 | 37 | return max(nums) 38 | 39 | 40 | class Solution3: 41 | def thirdMax(self, nums: List[int]) -> int: 42 | dedup_nums = set() 43 | max_heap = [] 44 | for num in nums: 45 | if num not in dedup_nums: 46 | dedup_nums.add(num) 47 | heapq.heappush(max_heap, -num) 48 | 49 | if len(max_heap) < 3: 50 | return -heapq.heappop(max_heap) 51 | else: 52 | third_max = None 53 | for _ in range(3): 54 | third_max = -heapq.heappop(max_heap) 55 | return third_max 56 | -------------------------------------------------------------------------------- /problems/three_sum.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/3sum/ 4 | """ 5 | from typing import List 6 | 7 | 8 | class Solution: 9 | def threeSum(self, nums: List[int]) -> List[List[int]]: 10 | dedup_set = set(nums) 11 | length_dedup_set = len(dedup_set) 12 | if length_dedup_set <= 1: 13 | if sum(dedup_set) == 0 and len(nums) >= 3: 14 | return [[0, 0, 0]] 15 | return [] 16 | 17 | nums.sort() 18 | 19 | # there might be multiple results 20 | def twoSum(nums, target): 21 | results = [] 22 | index_dict = {} 23 | for num in nums: 24 | complement = target - num 25 | if complement in index_dict: 26 | results.append([num, complement]) 27 | else: 28 | index_dict[num] = None 29 | return results 30 | 31 | results = [] 32 | results_set = set() 33 | first_nums = set() 34 | for i, num in enumerate(nums): 35 | if num in first_nums: 36 | continue 37 | else: 38 | first_nums.add(num) 39 | 40 | if num == 0: 41 | target = 0 42 | else: 43 | target = -num 44 | 45 | two_nums_lists = twoSum(nums[i + 1:], target) 46 | if two_nums_lists: 47 | for two_nums_list in two_nums_lists: 48 | result = sorted([num, ] + two_nums_list) 49 | result_tuple = tuple(result) 50 | if result_tuple not in results_set: 51 | results_set.add(result_tuple) 52 | results.append(result) 53 | 54 | return results 55 | -------------------------------------------------------------------------------- /problems/top_k_frequent_elements.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/top-k-frequent-elements/ 4 | """ 5 | from collections import Counter 6 | from typing import List 7 | 8 | 9 | class Solution: 10 | def topKFrequent(self, nums: List[int], k: int) -> List[int]: 11 | counter = Counter(nums) 12 | output = [] 13 | for num, _ in counter.most_common(k): 14 | output.append(num) 15 | 16 | return output 17 | -------------------------------------------------------------------------------- /problems/trapping_rain_water.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/trapping-rain-water/ 4 | """ 5 | from typing import List 6 | 7 | 8 | class Solution: 9 | def trap(self, height: List[int]) -> int: 10 | water = 0 11 | 12 | for i, h in enumerate(height): 13 | # Find the highest bar on the left side of the current index. 14 | max_left_h = 0 15 | for left_h in height[0:i]: 16 | if left_h > max_left_h: 17 | max_left_h = left_h 18 | 19 | # Find the highest bar on the right side of the current index. 20 | max_right_h = 0 21 | for right_h in height[i + 1:]: 22 | if right_h > max_right_h: 23 | max_right_h = right_h 24 | 25 | temp_water = min(max_left_h, max_right_h) - h 26 | if temp_water > 0: 27 | water += temp_water 28 | 29 | return water 30 | -------------------------------------------------------------------------------- /problems/tree_height_of_a_binary_tree.py: -------------------------------------------------------------------------------- 1 | #!/bin/python3 2 | """ 3 | https://www.hackerrank.com/challenges/tree-height-of-a-binary-tree/problem 4 | """ 5 | 6 | 7 | class Node: 8 | def __init__(self, info): 9 | self.info = info 10 | self.left = None 11 | self.right = None 12 | self.level = None 13 | 14 | def __str__(self): 15 | return str(self.info) 16 | 17 | 18 | class BinarySearchTree: 19 | def __init__(self): 20 | self.root = None 21 | 22 | def create(self, val): 23 | if self.root is None: 24 | self.root = Node(val) 25 | else: 26 | current = self.root 27 | 28 | while True: 29 | if val < current.info: 30 | if current.left: 31 | current = current.left 32 | else: 33 | current.left = Node(val) 34 | break 35 | elif val > current.info: 36 | if current.right: 37 | current = current.right 38 | else: 39 | current.right = Node(val) 40 | break 41 | else: 42 | break 43 | 44 | 45 | # Enter your code here. Read input from STDIN. Print output to STDOUT 46 | def height(root): 47 | if not root: 48 | return -1 49 | if (not root.left) and (not root.right): 50 | return 0 51 | 52 | return 1 + max(height(root.left), height(root.right)) 53 | 54 | 55 | tree = BinarySearchTree() 56 | t = int(input()) 57 | arr = list(map(int, input().split())) 58 | for i in range(t): 59 | tree.create(arr[i]) 60 | 61 | print(height(tree.root)) 62 | -------------------------------------------------------------------------------- /problems/two_characters.py: -------------------------------------------------------------------------------- 1 | #!/bin/python3 2 | """ 3 | https://www.hackerrank.com/challenges/two-characters/problem 4 | """ 5 | from collections import Counter 6 | import itertools 7 | import os 8 | 9 | 10 | def alternate(s): 11 | counter = Counter(s) 12 | 13 | max_length = 0 14 | for c1, c2 in itertools.combinations(set(s), 2): 15 | t_length = 0 16 | is_t_finished = False 17 | last_char = None 18 | for char in s: 19 | if char in (c1, c2): 20 | # If the total length of `c1` and `c2` is less than the current max length, we don't need to check this combination. 21 | if (counter[c1] + counter[c2]) <= max_length: 22 | break 23 | 24 | # If `char` is the same as `last_char`, the string is not alternating. 25 | if char == last_char: 26 | break 27 | 28 | t_length += 1 29 | last_char = char 30 | else: 31 | # If there is no `break` in this for loop. 32 | is_t_finished = True 33 | 34 | if is_t_finished and (t_length >= 2): 35 | max_length = max(max_length, t_length) 36 | 37 | return max_length 38 | 39 | 40 | if __name__ == '__main__': 41 | fptr = open(os.environ['OUTPUT_PATH'], 'w') 42 | 43 | _ = input() 44 | s = input() 45 | result = alternate(s) 46 | 47 | fptr.write(str(result) + '\n') 48 | fptr.close() 49 | -------------------------------------------------------------------------------- /problems/two_sum.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/two-sum/ 4 | """ 5 | from typing import List 6 | 7 | 8 | class Solution: 9 | def twoSum(self, nums: List[int], target: int) -> List[int]: 10 | # Is there duplicates in `nums`? 11 | for i, num1 in enumerate(nums): 12 | for j, num2 in enumerate(nums[i + 1:]): 13 | if num1 + num2 == target: 14 | real_index = j + i + 1 15 | return [i, real_index] 16 | 17 | 18 | class Solution2: 19 | def twoSum(self, nums: List[int], target: int) -> List[int]: 20 | mapping = { 21 | # num: index 22 | } 23 | for i, num in enumerate(nums): 24 | mapping[num] = i 25 | 26 | for i, num in enumerate(nums): 27 | another = target - num 28 | try: 29 | # We cannot use the same element twice, so both returned indexes must be distinct. 30 | another_i = mapping[another] 31 | if another_i == i: 32 | continue 33 | else: 34 | return [i, another_i] 35 | except KeyError: 36 | continue 37 | 38 | 39 | class Solution3: 40 | def twoSum(self, nums: List[int], target: int) -> List[int]: 41 | mapping = { 42 | # num: index 43 | } 44 | for i, num in enumerate(nums): 45 | another = target - num 46 | another_i = mapping.get(another) 47 | if another_i is not None: # NOTE: The index of another might be 0, so we cannot use `if another_i:`. 48 | return [another_i, i] 49 | mapping[num] = i 50 | -------------------------------------------------------------------------------- /problems/two_sum_ii_input_array_is_sorted.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/ 4 | """ 5 | from typing import List 6 | 7 | 8 | class Solution: 9 | def twoSum(self, numbers: List[int], target: int) -> List[int]: 10 | # NOTE: numbers is in increasing order. 11 | left = 0 # The left pointer starts from the leftmost index whose value is minimum. 12 | right = len(numbers) - 1 # The right pointer starts from the rightmost index whose value is maximum. 13 | while left < right: 14 | current_sum = numbers[left] + numbers[right] 15 | if current_sum == target: 16 | # Returned indexes are 1-based. 17 | return [left + 1, right + 1] 18 | elif current_sum < target: 19 | left += 1 20 | elif current_sum > target: 21 | right -= 1 22 | -------------------------------------------------------------------------------- /problems/univalued_binary_tree.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/univalued-binary-tree/ 4 | """ 5 | from collections import deque 6 | 7 | 8 | class TreeNode: # pragma: no cover 9 | def __init__(self, val=0, left=None, right=None): 10 | self.val = val 11 | self.left = left 12 | self.right = right 13 | 14 | 15 | class Solution: 16 | def isUnivalTree(self, root: TreeNode) -> bool: 17 | if not root: 18 | return True 19 | 20 | value = root.val 21 | queue = deque([root, ]) 22 | while queue: 23 | node = queue.popleft() 24 | if node: 25 | if node.val != value: 26 | return False 27 | 28 | queue.extend([node.left, node.right]) 29 | 30 | return True 31 | -------------------------------------------------------------------------------- /problems/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinta/fuck-coding-interviews/dfff746353781cf0fe8adbc886ff2dfd65e66d37/problems/utils/__init__.py -------------------------------------------------------------------------------- /problems/valid_anagram.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/valid-anagram/ 4 | https://algodaily.com/challenges/is-an-anagram 5 | """ 6 | from collections import Counter 7 | from collections import defaultdict 8 | 9 | 10 | class Solution: 11 | def isAnagram(self, s: str, t: str) -> bool: 12 | char_counts = defaultdict(int) 13 | for char in s: 14 | char_counts[char] += 1 15 | 16 | for char in t: 17 | char_counts[char] -= 1 18 | 19 | for value in char_counts.values(): 20 | if value != 0: 21 | return False 22 | 23 | return True 24 | 25 | 26 | class Solution2: 27 | def isAnagram(self, s: str, t: str) -> bool: 28 | if len(s) != len(t): 29 | return False 30 | 31 | char_counts = defaultdict(int) 32 | for s_char, t_char in zip(s, t): 33 | char_counts[s_char] += 1 34 | char_counts[t_char] -= 1 35 | 36 | for value in char_counts.values(): 37 | if value != 0: 38 | return False 39 | 40 | return True 41 | 42 | 43 | class Solution3: 44 | def isAnagram(self, s: str, t: str) -> bool: 45 | if len(s) != len(t): 46 | return False 47 | return sorted(s) == sorted(t) 48 | 49 | 50 | class Solution4: 51 | def isAnagram(self, s: str, t: str) -> bool: 52 | return Counter(s.lower()) == Counter(t.lower()) 53 | -------------------------------------------------------------------------------- /problems/valid_palindrome.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/valid-palindrome/ 4 | """ 5 | 6 | 7 | class Solution: 8 | def isPalindrome(self, s: str) -> bool: 9 | clean_s = ''.join(c for c in s if c.isalnum()).lower() 10 | # reversed_s = ''.join(reversed(clean_s)) 11 | reversed_s = clean_s[::-1] 12 | return clean_s == reversed_s 13 | 14 | 15 | # The Two-Pointer way. 16 | class Solution2: 17 | def isPalindrome(self, s: str) -> bool: 18 | clean_s = ''.join(c for c in s if c.isalnum()).lower() 19 | left = 0 20 | right = len(clean_s) - 1 21 | while left < right: 22 | if clean_s[left] != clean_s[right]: 23 | return False 24 | left += 1 25 | right -= 1 26 | 27 | return True 28 | -------------------------------------------------------------------------------- /problems/valid_parentheses.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | https://leetcode.com/problems/valid-parentheses/ 4 | """ 5 | 6 | 7 | class Solution: 8 | def isValid(self, s: str) -> bool: 9 | if (len(s) % 2) != 0: 10 | return False 11 | 12 | mapping = { 13 | '(': ')', 14 | '[': ']', 15 | '{': '}', 16 | } 17 | 18 | stack = [] 19 | 20 | for char in s: 21 | # If we find an opening bracket, we push it onto the stack. 22 | # Having it on the stack means we're waiting to close that particular bracket. 23 | if char in ['(', '{', '[']: 24 | stack.append(char) 25 | # If we find a closing bracket, we inspect the top element in the stack. We then analyze: 26 | elif char in [')', '}', ']']: 27 | # NOTE: The stack might be empty if there are unbalanced brackets. 28 | try: 29 | left = stack.pop() 30 | except IndexError: 31 | return False 32 | else: 33 | if char != mapping[left]: 34 | return False 35 | 36 | # If we make it to the end of the line and there's still something left on the stack, 37 | # that means there’s an opening bracket without a corresponding closing bracket 38 | if stack: 39 | return False 40 | 41 | return True 42 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "fuck-coding-interviews" 3 | version = "0.1.0" 4 | description = "How on earth can I ever think of a solution like that in an interview?!" 5 | authors = ["Vinta Chen "] 6 | license = "MIT" 7 | readme = "README.md" 8 | repository = "https://github.com/vinta/fuck-coding-interviews" 9 | keywords = [ 10 | "Algorithms", 11 | "Data Structures", 12 | "Coding Interviews", 13 | ] 14 | classifiers = [ 15 | "Development Status :: 3 - Alpha", 16 | "Intended Audience :: Developers", 17 | "Intended Audience :: Education", 18 | "Intended Audience :: Science/Research", 19 | "Operating System :: OS Independent", 20 | "Programming Language :: Python :: 3 :: Only", 21 | "Programming Language :: Python :: 3.6", 22 | "Programming Language :: Python :: 3.7", 23 | "Programming Language :: Python :: 3.8", 24 | "Programming Language :: Python :: Implementation", 25 | "Topic :: Education", 26 | "Topic :: Software Development", 27 | "Topic :: Utilities", 28 | ] 29 | 30 | [tool.poetry.dependencies] 31 | python = "^3.6" 32 | 33 | [tool.poetry.dev-dependencies] 34 | binarytree = "==5.1.0" 35 | networkx = "^2.5" 36 | pytest = "==6.1.1" 37 | pytest-benchmark = "==3.2.3" 38 | pytest-cov = "==2.10.1" 39 | pythonds3 = "==3.0.3" 40 | 41 | [build-system] 42 | requires = ["poetry>=0.12"] 43 | build-backend = "poetry.masonry.api" 44 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | python_files = 3 | test_*.py 4 | benchmark_*.py 5 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | binarytree==5.1.0 2 | networkx==2.5 3 | pytest==6.1.1 4 | pytest-benchmark==3.2.3 5 | pytest-cov==2.10.1 6 | pythonds3==3.0.3 7 | --------------------------------------------------------------------------------