diff --git a/.coveragerc b/.coveragerc index a5f7fcee8..c42e2db7a 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,5 +1,6 @@ [report] omit = + */tests/* */python?.?/* */site-packages/nose/* *__init__* diff --git a/README.md b/README.md index 65caeb5ca..aeed168f3 100644 --- a/README.md +++ b/README.md @@ -1,424 +1,303 @@ -[![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) -[![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) -[![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) -[![Coverage Status](https://coveralls.io/repos/github/keon/algorithms/badge.svg?branch=master)](https://coveralls.io/github/keon/algorithms?branch=master) - -

- -Pythonic Data Structures and Algorithms -========================================= - -Minimal and clean example implementations of data structures and algorithms in Python 3. - -## Contributing -Thanks for your interest in contributing! There are many ways to contribute to this project. [Get started here](CONTRIBUTING.md) - -## Tests - -### Use unittest -For running all tests write down: - - $ python3 -m unittest discover tests - -For running some specific tests you can do this as following (Ex: sort): - - $ python3 -m unittest tests.test_sort - -### Use pytest -For running all tests write down: - - $ python3 -m pytest tests - -## Install -If you want to use the API algorithms in your code, it is as simple as: - - $ pip3 install algorithms - -You can test by creating a python file: (Ex: use `merge_sort` in `sort`) - -```python3 -from algorithms.sort import merge_sort - -if __name__ == "__main__": - my_list = [1, 8, 3, 5, 6] - my_list = merge_sort(my_list) - print(my_list) -``` - -## Uninstall -If you want to uninstall algorithms, it is as simple as: - - $ pip3 uninstall -y algorithms - -## List of Implementations - -- [arrays](algorithms/arrays) - - [delete_nth](algorithms/arrays/delete_nth.py) - - [flatten](algorithms/arrays/flatten.py) - - [garage](algorithms/arrays/garage.py) - - [josephus_problem](algorithms/arrays/josephus.py) - - [limit](algorithms/arrays/limit.py) - - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) - - [max_ones_index](algorithms/arrays/max_ones_index.py) - - [merge_intervals](algorithms/arrays/merge_intervals.py) - - [missing_ranges](algorithms/arrays/missing_ranges.py) - - [plus_one](algorithms/arrays/plus_one.py) - - [remove_duplicates](algorithms/arrays/remove_duplicates.py) - - [rotate](algorithms/arrays/rotate.py) - - [summarize_ranges](algorithms/arrays/summarize_ranges.py) - - [three_sum](algorithms/arrays/three_sum.py) - - [trimmean](algorithms/arrays/trimmean.py) - - [top_1](algorithms/arrays/top_1.py) - - [two_sum](algorithms/arrays/two_sum.py) - - [move_zeros](algorithms/arrays/move_zeros.py) - - [n_sum](algorithms/arrays/n_sum.py) -- [greedy](algorithms/greedy/) - - [max_contiguous_subsequence_sum](algorithms/greedy/max_contiguous_subsequence_sum.py) -- [automata](algorithms/automata) - - [DFA](algorithms/automata/dfa.py) -- [backtrack](algorithms/backtrack) - - [general_solution.md](algorithms/backtrack/) - - [add_operators](algorithms/backtrack/add_operators.py) - - [anagram](algorithms/backtrack/anagram.py) - - [array_sum_combinations](algorithms/backtrack/array_sum_combinations.py) - - [combination_sum](algorithms/backtrack/combination_sum.py) - - [factor_combinations](algorithms/backtrack/factor_combinations.py) - - [generate_abbreviations](algorithms/backtrack/generate_abbreviations.py) - - [generate_parenthesis](algorithms/backtrack/generate_parenthesis.py) - - [letter_combination](algorithms/backtrack/letter_combination.py) - - [palindrome_partitioning](algorithms/backtrack/palindrome_partitioning.py) - - [pattern_match](algorithms/backtrack/pattern_match.py) - - [permute](algorithms/backtrack/permute.py) - - [permute_unique](algorithms/backtrack/permute_unique.py) - - [subsets](algorithms/backtrack/subsets.py) - - [subsets_unique](algorithms/backtrack/subsets_unique.py) -- [bfs](algorithms/bfs) - - [maze_search](algorithms/bfs/maze_search.py) - - [shortest_distance_from_all_buildings](algorithms/bfs/shortest_distance_from_all_buildings.py) - - [word_ladder](algorithms/bfs/word_ladder.py) -- [bit](algorithms/bit) - - [add_bitwise_operator](algorithms/bit/add_bitwise_operator.py) - - [bit_operation](algorithms/bit/bit_operation.py) - - [bytes_int_conversion](algorithms/bit/bytes_int_conversion.py) - - [count_flips_to_convert](algorithms/bit/count_flips_to_convert.py) - - [count_ones](algorithms/bit/count_ones.py) - - [find_difference](algorithms/bit/find_difference.py) - - [find_missing_number](algorithms/bit/find_missing_number.py) - - [flip_bit_longest_sequence](algorithms/bit/flip_bit_longest_sequence.py) - - [power_of_two](algorithms/bit/power_of_two.py) - - [reverse_bits](algorithms/bit/reverse_bits.py) - - [single_number](algorithms/bit/single_number.py) - - [single_number2](algorithms/bit/single_number2.py) - - [single_number3](algorithms/bit/single_number3.py) - - [subsets](algorithms/bit/subsets.py) - - [swap_pair](algorithms/bit/swap_pair.py) - - [has_alternative_bit](algorithms/bit/has_alternative_bit.py) - - [insert_bit](algorithms/bit/insert_bit.py) - - [remove_bit](algorithms/bit/remove_bit.py) - - [binary_gap](algorithms/bit/binary_gap.py) -- [compression](algorithms/compression) - - [huffman_coding](algorithms/compression/huffman_coding.py) - - [rle_compression](algorithms/compression/rle_compression.py) - - [elias](algorithms/compression/elias.py) -- [dfs](algorithms/dfs) - - [all_factors](algorithms/dfs/all_factors.py) - - [count_islands](algorithms/dfs/count_islands.py) - - [pacific_atlantic](algorithms/dfs/pacific_atlantic.py) - - [sudoku_solver](algorithms/dfs/sudoku_solver.py) - - [walls_and_gates](algorithms/dfs/walls_and_gates.py) -- [distribution](algorithms/distribution) - - [histogram](algorithms/distribution/histogram.py) -- [dp](algorithms/dp) - - [buy_sell_stock](algorithms/dp/buy_sell_stock.py) - - [climbing_stairs](algorithms/dp/climbing_stairs.py) - - [coin_change](algorithms/dp/coin_change.py) - - [combination_sum](algorithms/dp/combination_sum.py) - - [egg_drop](algorithms/dp/egg_drop.py) - - [house_robber](algorithms/dp/house_robber.py) - - [int_divide](algorithms/dp/int_divide.py) - - [job_scheduling](algorithms/dp/job_scheduling.py) - - [knapsack](algorithms/dp/knapsack.py) - - [longest_increasing](algorithms/dp/longest_increasing.py) - - [matrix_chain_order](algorithms/dp/matrix_chain_order.py) - - [max_product_subarray](algorithms/dp/max_product_subarray.py) - - [max_subarray](algorithms/dp/max_subarray.py) - - [min_cost_path](algorithms/dp/min_cost_path.py) - - [num_decodings](algorithms/dp/num_decodings.py) - - [regex_matching](algorithms/dp/regex_matching.py) - - [rod_cut](algorithms/dp/rod_cut.py) - - [word_break](algorithms/dp/word_break.py) - - [fibonacci](algorithms/dp/fib.py) - - [hosoya triangle](algorithms/dp/hosoya_triangle.py) - - [K-Factor_strings](algorithms/dp/k_factor.py) - - [planting_trees](algorithms/dp/planting_trees.py) -- [graph](algorithms/graph) - - [check_bipartite](algorithms/graph/check_bipartite.py) - - [strongly_connected](algorithms/graph/check_digraph_strongly_connected.py) - - [clone_graph](algorithms/graph/clone_graph.py) - - [cycle_detection](algorithms/graph/cycle_detection.py) - - [find_all_cliques](algorithms/graph/find_all_cliques.py) - - [find_path](algorithms/graph/find_path.py) - - [graph](algorithms/graph/graph.py) - - [dijkstra](algorithms/graph/dijkstra.py) - - [markov_chain](algorithms/graph/markov_chain.py) - - [minimum_spanning_tree](algorithms/graph/minimum_spanning_tree.py) - - [satisfiability](algorithms/graph/satisfiability.py) - - [minimum_spanning_tree_prims](algorithms/graph/prims_minimum_spanning.py) - - [tarjan](algorithms/graph/tarjan.py) - - [traversal](algorithms/graph/traversal.py) - - [maximum_flow](algorithms/graph/maximum_flow.py) - - [maximum_flow_bfs](algorithms/graph/maximum_flow_bfs.py) - - [maximum_flow_dfs](algorithms/graph/maximum_flow_dfs.py) - - [all_pairs_shortest_path](algorithms/graph/all_pairs_shortest_path.py) - - [bellman_ford](algorithms/graph/bellman_ford.py) - - [Count Connected Components](algorithms/graph/count_connected_number_of_component.py) -- [heap](algorithms/heap) - - [merge_sorted_k_lists](algorithms/heap/merge_sorted_k_lists.py) - - [skyline](algorithms/heap/skyline.py) - - [sliding_window_max](algorithms/heap/sliding_window_max.py) - - [binary_heap](algorithms/heap/binary_heap.py) - - [k_closest_points](algorithms/heap/k_closest_points.py) -- [linkedlist](algorithms/linkedlist) - - [add_two_numbers](algorithms/linkedlist/add_two_numbers.py) - - [copy_random_pointer](algorithms/linkedlist/copy_random_pointer.py) - - [delete_node](algorithms/linkedlist/delete_node.py) - - [first_cyclic_node](algorithms/linkedlist/first_cyclic_node.py) - - [is_cyclic](algorithms/linkedlist/is_cyclic.py) - - [is_palindrome](algorithms/linkedlist/is_palindrome.py) - - [kth_to_last](algorithms/linkedlist/kth_to_last.py) - - [linkedlist](algorithms/linkedlist/linkedlist.py) - - [remove_duplicates](algorithms/linkedlist/remove_duplicates.py) - - [reverse](algorithms/linkedlist/reverse.py) - - [rotate_list](algorithms/linkedlist/rotate_list.py) - - [swap_in_pairs](algorithms/linkedlist/swap_in_pairs.py) - - [is_sorted](algorithms/linkedlist/is_sorted.py) - - [remove_range](algorithms/linkedlist/remove_range.py) -- [map](algorithms/map) - - [hashtable](algorithms/map/hashtable.py) - - [separate_chaining_hashtable](algorithms/map/separate_chaining_hashtable.py) - - [longest_common_subsequence](algorithms/map/longest_common_subsequence.py) - - [longest_palindromic_subsequence](algorithms/map/longest_palindromic_subsequence.py) - - [randomized_set](algorithms/map/randomized_set.py) - - [valid_sudoku](algorithms/map/valid_sudoku.py) - - [word_pattern](algorithms/map/word_pattern.py) - - [is_isomorphic](algorithms/map/is_isomorphic.py) - - [is_anagram](algorithms/map/is_anagram.py) -- [maths](algorithms/maths) - - [base_conversion](algorithms/maths/base_conversion.py) - - [chinese_remainder_theorem](algorithms/maths/chinese_remainder_theorem.py) - - [combination](algorithms/maths/combination.py) - - [cosine_similarity](algorithms/maths/cosine_similarity.py) - - [decimal_to_binary_ip](algorithms/maths/decimal_to_binary_ip.py) - - [diffie_hellman_key_exchange](algorithms/maths/diffie_hellman_key_exchange.py) - - [euler_totient](algorithms/maths/euler_totient.py) - - [extended_gcd](algorithms/maths/extended_gcd.py) - - [factorial](algorithms/maths/factorial.py) - - [find_order](algorithms/maths/find_order_simple.py) - - [find_primitive_root](algorithms/maths/find_primitive_root_simple.py) - - [gcd/lcm](algorithms/maths/gcd.py) - - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) - - [hailstone](algorithms/maths/hailstone.py) - - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) - - [krishnamurthy_number](algorithms/maths/krishnamurthy_number.py) - - [magic_number](algorithms/maths/magic_number.py) - - [modular_exponential](algorithms/maths/modular_exponential.py) - - [modular_inverse](algorithms/maths/modular_inverse.py) - - [next_bigger](algorithms/maths/next_bigger.py) - - [next_perfect_square](algorithms/maths/next_perfect_square.py) - - [nth_digit](algorithms/maths/nth_digit.py) - - [num_perfect_squares](algorithms/maths/num_perfect_squares.py) - - [polynomial](algorithms/maths/polynomial.py) - - [power](algorithms/maths/power.py) - - [prime_check](algorithms/maths/prime_check.py) - - [primes_sieve_of_eratosthenes](algorithms/maths/primes_sieve_of_eratosthenes.py) - - [pythagoras](algorithms/maths/pythagoras.py) - - [rabin_miller](algorithms/maths/rabin_miller.py) - - [recursive_binomial_coefficient](algorithms/maths/recursive_binomial_coefficient.py) - - [rsa](algorithms/maths/rsa.py) - - [sqrt_precision_factor](algorithms/maths/sqrt_precision_factor.py) - - [summing_digits](algorithms/maths/summing_digits.py) - - [symmetry_group_cycle_index](algorithms/maths/symmetry_group_cycle_index.py) -- [matrix](algorithms/matrix) - - [sudoku_validator](algorithms/matrix/sudoku_validator.py) - - [bomb_enemy](algorithms/matrix/bomb_enemy.py) - - [copy_transform](algorithms/matrix/copy_transform.py) - - [count_paths](algorithms/matrix/count_paths.py) - - [matrix_exponentiation](algorithms/matrix/matrix_exponentiation.py) - - [matrix_inversion](algorithms/matrix/matrix_inversion.py) - - [matrix_multiplication](algorithms/matrix/multiply.py) - - [rotate_image](algorithms/matrix/rotate_image.py) - - [search_in_sorted_matrix](algorithms/matrix/search_in_sorted_matrix.py) - - [sparse_dot_vector](algorithms/matrix/sparse_dot_vector.py) - - [sparse_mul](algorithms/matrix/sparse_mul.py) - - [spiral_traversal](algorithms/matrix/spiral_traversal.py) - - [crout_matrix_decomposition](algorithms/matrix/crout_matrix_decomposition.py) - - [cholesky_matrix_decomposition](algorithms/matrix/cholesky_matrix_decomposition.py) - - [sum_sub_squares](algorithms/matrix/sum_sub_squares.py) - - [sort_matrix_diagonally](algorithms/matrix/sort_matrix_diagonally.py) -- [queues](algorithms/queues) - - [max_sliding_window](algorithms/queues/max_sliding_window.py) - - [moving_average](algorithms/queues/moving_average.py) - - [queue](algorithms/queues/queue.py) - - [reconstruct_queue](algorithms/queues/reconstruct_queue.py) - - [zigzagiterator](algorithms/queues/zigzagiterator.py) -- [search](algorithms/search) - - [binary_search](algorithms/search/binary_search.py) - - [first_occurrence](algorithms/search/first_occurrence.py) - - [last_occurrence](algorithms/search/last_occurrence.py) - - [linear_search](algorithms/search/linear_search.py) - - [search_insert](algorithms/search/search_insert.py) - - [two_sum](algorithms/search/two_sum.py) - - [search_range](algorithms/search/search_range.py) - - [find_min_rotate](algorithms/search/find_min_rotate.py) - - [search_rotate](algorithms/search/search_rotate.py) - - [jump_search](algorithms/search/jump_search.py) - - [next_greatest_letter](algorithms/search/next_greatest_letter.py) - - [interpolation_search](algorithms/search/interpolation_search.py) -- [set](algorithms/set) - - [randomized_set](algorithms/set/randomized_set.py) - - [set_covering](algorithms/set/set_covering.py) - - [find_keyboard_row](algorithms/set/find_keyboard_row.py) -- [sort](algorithms/sort) - - [bitonic_sort](algorithms/sort/bitonic_sort.py) - - [bogo_sort](algorithms/sort/bogo_sort.py) - - [bubble_sort](algorithms/sort/bubble_sort.py) - - [bucket_sort](algorithms/sort/bucket_sort.py) - - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) - - [comb_sort](algorithms/sort/comb_sort.py) - - [counting_sort](algorithms/sort/counting_sort.py) - - [cycle_sort](algorithms/sort/cycle_sort.py) - - [exchange_sort](algorithms/sort/exchange_sort.py) - - [gnome_sort](algorithms/sort/gnome_sort.py) - - [heap_sort](algorithms/sort/heap_sort.py) - - [insertion_sort](algorithms/sort/insertion_sort.py) - - [meeting_rooms](algorithms/sort/meeting_rooms.py) - - [merge_sort](algorithms/sort/merge_sort.py) - - [pancake_sort](algorithms/sort/pancake_sort.py) - - [pigeonhole_sort](algorithms/sort/pigeonhole_sort.py) - - [quick_sort](algorithms/sort/quick_sort.py) - - [radix_sort](algorithms/sort/radix_sort.py) - - [selection_sort](algorithms/sort/selection_sort.py) - - [shell_sort](algorithms/sort/shell_sort.py) - - [sort_colors](algorithms/sort/sort_colors.py) - - [stooge_sort](algorithms/sort/stooge_sort.py) - - [top_sort](algorithms/sort/top_sort.py) - - [wiggle_sort](algorithms/sort/wiggle_sort.py) -- [stack](algorithms/stack) - - [longest_abs_path](algorithms/stack/longest_abs_path.py) - - [simplify_path](algorithms/stack/simplify_path.py) - - [stack](algorithms/stack/stack.py) - - [valid_parenthesis](algorithms/stack/valid_parenthesis.py) - - [stutter](algorithms/stack/stutter.py) - - [switch_pairs](algorithms/stack/switch_pairs.py) - - [is_consecutive](algorithms/stack/is_consecutive.py) - - [remove_min](algorithms/stack/remove_min.py) - - [is_sorted](algorithms/stack/is_sorted.py) -- [streaming](algorithms/streaming) - - [1-sparse-recovery](algorithms/streaming/one_sparse_recovery.py) - - [misra-gries](algorithms/streaming/misra_gries.py) -- [strings](algorithms/strings) - - [fizzbuzz](algorithms/strings/fizzbuzz.py) - - [delete_reoccurring](algorithms/strings/delete_reoccurring.py) - - [strip_url_params](algorithms/strings/strip_url_params.py) - - [validate_coordinates](algorithms/strings/validate_coordinates.py) - - [domain_extractor](algorithms/strings/domain_extractor.py) - - [merge_string_checker](algorithms/strings/merge_string_checker.py) - - [add_binary](algorithms/strings/add_binary.py) - - [breaking_bad](algorithms/strings/breaking_bad.py) - - [decode_string](algorithms/strings/decode_string.py) - - [encode_decode](algorithms/strings/encode_decode.py) - - [group_anagrams](algorithms/strings/group_anagrams.py) - - [int_to_roman](algorithms/strings/int_to_roman.py) - - [is_palindrome](algorithms/strings/is_palindrome.py) - - [license_number](algorithms/strings/license_number.py) - - [make_sentence](algorithms/strings/make_sentence.py) - - [multiply_strings](algorithms/strings/multiply_strings.py) - - [one_edit_distance](algorithms/strings/one_edit_distance.py) - - [rabin_karp](algorithms/strings/rabin_karp.py) - - [reverse_string](algorithms/strings/reverse_string.py) - - [reverse_vowel](algorithms/strings/reverse_vowel.py) - - [reverse_words](algorithms/strings/reverse_words.py) - - [roman_to_int](algorithms/strings/roman_to_int.py) - - [word_squares](algorithms/strings/word_squares.py) - - [unique_morse](algorithms/strings/unique_morse.py) - - [judge_circle](algorithms/strings/judge_circle.py) - - [strong_password](algorithms/strings/strong_password.py) - - [caesar_cipher](algorithms/strings/caesar_cipher.py) - - [check_pangram](algorithms/strings/check_pangram.py) - - [contain_string](algorithms/strings/contain_string.py) - - [count_binary_substring](algorithms/strings/count_binary_substring.py) - - [repeat_string](algorithms/strings/repeat_string.py) - - [min_distance](algorithms/strings/min_distance.py) - - [longest_common_prefix](algorithms/strings/longest_common_prefix.py) - - [rotate](algorithms/strings/rotate.py) - - [first_unique_char](algorithms/strings/first_unique_char.py) - - [repeat_substring](algorithms/strings/repeat_substring.py) - - [atbash_cipher](algorithms/strings/atbash_cipher.py) - - [longest_palindromic_substring](algorithms/strings/longest_palindromic_substring.py) - - [knuth_morris_pratt](algorithms/strings/knuth_morris_pratt.py) - - [panagram](algorithms/strings/panagram.py) -- [tree](algorithms/tree) - - [bst](algorithms/tree/bst) - - [array_to_bst](algorithms/tree/bst/array_to_bst.py) - - [bst_closest_value](algorithms/tree/bst/bst_closest_value.py) - - [BSTIterator](algorithms/tree/bst/BSTIterator.py) - - [delete_node](algorithms/tree/bst/delete_node.py) - - [is_bst](algorithms/tree/bst/is_bst.py) - - [kth_smallest](algorithms/tree/bst/kth_smallest.py) - - [lowest_common_ancestor](algorithms/tree/bst/lowest_common_ancestor.py) - - [predecessor](algorithms/tree/bst/predecessor.py) - - [serialize_deserialize](algorithms/tree/bst/serialize_deserialize.py) - - [successor](algorithms/tree/bst/successor.py) - - [unique_bst](algorithms/tree/bst/unique_bst.py) - - [depth_sum](algorithms/tree/bst/depth_sum.py) - - [count_left_node](algorithms/tree/bst/count_left_node.py) - - [num_empty](algorithms/tree/bst/num_empty.py) - - [height](algorithms/tree/bst/height.py) - - [fenwick_tree](algorithms/tree/fenwick_tree/fenwick_tree.py) - - [red_black_tree](algorithms/tree/red_black_tree) - - [red_black_tree](algorithms/tree/red_black_tree/red_black_tree.py) - - [segment_tree](algorithms/tree/segment_tree) - - [segment_tree](algorithms/tree/segment_tree/segment_tree.py) - - [iterative_segment_tree](algorithms/tree/segment_tree/iterative_segment_tree.py) - - [traversal](algorithms/tree/traversal) - - [inorder](algorithms/tree/traversal/inorder.py) - - [level_order](algorithms/tree/traversal/level_order.py) - - [postorder](algorithms/tree/traversal/postorder.py) - - [preorder](algorithms/tree/traversal/preorder.py) - - [zigzag](algorithms/tree/traversal/zigzag.py) - - [trie](algorithms/tree/trie) - - [add_and_search](algorithms/tree/trie/add_and_search.py) - - [trie](algorithms/tree/trie/trie.py) - - [b_tree](algorithms/tree/b_tree.py) - - [binary_tree_paths](algorithms/tree/binary_tree_paths.py) - - [bin_tree_to_list](algorithms/tree/bin_tree_to_list.py) - - [construct_tree_preorder_postorder](algorithms/tree/construct_tree_postorder_preorder.py) - - [deepest_left](algorithms/tree/deepest_left.py) - - [invert_tree](algorithms/tree/invert_tree.py) - - [is_balanced](algorithms/tree/is_balanced.py) - - [is_subtree](algorithms/tree/is_subtree.py) - - [is_symmetric](algorithms/tree/is_symmetric.py) - - [longest_consecutive](algorithms/tree/longest_consecutive.py) - - [lowest_common_ancestor](algorithms/tree/lowest_common_ancestor.py) - - [max_height](algorithms/tree/max_height.py) - - [max_path_sum](algorithms/tree/max_path_sum.py) - - [min_height](algorithms/tree/min_height.py) - - [path_sum](algorithms/tree/path_sum.py) - - [path_sum2](algorithms/tree/path_sum2.py) - - [pretty_print](algorithms/tree/pretty_print.py) - - [same_tree](algorithms/tree/same_tree.py) - - [tree](algorithms/tree/tree.py) -- [unix](algorithms/unix) - - [path](algorithms/unix/path/) - - [join_with_slash](algorithms/unix/path/join_with_slash.py) - - [full_path](algorithms/unix/path/full_path.py) - - [split](algorithms/unix/path/split.py) - - [simplify_path](algorithms/unix/path/simplify_path.py) -- [unionfind](algorithms/unionfind) - - [count_islands](algorithms/unionfind/count_islands.py) - - -## Contributors - -Thanks to [all the contributors](https://github.com/keon/algorithms/graphs/contributors) -who helped in building the repo. +# Report for Assignment 1 + +## Project chosen + +Name: algorithms + +URL: (https://github.com/keon/algorithms) + +Number of lines of code and the tool used to count it: 18023(18 KLOC), counted using lizard + +Programming language: Python + +## Coverage measurement + +### Existing tool + +We have used coverage.py to measure the cover of our chosen project. After installing all tools and dependencies, we have +run the tool by typing coverage run --branch -m pytest tests. Afterwards, we use coverage report to generate the report. Later, Ayman has written a scrip to run the commands in a single script, and to also skip the test files, which don't need to be tested. + +In order to not put in 8 large images, I will insert the final screenshot, with the total branch coverage: +![image](https://github.com/CatalinAnt/algorithms-SEP-95/assets/113595149/f1cd3fab-b00c-4cd0-89d0-6452e7ed1a63) + + +### Your own coverage tool + +#### Ayman Errahmouni + +##### Function 1: simplify_path_v2 + +[Link the commit](https://github.com/CatalinAnt/algorithms-SEP-95/pull/2/commits/22ee6fa1df4785596c603af61a725c558973eb0b) + +Screenshot of branch measurement:
+![image](image-7.png) + +##### Function 2: insertion_sort + +[Link to commit](https://github.com/CatalinAnt/algorithms-SEP-95/pull/2/commits/5dae7f28036f89b7f6ff673639a922dd714aff3e) + +Screenshot of branch measurement:
+![alt text](image-12.png) + +#### Catalin Antonescu + +##### Function 1: strong_password + +Link to commit: +[https://github.com/CatalinAnt/algorithms-SEP-95/commit/eaad6d32ecd73bb8fde876a4d4852cb522aea6f8](https://github.com/CatalinAnt/algorithms-SEP-95/commit/2b0b9187c1c040e4476b1ca14f2c2249273566b7) + +Screenshot of branch measurement: +![image](https://github.com/CatalinAnt/algorithms-SEP-95/assets/113595149/e718a47f-5ea0-412c-b250-25a193412164) + +##### Function 2: rotate_image + +Link to commit:(same as for the first one) +[https://github.com/CatalinAnt/algorithms-SEP-95/commit/eaad6d32ecd73bb8fde876a4d4852cb522aea6f8](https://github.com/CatalinAnt/algorithms-SEP-95/commit/2b0b9187c1c040e4476b1ca14f2c2249273566b7) + +Screenshot of branch measurement: +![image](https://github.com/CatalinAnt/algorithms-SEP-95/assets/113595149/94eec9b6-3dd6-46e3-b087-40892eccc10e) + +#### Almuthana Almustafa + +##### Function 1: stoogsort in stoog_sort.py + +[Link to the commit in the founction files](https://github.com/CatalinAnt/algorithms-SEP-95/commit/57b66879c6ae0f82712c55528f540dfdb3c3ddd3) + +result: + +![alt text](result_image-2.png) + +##### Function 2: word_break in word_break.py + +link to commit in founction: +[Link to the commit in the founction files](https://github.com/CatalinAnt/algorithms-SEP-95/commit/57b66879c6ae0f82712c55528f540dfdb3c3ddd3 ) + +result: + +![alt text](result_image_2.png) + +## Coverage improvement + +### Individual tests + +## Ayman Errahmouni + +#### + +An enhanced existing test + +Old coverage:
+![old coverage result (24%)](image-2.png) + +Diff (LHS = new code, RHS = old code):
+![LHS: new code, RHS: old code](image.png) +![alt text](image-9.png) + +New coverage:
+![new coverage result (100%)](image-1.png) + +The coverage was improved because certain cases that could happen in file paths (e.g. the "." directory, empty path) were not tested for. +By added additional tests that use such cases, the coverage improved. + +The test was also faulty on windows (i guess linux was assumed), so i added support for that in the test. (It now passes on Windows 10 too) + +#### + +An new test. (before, `insertion_sort` was not present in any test) + +Diff (LHS: new code, RHS: old code):
+(New test)
+![LHS: new code, RHS: old code](image-5.png)
+(Changes in imports)
+![LHS: new code, RHS: old code](image-6.png) +(Instrumentation)
+![alt text](image-8.png) + +Old coverage:
+![Old coverage result (4%)](image-3.png) + +New coverage:
+![alt text](image-4.png) + + + +## Catalin Antonescu + +Test 1: + +In test_string: + +Link to commit: + +[https://github.com/CatalinAnt/algorithms-SEP-95/commit/eaad6d32ecd73bb8fde876a4d4852cb522aea6f8](https://github.com/CatalinAnt/algorithms-SEP-95/commit/2b0b9187c1c040e4476b1ca14f2c2249273566b7) + +Old coverage: + +![image](https://github.com/CatalinAnt/algorithms-SEP-95/assets/113595149/5ea3487d-f024-45e6-a1e7-e6d9d1d953b7) +![image](https://github.com/CatalinAnt/algorithms-SEP-95/assets/113595149/e718a47f-5ea0-412c-b250-25a193412164) + +New coverage: + +![image](https://github.com/CatalinAnt/algorithms-SEP-95/assets/113595149/1d179cc4-1179-40e2-b344-5e904e899647) +![image](https://github.com/CatalinAnt/algorithms-SEP-95/assets/113595149/c8173a47-bcc9-4b6a-9a91-c70b5a8b002f) + +For strong_password there was a 26% coverage improvement with the existing tool and 40% with manual measurement tool. + +Test 2: + +In test_matrix: + +[https://github.com/CatalinAnt/algorithms-SEP-95/commit/eaad6d32ecd73bb8fde876a4d4852cb522aea6f8](https://github.com/CatalinAnt/algorithms-SEP-95/commit/2b0b9187c1c040e4476b1ca14f2c2249273566b7) + +Old coverage: + +![image](https://github.com/CatalinAnt/algorithms-SEP-95/assets/113595149/94eec9b6-3dd6-46e3-b087-40892eccc10e) +![image](https://github.com/CatalinAnt/algorithms-SEP-95/assets/113595149/a97a2bd6-c69e-4435-a8e2-bbdefc429bd1) + + +New coverage: + +![image](https://github.com/CatalinAnt/algorithms-SEP-95/assets/113595149/7cc337eb-5684-40b3-aedd-dc2b7180b7f3) +![image](https://github.com/CatalinAnt/algorithms-SEP-95/assets/113595149/2143adff-e0aa-4113-858a-0c92ec288d20) + For rotate_image, thre was a 33% coverage improvement with the existing tool and 25% with manual tool. + +## Almuthana Almustafa + +### Test 1: stoogsort + + + +link to commit in test files: +[Link to the commit in the test files](https://github.com/CatalinAnt/algorithms-SEP-95/commit/157de36fd4c373b67cd03e3b3713be9ba5cf0d97) + +existing tool result before: + +![alt text](stoog_sort_image1.png) + +existing tool result after: + +![alt text](stoog_sort_image2.png) + +The coverage increased by 89%, largely attributable to the implementation of new tests. + +### Test 2: word_break + +[Link to the commit in the test files](https://github.com/CatalinAnt/algorithms-SEP-95/commit/157de36fd4c373b67cd03e3b3713be9ba5cf0d97) + +existing tool result before: + +![alt text](word_break_image1.png) + +existing tool result after: + +![alt text](word_break_image2.png) + +The coverage improved by 86% due to the creation of new tests. + + + + + + + + + + + + + + + + + + + + + + + + +#### Abdullah Abdelkhalik + + +pythagoras + +https://github.com/CatalinAnt/algorithms-SEP-95/commit/5651abafebe8ae3a5ea63e74883bb991acf19303 + +![pythagoras_hits](https://github.com/CatalinAnt/algorithms-SEP-95/assets/114078193/c61bff67-be7e-4bd2-b892-0a0f2dada1f3) + + + + +first_unique_char + +https://github.com/CatalinAnt/algorithms-SEP-95/commit/c16f26e952322b2c1729778a4141a57103ba7658 + +![first_unique_char_hits (2)](https://github.com/CatalinAnt/algorithms-SEP-95/assets/114078193/8c1b704e-cadb-4f54-aea7-795005348538) + + + + + +## Improvements + +test_maths + +https://github.com/CatalinAnt/algorithms-SEP-95/commit/60832d9c672efd586848077cc41a52630d34371b + +![pythagoras_before](https://github.com/CatalinAnt/algorithms-SEP-95/assets/114078193/cf57112b-1aef-4a10-a41f-bd4b797e2012) + +![pythagoras_after](https://github.com/CatalinAnt/algorithms-SEP-95/assets/114078193/1aa45c17-46fc-49d3-944a-03c2276d1be6) + +the coverage is improved by 28%, the code only hit one of the five branches and cover only one of the three cases of the pythagoras theory. I added the other two cases, i could have a fourth case where none of the cases is present. + +test_strings + +https://github.com/CatalinAnt/algorithms-SEP-95/commit/5651abafebe8ae3a5ea63e74883bb991acf19303 + +![first_unique_char_before](https://github.com/CatalinAnt/algorithms-SEP-95/assets/114078193/9910ec69-73b0-4c87-afc8-abc01f65a423) + +![first_unique_char_after](https://github.com/CatalinAnt/algorithms-SEP-95/assets/114078193/10859fac-776c-4a48-8a1c-9531afcbfa9b) + +The coverage is improved by 13%, the code only hit three out of five branches and only set up two examples. I added a case where there is no unique letter. + + + + + + + + + + + + + +### Overall + + +Old overall coverage: +![image](https://github.com/CatalinAnt/algorithms-SEP-95/assets/113595149/f1cd3fab-b00c-4cd0-89d0-6452e7ed1a63) + + +New overall coverage: + +![image](https://github.com/CatalinAnt/algorithms-SEP-95/assets/113595149/a53729ff-a4f1-42ce-9fe9-ff0813952658) + +Due to the large size of the project, the percentage only went up by one percent. + +## Statement of individual contributions + + + +Abdullah -> increased the coverage for two functions. + +Almuthana Almustafa -> Instrumentation was added to two functions, and test cases were created for them to improve coverage. + +Cataline -> Instrumentation was added to two functions, and the tests for these functions were enhanced. + + + + + + diff --git a/README_original.md b/README_original.md new file mode 100644 index 000000000..25bf3bc03 --- /dev/null +++ b/README_original.md @@ -0,0 +1,424 @@ +[![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms) +[![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms) +[![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms) +[![Coverage Status](https://coveralls.io/repos/github/keon/algorithms/badge.svg?branch=master)](https://coveralls.io/github/keon/algorithms?branch=master) + +

+ +Pythonic Data Structures and Algorithms +========================================= + +Minimal and clean example implementations of data structures and algorithms in Python 3. + +## Contributing +Thanks for your interest in contributing! There are many ways to contribute to this project. [Get started here](CONTRIBUTING.md) + +## Tests + +### Use unittest +For running all tests write down: + + $ python3 -m unittest discover tests + +For running some specific tests you can do this as following (Ex: sort): + + $ python3 -m unittest tests.test_sort + +### Use pytest +For running all tests write down: + + $ python3 -m pytest tests + +## Install +If you want to use the API algorithms in your code, it is as simple as: + + $ pip3 install algorithms + +You can test by creating a python file: (Ex: use `merge_sort` in `sort`) + +```python3 +from algorithms.sort import merge_sort + +if __name__ == "__main__": + my_list = [1, 8, 3, 5, 6] + my_list = merge_sort(my_list) + print(my_list) +``` + +## Uninstall +If you want to uninstall algorithms, it is as simple as: + + $ pip3 uninstall -y algorithms + +## List of Implementations + +- [arrays](algorithms/arrays) + - [delete_nth](algorithms/arrays/delete_nth.py) + - [flatten](algorithms/arrays/flatten.py) + - [garage](algorithms/arrays/garage.py) + - [josephus_problem](algorithms/arrays/josephus.py) + - [limit](algorithms/arrays/limit.py) + - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/) + - [max_ones_index](algorithms/arrays/max_ones_index.py) + - [merge_intervals](algorithms/arrays/merge_intervals.py) + - [missing_ranges](algorithms/arrays/missing_ranges.py) + - [plus_one](algorithms/arrays/plus_one.py) + - [remove_duplicates](algorithms/arrays/remove_duplicates.py) + - [rotate](algorithms/arrays/rotate.py) + - [summarize_ranges](algorithms/arrays/summarize_ranges.py) + - [three_sum](algorithms/arrays/three_sum.py) + - [trimmean](algorithms/arrays/trimmean.py) + - [top_1](algorithms/arrays/top_1.py) + - [two_sum](algorithms/arrays/two_sum.py) + - [move_zeros](algorithms/arrays/move_zeros.py) + - [n_sum](algorithms/arrays/n_sum.py) +- [greedy](algorithms/greedy/) + - [max_contiguous_subsequence_sum](algorithms/greedy/max_contiguous_subsequence_sum.py) +- [automata](algorithms/automata) + - [DFA](algorithms/automata/dfa.py) +- [backtrack](algorithms/backtrack) + - [general_solution.md](algorithms/backtrack/) + - [add_operators](algorithms/backtrack/add_operators.py) + - [anagram](algorithms/backtrack/anagram.py) + - [array_sum_combinations](algorithms/backtrack/array_sum_combinations.py) + - [combination_sum](algorithms/backtrack/combination_sum.py) + - [factor_combinations](algorithms/backtrack/factor_combinations.py) + - [generate_abbreviations](algorithms/backtrack/generate_abbreviations.py) + - [generate_parenthesis](algorithms/backtrack/generate_parenthesis.py) + - [letter_combination](algorithms/backtrack/letter_combination.py) + - [palindrome_partitioning](algorithms/backtrack/palindrome_partitioning.py) + - [pattern_match](algorithms/backtrack/pattern_match.py) + - [permute](algorithms/backtrack/permute.py) + - [permute_unique](algorithms/backtrack/permute_unique.py) + - [subsets](algorithms/backtrack/subsets.py) + - [subsets_unique](algorithms/backtrack/subsets_unique.py) +- [bfs](algorithms/bfs) + - [maze_search](algorithms/bfs/maze_search.py) + - [shortest_distance_from_all_buildings](algorithms/bfs/shortest_distance_from_all_buildings.py) + - [word_ladder](algorithms/bfs/word_ladder.py) +- [bit](algorithms/bit) + - [add_bitwise_operator](algorithms/bit/add_bitwise_operator.py) + - [bit_operation](algorithms/bit/bit_operation.py) + - [bytes_int_conversion](algorithms/bit/bytes_int_conversion.py) + - [count_flips_to_convert](algorithms/bit/count_flips_to_convert.py) + - [count_ones](algorithms/bit/count_ones.py) + - [find_difference](algorithms/bit/find_difference.py) + - [find_missing_number](algorithms/bit/find_missing_number.py) + - [flip_bit_longest_sequence](algorithms/bit/flip_bit_longest_sequence.py) + - [power_of_two](algorithms/bit/power_of_two.py) + - [reverse_bits](algorithms/bit/reverse_bits.py) + - [single_number](algorithms/bit/single_number.py) + - [single_number2](algorithms/bit/single_number2.py) + - [single_number3](algorithms/bit/single_number3.py) + - [subsets](algorithms/bit/subsets.py) + - [swap_pair](algorithms/bit/swap_pair.py) + - [has_alternative_bit](algorithms/bit/has_alternative_bit.py) + - [insert_bit](algorithms/bit/insert_bit.py) + - [remove_bit](algorithms/bit/remove_bit.py) + - [binary_gap](algorithms/bit/binary_gap.py) +- [compression](algorithms/compression) + - [huffman_coding](algorithms/compression/huffman_coding.py) + - [rle_compression](algorithms/compression/rle_compression.py) + - [elias](algorithms/compression/elias.py) +- [dfs](algorithms/dfs) + - [all_factors](algorithms/dfs/all_factors.py) + - [count_islands](algorithms/dfs/count_islands.py) + - [pacific_atlantic](algorithms/dfs/pacific_atlantic.py) + - [sudoku_solver](algorithms/dfs/sudoku_solver.py) + - [walls_and_gates](algorithms/dfs/walls_and_gates.py) +- [distribution](algorithms/distribution) + - [histogram](algorithms/distribution/histogram.py) +- [dp](algorithms/dp) + - [buy_sell_stock](algorithms/dp/buy_sell_stock.py) + - [climbing_stairs](algorithms/dp/climbing_stairs.py) + - [coin_change](algorithms/dp/coin_change.py) + - [combination_sum](algorithms/dp/combination_sum.py) + - [egg_drop](algorithms/dp/egg_drop.py) + - [house_robber](algorithms/dp/house_robber.py) + - [int_divide](algorithms/dp/int_divide.py) + - [job_scheduling](algorithms/dp/job_scheduling.py) + - [knapsack](algorithms/dp/knapsack.py) + - [longest_increasing](algorithms/dp/longest_increasing.py) + - [matrix_chain_order](algorithms/dp/matrix_chain_order.py) + - [max_product_subarray](algorithms/dp/max_product_subarray.py) + - [max_subarray](algorithms/dp/max_subarray.py) + - [min_cost_path](algorithms/dp/min_cost_path.py) + - [num_decodings](algorithms/dp/num_decodings.py) + - [regex_matching](algorithms/dp/regex_matching.py) + - [rod_cut](algorithms/dp/rod_cut.py) + - [word_break](algorithms/dp/word_break.py) + - [fibonacci](algorithms/dp/fib.py) + - [hosoya triangle](algorithms/dp/hosoya_triangle.py) + - [K-Factor_strings](algorithms/dp/k_factor.py) + - [planting_trees](algorithms/dp/planting_trees.py) +- [graph](algorithms/graph) + - [check_bipartite](algorithms/graph/check_bipartite.py) + - [strongly_connected](algorithms/graph/check_digraph_strongly_connected.py) + - [clone_graph](algorithms/graph/clone_graph.py) + - [cycle_detection](algorithms/graph/cycle_detection.py) + - [find_all_cliques](algorithms/graph/find_all_cliques.py) + - [find_path](algorithms/graph/find_path.py) + - [graph](algorithms/graph/graph.py) + - [dijkstra](algorithms/graph/dijkstra.py) + - [markov_chain](algorithms/graph/markov_chain.py) + - [minimum_spanning_tree](algorithms/graph/minimum_spanning_tree.py) + - [satisfiability](algorithms/graph/satisfiability.py) + - [minimum_spanning_tree_prims](algorithms/graph/prims_minimum_spanning.py) + - [tarjan](algorithms/graph/tarjan.py) + - [traversal](algorithms/graph/traversal.py) + - [maximum_flow](algorithms/graph/maximum_flow.py) + - [maximum_flow_bfs](algorithms/graph/maximum_flow_bfs.py) + - [maximum_flow_dfs](algorithms/graph/maximum_flow_dfs.py) + - [all_pairs_shortest_path](algorithms/graph/all_pairs_shortest_path.py) + - [bellman_ford](algorithms/graph/bellman_ford.py) + - [Count Connected Components](algorithms/graph/count_connected_number_of_component.py) +- [heap](algorithms/heap) + - [merge_sorted_k_lists](algorithms/heap/merge_sorted_k_lists.py) + - [skyline](algorithms/heap/skyline.py) + - [sliding_window_max](algorithms/heap/sliding_window_max.py) + - [binary_heap](algorithms/heap/binary_heap.py) + - [k_closest_points](algorithms/heap/k_closest_points.py) +- [linkedlist](algorithms/linkedlist) + - [add_two_numbers](algorithms/linkedlist/add_two_numbers.py) + - [copy_random_pointer](algorithms/linkedlist/copy_random_pointer.py) + - [delete_node](algorithms/linkedlist/delete_node.py) + - [first_cyclic_node](algorithms/linkedlist/first_cyclic_node.py) + - [is_cyclic](algorithms/linkedlist/is_cyclic.py) + - [is_palindrome](algorithms/linkedlist/is_palindrome.py) + - [kth_to_last](algorithms/linkedlist/kth_to_last.py) + - [linkedlist](algorithms/linkedlist/linkedlist.py) + - [remove_duplicates](algorithms/linkedlist/remove_duplicates.py) + - [reverse](algorithms/linkedlist/reverse.py) + - [rotate_list](algorithms/linkedlist/rotate_list.py) + - [swap_in_pairs](algorithms/linkedlist/swap_in_pairs.py) + - [is_sorted](algorithms/linkedlist/is_sorted.py) + - [remove_range](algorithms/linkedlist/remove_range.py) +- [map](algorithms/map) + - [hashtable](algorithms/map/hashtable.py) + - [separate_chaining_hashtable](algorithms/map/separate_chaining_hashtable.py) + - [longest_common_subsequence](algorithms/map/longest_common_subsequence.py) + - [longest_palindromic_subsequence](algorithms/map/longest_palindromic_subsequence.py) + - [randomized_set](algorithms/map/randomized_set.py) + - [valid_sudoku](algorithms/map/valid_sudoku.py) + - [word_pattern](algorithms/map/word_pattern.py) + - [is_isomorphic](algorithms/map/is_isomorphic.py) + - [is_anagram](algorithms/map/is_anagram.py) +- [maths](algorithms/maths) + - [base_conversion](algorithms/maths/base_conversion.py) + - [chinese_remainder_theorem](algorithms/maths/chinese_remainder_theorem.py) + - [combination](algorithms/maths/combination.py) + - [cosine_similarity](algorithms/maths/cosine_similarity.py) + - [decimal_to_binary_ip](algorithms/maths/decimal_to_binary_ip.py) + - [diffie_hellman_key_exchange](algorithms/maths/diffie_hellman_key_exchange.py) + - [euler_totient](algorithms/maths/euler_totient.py) + - [extended_gcd](algorithms/maths/extended_gcd.py) + - [factorial](algorithms/maths/factorial.py) + - [find_order](algorithms/maths/find_order_simple.py) + - [find_primitive_root](algorithms/maths/find_primitive_root_simple.py) + - [gcd/lcm](algorithms/maths/gcd.py) + - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py) + - [hailstone](algorithms/maths/hailstone.py) + - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py) + - [krishnamurthy_number](algorithms/maths/krishnamurthy_number.py) + - [magic_number](algorithms/maths/magic_number.py) + - [modular_exponential](algorithms/maths/modular_exponential.py) + - [modular_inverse](algorithms/maths/modular_inverse.py) + - [next_bigger](algorithms/maths/next_bigger.py) + - [next_perfect_square](algorithms/maths/next_perfect_square.py) + - [nth_digit](algorithms/maths/nth_digit.py) + - [num_perfect_squares](algorithms/maths/num_perfect_squares.py) + - [polynomial](algorithms/maths/polynomial.py) + - [power](algorithms/maths/power.py) + - [prime_check](algorithms/maths/prime_check.py) + - [primes_sieve_of_eratosthenes](algorithms/maths/primes_sieve_of_eratosthenes.py) + - [pythagoras](algorithms/maths/pythagoras.py) + - [rabin_miller](algorithms/maths/rabin_miller.py) + - [recursive_binomial_coefficient](algorithms/maths/recursive_binomial_coefficient.py) + - [rsa](algorithms/maths/rsa.py) + - [sqrt_precision_factor](algorithms/maths/sqrt_precision_factor.py) + - [summing_digits](algorithms/maths/summing_digits.py) + - [symmetry_group_cycle_index](algorithms/maths/symmetry_group_cycle_index.py) +- [matrix](algorithms/matrix) + - [sudoku_validator](algorithms/matrix/sudoku_validator.py) + - [bomb_enemy](algorithms/matrix/bomb_enemy.py) + - [copy_transform](algorithms/matrix/copy_transform.py) + - [count_paths](algorithms/matrix/count_paths.py) + - [matrix_exponentiation](algorithms/matrix/matrix_exponentiation.py) + - [matrix_inversion](algorithms/matrix/matrix_inversion.py) + - [matrix_multiplication](algorithms/matrix/multiply.py) + - [rotate_image](algorithms/matrix/rotate_image.py) + - [search_in_sorted_matrix](algorithms/matrix/search_in_sorted_matrix.py) + - [sparse_dot_vector](algorithms/matrix/sparse_dot_vector.py) + - [sparse_mul](algorithms/matrix/sparse_mul.py) + - [spiral_traversal](algorithms/matrix/spiral_traversal.py) + - [crout_matrix_decomposition](algorithms/matrix/crout_matrix_decomposition.py) + - [cholesky_matrix_decomposition](algorithms/matrix/cholesky_matrix_decomposition.py) + - [sum_sub_squares](algorithms/matrix/sum_sub_squares.py) + - [sort_matrix_diagonally](algorithms/matrix/sort_matrix_diagonally.py) +- [queues](algorithms/queues) + - [max_sliding_window](algorithms/queues/max_sliding_window.py) + - [moving_average](algorithms/queues/moving_average.py) + - [queue](algorithms/queues/queue.py) + - [reconstruct_queue](algorithms/queues/reconstruct_queue.py) + - [zigzagiterator](algorithms/queues/zigzagiterator.py) +- [search](algorithms/search) + - [binary_search](algorithms/search/binary_search.py) + - [first_occurrence](algorithms/search/first_occurrence.py) + - [last_occurrence](algorithms/search/last_occurrence.py) + - [linear_search](algorithms/search/linear_search.py) + - [search_insert](algorithms/search/search_insert.py) + - [two_sum](algorithms/search/two_sum.py) + - [search_range](algorithms/search/search_range.py) + - [find_min_rotate](algorithms/search/find_min_rotate.py) + - [search_rotate](algorithms/search/search_rotate.py) + - [jump_search](algorithms/search/jump_search.py) + - [next_greatest_letter](algorithms/search/next_greatest_letter.py) + - [interpolation_search](algorithms/search/interpolation_search.py) +- [set](algorithms/set) + - [randomized_set](algorithms/set/randomized_set.py) + - [set_covering](algorithms/set/set_covering.py) + - [find_keyboard_row](algorithms/set/find_keyboard_row.py) +- [sort](algorithms/sort) + - [bitonic_sort](algorithms/sort/bitonic_sort.py) + - [bogo_sort](algorithms/sort/bogo_sort.py) + - [bubble_sort](algorithms/sort/bubble_sort.py) + - [bucket_sort](algorithms/sort/bucket_sort.py) + - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py) + - [comb_sort](algorithms/sort/comb_sort.py) + - [counting_sort](algorithms/sort/counting_sort.py) + - [cycle_sort](algorithms/sort/cycle_sort.py) + - [exchange_sort](algorithms/sort/exchange_sort.py) + - [gnome_sort](algorithms/sort/gnome_sort.py) + - [heap_sort](algorithms/sort/heap_sort.py) + - [insertion_sort](algorithms/sort/insertion_sort.py) + - [meeting_rooms](algorithms/sort/meeting_rooms.py) + - [merge_sort](algorithms/sort/merge_sort.py) + - [pancake_sort](algorithms/sort/pancake_sort.py) + - [pigeonhole_sort](algorithms/sort/pigeonhole_sort.py) + - [quick_sort](algorithms/sort/quick_sort.py) + - [radix_sort](algorithms/sort/radix_sort.py) + - [selection_sort](algorithms/sort/selection_sort.py) + - [shell_sort](algorithms/sort/shell_sort.py) + - [sort_colors](algorithms/sort/sort_colors.py) + - [stooge_sort](algorithms/sort/stooge_sort.py) + - [top_sort](algorithms/sort/top_sort.py) + - [wiggle_sort](algorithms/sort/wiggle_sort.py) +- [stack](algorithms/stack) + - [longest_abs_path](algorithms/stack/longest_abs_path.py) + - [simplify_path](algorithms/stack/simplify_path.py) + - [stack](algorithms/stack/stack.py) + - [valid_parenthesis](algorithms/stack/valid_parenthesis.py) + - [stutter](algorithms/stack/stutter.py) + - [switch_pairs](algorithms/stack/switch_pairs.py) + - [is_consecutive](algorithms/stack/is_consecutive.py) + - [remove_min](algorithms/stack/remove_min.py) + - [is_sorted](algorithms/stack/is_sorted.py) +- [streaming](algorithms/streaming) + - [1-sparse-recovery](algorithms/streaming/one_sparse_recovery.py) + - [misra-gries](algorithms/streaming/misra_gries.py) +- [strings](algorithms/strings) + - [fizzbuzz](algorithms/strings/fizzbuzz.py) + - [delete_reoccurring](algorithms/strings/delete_reoccurring.py) + - [strip_url_params](algorithms/strings/strip_url_params.py) + - [validate_coordinates](algorithms/strings/validate_coordinates.py) + - [domain_extractor](algorithms/strings/domain_extractor.py) + - [merge_string_checker](algorithms/strings/merge_string_checker.py) + - [add_binary](algorithms/strings/add_binary.py) + - [breaking_bad](algorithms/strings/breaking_bad.py) + - [decode_string](algorithms/strings/decode_string.py) + - [encode_decode](algorithms/strings/encode_decode.py) + - [group_anagrams](algorithms/strings/group_anagrams.py) + - [int_to_roman](algorithms/strings/int_to_roman.py) + - [is_palindrome](algorithms/strings/is_palindrome.py) + - [license_number](algorithms/strings/license_number.py) + - [make_sentence](algorithms/strings/make_sentence.py) + - [multiply_strings](algorithms/strings/multiply_strings.py) + - [one_edit_distance](algorithms/strings/one_edit_distance.py) + - [rabin_karp](algorithms/strings/rabin_karp.py) + - [reverse_string](algorithms/strings/reverse_string.py) + - [reverse_vowel](algorithms/strings/reverse_vowel.py) + - [reverse_words](algorithms/strings/reverse_words.py) + - [roman_to_int](algorithms/strings/roman_to_int.py) + - [word_squares](algorithms/strings/word_squares.py) + - [unique_morse](algorithms/strings/unique_morse.py) + - [judge_circle](algorithms/strings/judge_circle.py) + - [strong_password](algorithms/strings/strong_password.py) + - [caesar_cipher](algorithms/strings/caesar_cipher.py) + - [check_pangram](algorithms/strings/check_pangram.py) + - [contain_string](algorithms/strings/contain_string.py) + - [count_binary_substring](algorithms/strings/count_binary_substring.py) + - [repeat_string](algorithms/strings/repeat_string.py) + - [min_distance](algorithms/strings/min_distance.py) + - [longest_common_prefix](algorithms/strings/longest_common_prefix.py) + - [rotate](algorithms/strings/rotate.py) + - [first_unique_char](algorithms/strings/first_unique_char.py) + - [repeat_substring](algorithms/strings/repeat_substring.py) + - [atbash_cipher](algorithms/strings/atbash_cipher.py) + - [longest_palindromic_substring](algorithms/strings/longest_palindromic_substring.py) + - [knuth_morris_pratt](algorithms/strings/knuth_morris_pratt.py) + - [panagram](algorithms/strings/panagram.py) +- [tree](algorithms/tree) + - [bst](algorithms/tree/bst) + - [array_to_bst](algorithms/tree/bst/array_to_bst.py) + - [bst_closest_value](algorithms/tree/bst/bst_closest_value.py) + - [BSTIterator](algorithms/tree/bst/BSTIterator.py) + - [delete_node](algorithms/tree/bst/delete_node.py) + - [is_bst](algorithms/tree/bst/is_bst.py) + - [kth_smallest](algorithms/tree/bst/kth_smallest.py) + - [lowest_common_ancestor](algorithms/tree/bst/lowest_common_ancestor.py) + - [predecessor](algorithms/tree/bst/predecessor.py) + - [serialize_deserialize](algorithms/tree/bst/serialize_deserialize.py) + - [successor](algorithms/tree/bst/successor.py) + - [unique_bst](algorithms/tree/bst/unique_bst.py) + - [depth_sum](algorithms/tree/bst/depth_sum.py) + - [count_left_node](algorithms/tree/bst/count_left_node.py) + - [num_empty](algorithms/tree/bst/num_empty.py) + - [height](algorithms/tree/bst/height.py) + - [fenwick_tree](algorithms/tree/fenwick_tree/fenwick_tree.py) + - [red_black_tree](algorithms/tree/red_black_tree) + - [red_black_tree](algorithms/tree/red_black_tree/red_black_tree.py) + - [segment_tree](algorithms/tree/segment_tree) + - [segment_tree](algorithms/tree/segment_tree/segment_tree.py) + - [iterative_segment_tree](algorithms/tree/segment_tree/iterative_segment_tree.py) + - [traversal](algorithms/tree/traversal) + - [inorder](algorithms/tree/traversal/inorder.py) + - [level_order](algorithms/tree/traversal/level_order.py) + - [postorder](algorithms/tree/traversal/postorder.py) + - [preorder](algorithms/tree/traversal/preorder.py) + - [zigzag](algorithms/tree/traversal/zigzag.py) + - [trie](algorithms/tree/trie) + - [add_and_search](algorithms/tree/trie/add_and_search.py) + - [trie](algorithms/tree/trie/trie.py) + - [b_tree](algorithms/tree/b_tree.py) + - [binary_tree_paths](algorithms/tree/binary_tree_paths.py) + - [bin_tree_to_list](algorithms/tree/bin_tree_to_list.py) + - [construct_tree_preorder_postorder](algorithms/tree/construct_tree_postorder_preorder.py) + - [deepest_left](algorithms/tree/deepest_left.py) + - [invert_tree](algorithms/tree/invert_tree.py) + - [is_balanced](algorithms/tree/is_balanced.py) + - [is_subtree](algorithms/tree/is_subtree.py) + - [is_symmetric](algorithms/tree/is_symmetric.py) + - [longest_consecutive](algorithms/tree/longest_consecutive.py) + - [lowest_common_ancestor](algorithms/tree/lowest_common_ancestor.py) + - [max_height](algorithms/tree/max_height.py) + - [max_path_sum](algorithms/tree/max_path_sum.py) + - [min_height](algorithms/tree/min_height.py) + - [path_sum](algorithms/tree/path_sum.py) + - [path_sum2](algorithms/tree/path_sum2.py) + - [pretty_print](algorithms/tree/pretty_print.py) + - [same_tree](algorithms/tree/same_tree.py) + - [tree](algorithms/tree/tree.py) +- [unix](algorithms/unix) + - [path](algorithms/unix/path/) + - [join_with_slash](algorithms/unix/path/join_with_slash.py) + - [full_path](algorithms/unix/path/full_path.py) + - [split](algorithms/unix/path/split.py) + - [simplify_path](algorithms/unix/path/simplify_path.py) +- [unionfind](algorithms/unionfind) + - [count_islands](algorithms/unionfind/count_islands.py) + + +## Contributors + +Thanks to [all the contributors](https://github.com/keon/algorithms/graphs/contributors) +who helped in building the repo. diff --git a/algorithms/dp/word_break.py b/algorithms/dp/word_break.py index f520456b0..2ef9fd03b 100644 --- a/algorithms/dp/word_break.py +++ b/algorithms/dp/word_break.py @@ -17,6 +17,14 @@ """ +# TC: O(N^2) SC: O(N) +branch_coverage = { + "check_5": False, + "check_6": False, + "check_7": False, + "check_8": False, + +} # TC: O(N^2) SC: O(N) def word_break(word, word_dict): """ @@ -27,15 +35,29 @@ def word_break(word, word_dict): dp_array = [False] * (len(word)+1) dp_array[0] = True for i in range(1, len(word)+1): + branch_coverage["check_5"] = True for j in range(0, i): + branch_coverage["check_6"] = True if dp_array[j] and word[j:i] in word_dict: + branch_coverage["check_7"] = True dp_array[i] = True break + branch_coverage["check_8"] = True return dp_array[-1] -if __name__ == "__main__": - STR = "keonkim" - dic = ["keon", "kim"] +def print_coverage(): + total = len(branch_coverage) + reached = sum(branch_coverage.values()) + coverage_percentage = (reached / total) * 100 + for branch, hit in branch_coverage.items(): + print(f"{branch} was {'hit' if hit else 'not hit'}") + print(f"coverage_percentage: {coverage_percentage}%") + + +result = word_break("keonkim", {"keon", "kim"}) +print_coverage() + + + - print(word_break(str, dic)) diff --git a/algorithms/maths/euler_totient.py b/algorithms/maths/euler_totient.py index f29d382ff..ed5d873c5 100644 --- a/algorithms/maths/euler_totient.py +++ b/algorithms/maths/euler_totient.py @@ -4,15 +4,37 @@ which are coprime to n. (Two numbers are coprime if their greatest common divisor (GCD) equals 1). """ +branch_coverage = { + "check_1": False, # if branch for x > 0 + "check_2": False, # else branch + "check_2": False, + "check_2": False, +} def euler_totient(n): """Euler's totient function or Phi function. Time Complexity: O(sqrt(n)).""" result = n for i in range(2, int(n ** 0.5) + 1): + branch_coverage["check_1"] = True if n % i == 0: + branch_coverage["check_2"] = True while n % i == 0: + branch_coverage["check_3"] = True n //= i result -= result // i if n > 1: + branch_coverage["check_4"] = True result -= result // n return result + +def print_coverage(): + total = len(branch_coverage) + reached = sum(branch_coverage.values()) + coverage_percentage = (reached / total) * 100 + for branch, hit in branch_coverage.items(): + print(f"{branch} was {'hit' if hit else 'not hit'}") + print(f"coverage_percentage: {coverage_percentage}%") + + +result = euler_totient(21) +print_coverage() \ No newline at end of file diff --git a/algorithms/maths/find_order_simple.py b/algorithms/maths/find_order_simple.py index 8f69773c7..732fcae62 100644 --- a/algorithms/maths/find_order_simple.py +++ b/algorithms/maths/find_order_simple.py @@ -11,17 +11,42 @@ import math +branch_coverage = { + "branch_6": False, + "branch_7": False, + "branch_8": False, + "branch_9": False, + "branch_10": False +} + def find_order(a, n): """ Find order for positive integer n and given integer a that satisfies gcd(a, n) = 1. """ + if (a == 1) & (n == 1): # Exception Handeling : 1 is the order of of 1 + branch_coverage["branch_6"] = True + print("branch_6") return 1 if math.gcd(a, n) != 1: + branch_coverage["branch_7"] = True + print("branch_7") print ("a and n should be relative prime!") return -1 for i in range(1, n): + branch_coverage["branch_8"] = True + print("branch_8") if pow(a, i) % n == 1: + branch_coverage["branch_9"] = True + print("branch_9") return i + branch_coverage["branch_10"] = True + print("branch_10") return -1 + +def print_coverage(): + for branch, hit in branch_coverage.items(): + print(f"{branch} was {'hit' if hit else 'not hit'}") + +print_coverage() \ No newline at end of file diff --git a/algorithms/maths/prime_check.py b/algorithms/maths/prime_check.py index 60e4427ab..532f7afba 100644 --- a/algorithms/maths/prime_check.py +++ b/algorithms/maths/prime_check.py @@ -1,17 +1,42 @@ +branch_coverage = { + "branch_1": False, # n <= 1 + "branch_2": False, # n == 2 or n == 3 + "branch_3": False, # n % 2 == 0 or n % 3 == 0 + "branch_4": False, # while j * j <= n + "branch_5": False # n % j == 0 or n % (j + 2) == 0 +} def prime_check(n): """Return True if n is a prime number Else return False. """ + print(f"Checking {n}") # Debugging statement if n <= 1: + branch_coverage["branch_1"] = True + print("branch_1") return False + if n == 2 or n == 3: + branch_coverage["branch_2"] = True + print("branch_2") return True if n % 2 == 0 or n % 3 == 0: + branch_coverage["branch_3"] = True + print("branch_3") return False j = 5 while j * j <= n: + branch_coverage["branch_4"] = True + print("branch_4") if n % j == 0 or n % (j + 2) == 0: + branch_coverage["branch_5"] = True + print("branch_5") return False j += 6 return True + +def print_coverage(): + for branch, hit in branch_coverage.items(): + print(f"{branch} was {'hit' if hit else 'not hit'}") + +print_coverage() diff --git a/algorithms/maths/pythagoras.py b/algorithms/maths/pythagoras.py index b24b682ac..386b821b3 100644 --- a/algorithms/maths/pythagoras.py +++ b/algorithms/maths/pythagoras.py @@ -2,6 +2,13 @@ Given the lengths of two of the three sides of a right angled triangle, this function returns the length of the third side. """ +branch_coverage = { + "branch_31": False, + "branch_32": False, + "branch_33": False, + "branch_34": False, + "branch_35": False +} def pythagoras(opposite, adjacent, hypotenuse): """ @@ -10,11 +17,25 @@ def pythagoras(opposite, adjacent, hypotenuse): """ try: if opposite == str("?"): + branch_coverage["branch_31"] = True return ("Opposite = " + str(((hypotenuse**2) - (adjacent**2))**0.5)) if adjacent == str("?"): + branch_coverage["branch_32"] = True return ("Adjacent = " + str(((hypotenuse**2) - (opposite**2))**0.5)) if hypotenuse == str("?"): + branch_coverage["branch_33"] = True return ("Hypotenuse = " + str(((opposite**2) + (adjacent**2))**0.5)) + branch_coverage["branch_34"] = True return "You already know the answer!" except: + branch_coverage["branch_35"] = True raise ValueError("invalid argument(s) were given.") + +def print_coverage(): + for branch, hit in branch_coverage.items(): + print(f"{branch} was {'hit' if hit else 'not hit'}") + +pythagoras(3, 2, "?") + +print_coverage() + diff --git a/algorithms/matrix/rotate_image.py b/algorithms/matrix/rotate_image.py index a8b5e4e77..f525e24bb 100644 --- a/algorithms/matrix/rotate_image.py +++ b/algorithms/matrix/rotate_image.py @@ -7,6 +7,14 @@ Could you do this in-place? """ +branch_coverage = { + "rotate_matrix_1": False, # if not branch for mat + "rotate_matrix_2": False, # invisible else branch + "rotate_matrix_3": False, # for branch + "rotate_matrix_4": False, # for branch + +} + # clockwise rotate # first reverse up to down, then swap the symmetry @@ -16,18 +24,38 @@ def rotate(mat): if not mat: + branch_coverage["rotate_matrix_1"] = True return mat + + branch_coverage["rotate_matrix_2"] = True + mat.reverse() for i in range(len(mat)): + branch_coverage["rotate_matrix_3"] = True + for j in range(i): + branch_coverage["rotate_matrix_4"] = True + mat[i][j], mat[j][i] = mat[j][i], mat[i][j] return mat -if __name__ == "__main__": - mat = [[1, 2, 3], - [4, 5, 6], - [7, 8, 9]] - print(mat) - rotate(mat) - print(mat) +def print_coverage(): + for branch, hit in branch_coverage.items(): + print(f"{branch} was {'hit' if hit else 'not hit'}") + total = len(branch_coverage) + hit = sum(branch_coverage.values()) + result = hit / total * 100 + + print("The total branch coverage is:", result, "%") + + +rotate([]) +print_coverage() +print("\n") +print_coverage() +rotate([[1, 2], [3, 4]]) +print("\n") +print_coverage() +rotate([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) +print("\n") diff --git a/algorithms/search/interpolation_search.py b/algorithms/search/interpolation_search.py index 5b1d00a1a..98a405431 100644 --- a/algorithms/search/interpolation_search.py +++ b/algorithms/search/interpolation_search.py @@ -13,6 +13,15 @@ from typing import List +branch_coverage = { + "branch_60": False, + "branch_61": False, + "branch_62": False, + "branch_63": False, + "branch_64": False, + +} + def interpolation_search(array: List[int], search_key: int) -> int: """ @@ -38,24 +47,36 @@ def interpolation_search(array: List[int], search_key: int) -> int: while (low <= high) and (array[low] <= search_key <= array[high]): # calculate the search position + branch_coverage["branch_60"] = True pos = low + int(((search_key - array[low]) * (high - low) / (array[high] - array[low]))) # search_key is found if array[pos] == search_key: + branch_coverage["branch_61"] = True return pos # if search_key is larger, search_key is in upper part if array[pos] < search_key: + branch_coverage["branch_62"] = True low = pos + 1 # if search_key is smaller, search_key is in lower part else: + branch_coverage["branch_63"] = True high = pos - 1 - + + branch_coverage["branch_64"] = True return -1 +def print_coverage(): + for branch, hit in branch_coverage.items(): + print(f"{branch} was {'hit' if hit else 'not hit'}") + + if __name__ == "__main__": import doctest doctest.testmod() +print_coverage() + diff --git a/algorithms/sort/insertion_sort.py b/algorithms/sort/insertion_sort.py index 06c86228d..f1f7613e4 100644 --- a/algorithms/sort/insertion_sort.py +++ b/algorithms/sort/insertion_sort.py @@ -1,3 +1,10 @@ +branch_coverage = { + "simulation": False, + "for": False, + "while": False, + "simulation-nested": False, +} + def insertion_sort(arr, simulation=False): """ Insertion Sort Complexity: O(n^2) @@ -5,13 +12,16 @@ def insertion_sort(arr, simulation=False): iteration = 0 if simulation: + branch_coverage["simulation"] = True print("iteration",iteration,":",*arr) for i in range(len(arr)): + branch_coverage["for"] = True cursor = arr[i] pos = i while pos > 0 and arr[pos - 1] > cursor: + branch_coverage["while"] = True # Swap the number down the list arr[pos] = arr[pos - 1] pos = pos - 1 @@ -19,7 +29,25 @@ def insertion_sort(arr, simulation=False): arr[pos] = cursor if simulation: + branch_coverage["simulation-nested"] = True iteration = iteration + 1 print("iteration",iteration,":",*arr) return arr + +def print_coverage(): + covered = 0 + print("branch coverage for `insertion_sort`:") + for branch, hit in branch_coverage.items(): + print(f"{branch} was {'hit' if hit else 'not hit'}") + if hit: covered += 1; + print(f"Branch coverage: {covered / len(branch_coverage) * 100}") + +insertion_sort([]) +insertion_sort([1]) +insertion_sort([69, 420]) +insertion_sort([420, 69]) +insertion_sort([0, 1, 2, 3, 4, 3, 2, 1, 0]) +insertion_sort([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], True) +insertion_sort([0, 1, 2, 3, 4, 3, 2, 1, 0], True) +print_coverage() diff --git a/algorithms/sort/stooge_sort.py b/algorithms/sort/stooge_sort.py index 42f8b3bd4..b8419cef8 100644 --- a/algorithms/sort/stooge_sort.py +++ b/algorithms/sort/stooge_sort.py @@ -6,15 +6,22 @@ ''' - +branch_coverage = { + "check_1": False, # if branch for x > 0 + "check_2": False, # else branch + "check_3": False, + "check_4": False, +} def stoogesort(arr, l, h): if l >= h: + branch_coverage["check_1"] = True return # If first element is smaller # than last, swap them if arr[l]>arr[h]: + branch_coverage["check_2"] = True t = arr[l] arr[l] = arr[h] arr[h] = t @@ -22,6 +29,7 @@ def stoogesort(arr, l, h): # If there are more than 2 elements in # the array if h-l + 1 > 2: + branch_coverage["check_3"] = True t = (int)((h-l + 1)/3) # Recursively sort first 2 / 3 elements @@ -33,11 +41,27 @@ def stoogesort(arr, l, h): # Recursively sort first 2 / 3 elements # again to confirm stoogesort(arr, l, (h-t)) + + branch_coverage["check_4"] = True + +def print_coverage(): + total = len(branch_coverage) + reached = sum(branch_coverage.values()) + coverage_percentage = (reached / total) * 100 + for branch, hit in branch_coverage.items(): + print(f"{branch} was {'hit' if hit else 'not hit'}") + print(f"coverage_percentage: {coverage_percentage}%") + +arr1 = [10, -1, 2, 3, 0] +arr2 = [] +result = stoogesort(arr1, 0, len(arr1) - 1) +result = stoogesort(arr1, 0, len(arr2) - 1) +print_coverage() -if __name__ == "__main__": - array = [1,3,64,5,7,8] - n = len(array) - stoogesort(array, 0, n-1) - for i in range(0, n): - print(array[i], end = ' ') +# if __name__ == "__main__": +# array = [1,3,64,5,7,8] +# n = len(array) +# stoogesort(array, 0, n-1) +# for i in range(0, n): +# print(array[i], end = ' ') diff --git a/algorithms/strings/count_binary_substring.py b/algorithms/strings/count_binary_substring.py index bd775ee53..b766d12c9 100644 --- a/algorithms/strings/count_binary_substring.py +++ b/algorithms/strings/count_binary_substring.py @@ -18,16 +18,39 @@ Explanation: There are 4 substrings: "10", "01", "10", "01" that have equal number of consecutive 1's and 0's. Reference: https://leetcode.com/problems/count-binary-substrings/description/ """ +branch_coverage = { + "check_5": False, + "check_6": False, + "check_7": False, +} + def count_binary_substring(s): + global branch_coverage cur = 1 pre = 0 count = 0 for i in range(1, len(s)): + branch_coverage["check_5"] = True if s[i] != s[i - 1]: + branch_coverage["check_6"] = True count = count + min(pre, cur) pre = cur cur = 1 else: + branch_coverage["check_7"] = True cur = cur + 1 count = count + min(pre, cur) return count + + +def print_coverage(): + total = len(branch_coverage) + reached_branches = sum(branch_coverage.values()) + percentage = (reached_branches / total) * 100 + for branch, hit in branch_coverage.items(): + print(f"{branch} was {'hit' if hit else 'not hit'}") + print(f"total Coverage: {percentage}%") + +count = count_binary_substring("01100110") + +print_coverage() diff --git a/algorithms/strings/first_unique_char.py b/algorithms/strings/first_unique_char.py index 44ba05e49..a1a57b521 100644 --- a/algorithms/strings/first_unique_char.py +++ b/algorithms/strings/first_unique_char.py @@ -11,17 +11,39 @@ Reference: https://leetcode.com/problems/first-unique-character-in-a-string/description/ """ + +branch_coverage = { + "branch_26": False, + "branch_27": False, + "branch_28": False, + "branch_29": False, + "branch_30": False, +} + def first_unique_char(s): """ :type s: str :rtype: int """ if (len(s) == 1): + branch_coverage["branch_26"] = True return 0 ban = [] for i in range(len(s)): + branch_coverage["branch_27"] = True if all(s[i] != s[k] for k in range(i + 1, len(s))) == True and s[i] not in ban: + branch_coverage["branch_28"] = True return i else: + branch_coverage["branch_29"] = True ban.append(s[i]) + branch_coverage["branch_30"] = True return -1 + +def print_coverage(): + for branch, hit in branch_coverage.items(): + print(f"{branch} was {'hit' if hit else 'not hit'}") + +first_unique_char("leetcode") +first_unique_char("loveleetcode") +print_coverage() diff --git a/algorithms/strings/strong_password.py b/algorithms/strings/strong_password.py index 85acd0223..b3e9317b8 100644 --- a/algorithms/strings/strong_password.py +++ b/algorithms/strings/strong_password.py @@ -29,15 +29,53 @@ Output: 1 (Because the password isn't strong, but she can make it strong by adding a single digit.) """ +branch_coverage = { + "strong_password_1": False, # if branch for any(i.isdigit() for i in password) == False + "strong_password_2": False, # if branch for any(i.islower() for i in password) == False + "strong_password_3": False, # if branch for any(i.isupper() for i in password) == False + "strong_password_4": False, # if branch for any(i in '!@#$%^&*()-+' for i in password) == False + "strong_password_5": False # invisible else branch + +} +counter = 0 + def strong_password(n, password): count_error = 0 # Return the minimum number of characters to make the password strong if any(i.isdigit() for i in password) == False: + branch_coverage["strong_password_1"] = True count_error = count_error + 1 if any(i.islower() for i in password) == False: + branch_coverage["strong_password_2"] = True count_error = count_error + 1 if any(i.isupper() for i in password) == False: + branch_coverage["strong_password_3"] = True count_error = count_error + 1 if any(i in '!@#$%^&*()-+' for i in password) == False: + branch_coverage["strong_password_4"] = True count_error = count_error + 1 + + branch_coverage["strong_password_5"] = True return max(count_error, 6 - n) + + +def print_coverage(): + for branch, hit in branch_coverage.items(): + print(f"{branch} was {'hit' if hit else 'not hit'}") + total = len(branch_coverage) + hit = sum(branch_coverage.values()) + result = hit / total * 100 + print("The total branch coverage is:", result, "%" ) + + +strong_password(11, "#Algorithms") +print_coverage() +print("\n") +strong_password(5, "12345") +print_coverage() +print("\n") +strong_password(5, "abcde") +print_coverage() +print("\n") +strong_password(3, "Ab1") +print_coverage() diff --git a/algorithms/unix/path/simplify_path.py b/algorithms/unix/path/simplify_path.py index 8880fc0c6..8f993b763 100644 --- a/algorithms/unix/path/simplify_path.py +++ b/algorithms/unix/path/simplify_path.py @@ -15,6 +15,12 @@ Reference: https://leetcode.com/problems/simplify-path/description/ """ +branch_coverage = { + "for": False, + "if": False, + "elif": False, +} + import os def simplify_path_v1(path): return os.path.abspath(path) @@ -22,8 +28,28 @@ def simplify_path_v1(path): def simplify_path_v2(path): stack, tokens = [], path.split("/") for token in tokens: + branch_coverage["for"] = True if token == ".." and stack: + branch_coverage["if"] = True stack.pop() elif token != ".." and token != "." and token: + branch_coverage["elif"] = True stack.append(token) + return "/" + "/".join(stack) + +def print_coverage(): + covered = 0 + print("branch coverage for `simplify_path_v2`:") + for branch, hit in branch_coverage.items(): + print(f"{branch} was {'hit' if hit else 'not hit'}") + if hit: covered += 1; + print(f"Branch coverage: {covered / len(branch_coverage) * 100}") + + +# simplify_path_v2(".") +# simplify_path_v2("/../") +# simplify_path_v2("/home//foo/") +# simplify_path_v2("") +# simplify_path_v2("/home/../") +print_coverage() diff --git a/branch-coverage.py b/branch-coverage.py new file mode 100644 index 000000000..04ab54c8f --- /dev/null +++ b/branch-coverage.py @@ -0,0 +1,4 @@ +import subprocess + +subprocess.run(["coverage", "run", "--branch", "-m", "pytest", "tests"]) +subprocess.run(["coverage", "report"]) \ No newline at end of file diff --git a/image-1.png b/image-1.png new file mode 100644 index 000000000..7071337a2 Binary files /dev/null and b/image-1.png differ diff --git a/image-10.png b/image-10.png new file mode 100644 index 000000000..7e4ab2a58 Binary files /dev/null and b/image-10.png differ diff --git a/image-11.png b/image-11.png new file mode 100644 index 000000000..cebd821ad Binary files /dev/null and b/image-11.png differ diff --git a/image-12.png b/image-12.png new file mode 100644 index 000000000..5401aea73 Binary files /dev/null and b/image-12.png differ diff --git a/image-2.png b/image-2.png new file mode 100644 index 000000000..77702129e Binary files /dev/null and b/image-2.png differ diff --git a/image-3.png b/image-3.png new file mode 100644 index 000000000..61fc9d074 Binary files /dev/null and b/image-3.png differ diff --git a/image-4.png b/image-4.png new file mode 100644 index 000000000..9b5c60694 Binary files /dev/null and b/image-4.png differ diff --git a/image-5.png b/image-5.png new file mode 100644 index 000000000..e65d38265 Binary files /dev/null and b/image-5.png differ diff --git a/image-6.png b/image-6.png new file mode 100644 index 000000000..78045907d Binary files /dev/null and b/image-6.png differ diff --git a/image-7.png b/image-7.png new file mode 100644 index 000000000..ffd360b0f Binary files /dev/null and b/image-7.png differ diff --git a/image-8.png b/image-8.png new file mode 100644 index 000000000..6e6eab6b2 Binary files /dev/null and b/image-8.png differ diff --git a/image-9.png b/image-9.png new file mode 100644 index 000000000..2a59acdd5 Binary files /dev/null and b/image-9.png differ diff --git a/image.png b/image.png new file mode 100644 index 000000000..2a9ba91c1 Binary files /dev/null and b/image.png differ diff --git a/result_image-2.png b/result_image-2.png new file mode 100644 index 000000000..1106174d2 Binary files /dev/null and b/result_image-2.png differ diff --git a/result_image_2.png b/result_image_2.png new file mode 100644 index 000000000..3cc6c8190 Binary files /dev/null and b/result_image_2.png differ diff --git a/stoog_sort_image1.png b/stoog_sort_image1.png new file mode 100644 index 000000000..98f6c7c6d Binary files /dev/null and b/stoog_sort_image1.png differ diff --git a/stoog_sort_image2.png b/stoog_sort_image2.png new file mode 100644 index 000000000..f71cf5261 Binary files /dev/null and b/stoog_sort_image2.png differ diff --git a/tests/test_array.py b/tests/test_array.py index f1ad11693..b73ecb17b 100644 --- a/tests/test_array.py +++ b/tests/test_array.py @@ -9,7 +9,7 @@ missing_ranges, move_zeros, plus_one_v1, plus_one_v2, plus_one_v3, - remove_duplicates + remove_duplicates, rotate_v1, rotate_v2, rotate_v3, summarize_ranges, three_sum, diff --git a/tests/test_dp.py b/tests/test_dp.py index e92800a11..e1f2ab8cd 100644 --- a/tests/test_dp.py +++ b/tests/test_dp.py @@ -14,7 +14,8 @@ longest_increasing_subsequence_optimized, longest_increasing_subsequence_optimized2, int_divide,find_k_factor, - planting_trees, regex_matching + planting_trees, regex_matching, + word_break, ) @@ -258,6 +259,16 @@ def test_symbol_2(self): p = "ab*" self.assertTrue(regex_matching.is_match(s, p)) +class TestWordBreak(unittest.TestCase): + """Test for interpolation_search and word_break""" + + def test_word_break(self): + self.assertTrue(word_break("keonkim", {"keon", "kim"})) + self.assertTrue(word_break("leetcode", {"leet", "code"})) + self.assertFalse(word_break("catsandog", {"cats", "dog", "sand", "and", "cat"})) + self.assertTrue(word_break("applepenapple", {"apple", "pen"})) + self.assertFalse(word_break("pineapplepenapple", {"apple", "pen"})) + self.assertTrue(word_break("aaaaaaa", {"aaaa", "aaa"})) if __name__ == '__main__': unittest.main() diff --git a/tests/test_maths.py b/tests/test_maths.py index c4a54af03..8d6e5f383 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -1,3 +1,6 @@ +from algorithms.maths.prime_check import prime_check, print_coverage +import unittest + from algorithms.maths import ( power, power_recur, int_to_base, base_to_int, @@ -276,17 +279,45 @@ class TestPrimeTest(unittest.TestCase): Arguments: unittest {[type]} -- [description] """ + - def test_prime_test(self): + def test_prime_numbers(self): """ - checks all prime numbers between 2 up to 100. - Between 2 up to 100 exists 25 prime numbers! + Checks specific prime numbers between 2 up to 100. """ - counter = 0 - for i in range(2, 101): - if prime_check(i): - counter += 1 - self.assertEqual(25, counter) + primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97] + for prime in primes: + with self.subTest(n=prime): + self.assertTrue(prime_check(prime), f"{prime} should be prime") + + def test_non_prime_numbers(self): + """ + Checks specific non-prime numbers between 2 up to 100. + """ + non_primes = [4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 22, 24, 25, 26, 27, 28, 30, 32, 33, 34, 35, 36, 38, 39, 40, 42, 44, 45, 46, 48, 49, 50, 51, 52, 54, 55, 56, 57, 58, 60, 62, 63, 64, 65, 66, 68, 69, 70, 72, 74, 75, 76, 77, 78, 80, 81, 82, 84, 85, 86, 87, 88, 90, 91, 92, 93, 94, 95, 96, 98, 99, 100] + for non_prime in non_primes: + with self.subTest(n=non_prime): + self.assertFalse(prime_check(non_prime), f"{non_prime} should not be prime") + + def test_prime_check_coverage(self): + """ + Additional checks to cover all branches in prime_check function. + """ + self.assertFalse(prime_check(-1), "-1 should not be prime") # Branch 1 + self.assertFalse(prime_check(0), "0 should not be prime") # Branch 1 + self.assertFalse(prime_check(1), "1 should not be prime") # Branch 1 + self.assertTrue(prime_check(2), "2 should be prime") # Branch 2 + self.assertTrue(prime_check(3), "3 should be prime") # Branch 2 + self.assertFalse(prime_check(4), "4 should not be prime") # Branch 3 + self.assertFalse(prime_check(9), "9 should not be prime") # Branch 3 + self.assertFalse(prime_check(15), "15 should not be prime") # Branch 3, 4, 5 + self.assertTrue(prime_check(5), "5 should be prime") # Branch 4 + self.assertTrue(prime_check(7), "7 should be prime") # Branch 4 + self.assertFalse(prime_check(25), "25 should not be prime") # Branch 5 + self.assertFalse(prime_check(49), "49 should not be prime") # Branch 5 + self.assertFalse(prime_check(50), "50 should not be prime") # Branch 3 + self.assertTrue(prime_check(97), "97 should be prime") # Branch 4 + class TestPythagoras(unittest.TestCase): @@ -301,6 +332,16 @@ def test_pythagoras(self): self.assertEqual("Hypotenuse = 3.605551275463989", pythagoras(3, 2, "?")) + def test_opposite_calculation(self): + result = pythagoras("?", 4, 5) + expected = "Opposite = 3.0" + self.assertEqual(result, expected) + + def test_adjacent_calculation(self): + result = pythagoras(3, "?", 5) + expected = "Adjacent = 4.0" + self.assertEqual(result, expected) + class TestRabinMiller(unittest.TestCase): """[summary] @@ -434,10 +475,12 @@ class TestFindOrder(unittest.TestCase): """ def test_find_order_simple(self): - self.assertEqual(1, find_order(1, 1)) + self.assertEqual(1, find_order(1, 1)) # Should hit branch_1 self.assertEqual(6, find_order(3, 7)) self.assertEqual(-1, find_order(128, 256)) self.assertEqual(352, find_order(3, 353)) + self.assertEqual(-1, find_order(10, 20)) # Should hit branches 2, 3, 5 + class TestKrishnamurthyNumber(unittest.TestCase): diff --git a/tests/test_matrix.py b/tests/test_matrix.py index 262fdbe62..5961680cc 100644 --- a/tests/test_matrix.py +++ b/tests/test_matrix.py @@ -15,6 +15,8 @@ ) import unittest +from algorithms.matrix.rotate_image import rotate + class TestBombEnemy(unittest.TestCase): def test_3x4(self): @@ -228,6 +230,8 @@ def test_rotate_image(self): self.assertEqual(rotate_image.rotate( [[1, 2, 3], [4, 5, 6], [7, 8, 9]]), [[7, 4, 1], [8, 5, 2], [9, 6, 3]]) + self.assertEqual([],rotate_image.rotate([])) + self.assertEqual([[3, 1], [4, 2]],rotate([[1, 2], [3, 4]])) class TestSparseDotVector(unittest.TestCase): diff --git a/tests/test_search.py b/tests/test_search.py index f515cfcb9..f414cacc1 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -139,13 +139,28 @@ def test_next_greatest_letter(self): self.assertEqual("c", next_greatest_letter_v2(letters, target)) def test_interpolation_search(self): - array = [0, 3, 5, 5, 9, 12, 12, 15, 16, 19, 20] + array = [0, 3, 5, 5, 9, 12, 12, 15, 16, 19, 20, 25] + #, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100] + + # array = [0, 3, 5, 5, 9, 12, 12, 15, 16, 19, 20, 25] self.assertEqual(1, interpolation_search(array, 3)) self.assertEqual(2, interpolation_search(array, 5)) - self.assertEqual(6, interpolation_search(array, 12)) + self.assertEqual(5, interpolation_search(array, 12)) self.assertEqual(-1, interpolation_search(array, 22)) self.assertEqual(-1, interpolation_search(array, -10)) self.assertEqual(10, interpolation_search(array, 20)) + + # self.assertEqual(-1, interpolation_search(array, 1)) + # self.assertEqual(0, interpolation_search(array, 0)) # Found at the start + # self.assertEqual(interpolation_search(array, 12), 5) # Found in the middle, first occurrence + # self.assertEqual(-1, interpolation_search(array, 110)) # Not found, above maximum + # self.assertEqual(interpolation_search(array, 55), 17) # Found in the middle + # self.assertEqual(interpolation_search(array, 70), 20) # Found, single value in range + # self.assertEqual(interpolation_search(array, 22), -1) # Not found, above the range + # self.assertEqual(interpolation_search(array, 50), 16) # Found, single value in range + # self.assertEqual(interpolation_search(array, 45), 15) # Found, single value in range + + if __name__ == '__main__': diff --git a/tests/test_sort.py b/tests/test_sort.py index c80290fdf..10113348e 100644 --- a/tests/test_sort.py +++ b/tests/test_sort.py @@ -17,7 +17,8 @@ radix_sort, gnome_sort, cocktail_shaker_sort, - top_sort, top_sort_recursive + top_sort, top_sort_recursive, + stoogesort ) import unittest @@ -124,7 +125,27 @@ def test_topsort(self): self.assertTrue(res.index('g') < res.index('e')) res = top_sort(self.depGraph) self.assertTrue(res.index('g') < res.index('e')) - +class TestStoog(unittest.TestCase): + def test_stoogesort(self): + arr1 = [1, 3, 64, 5, 7, 8] + stoogesort(arr1, 0, len(arr1) - 1) + self.assertEqual(arr1, [1, 3, 5, 7, 8, 64]) + + arr2 = [5, 4, 3, 2, 1] + stoogesort(arr2, 0, len(arr2) - 1) + self.assertEqual(arr2, [1, 2, 3, 4, 5]) + + arr3 = [1, 2, 3, 4, 5] + stoogesort(arr3, 0, len(arr3) - 1) + self.assertEqual(arr3, [1, 2, 3, 4, 5]) + + arr4 = [10, -1, 2, 3, 0] + stoogesort(arr4, 0, len(arr4) - 1) + self.assertEqual(arr4, [-1, 0, 2, 3, 10]) + + arr5 = [] + stoogesort(arr5, 0, len(arr5) - 1) + self.assertEqual(arr5, []) if __name__ == "__main__": unittest.main() diff --git a/tests/test_strings.py b/tests/test_strings.py index e7a68302a..4a4c8da90 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -479,6 +479,8 @@ class TestStrongPassword(unittest.TestCase): def test_strong_password(self): self.assertEqual(3, strong_password(3, "Ab1")) self.assertEqual(1, strong_password(11, "#Algorithms")) + self.assertEqual(3,strong_password(5, "12345")) + self.assertEqual(3,strong_password(5, "abcde")) class TestCaesarCipher(unittest.TestCase): @@ -568,6 +570,7 @@ class TestFirstUniqueChar(unittest.TestCase): def test_first_unique_char(self): self.assertEqual(0, first_unique_char("leetcode")) self.assertEqual(2, first_unique_char("loveleetcode")) + self.assertEqual(-1, first_unique_char("aabb")) class TestRepeatSubstring(unittest.TestCase): diff --git a/tests/test_unix.py b/tests/test_unix.py index 3cafba98f..e53881ef1 100644 --- a/tests/test_unix.py +++ b/tests/test_unix.py @@ -7,6 +7,9 @@ import os import unittest +from algorithms.unix import ( + print_coverage +) class TestUnixPath(unittest.TestCase): def test_join_with_slash(self): @@ -42,7 +45,26 @@ def test_split(self): self.assertEqual("test.py", expect_result[1]) def test_simplify_path(self): - self.assertEqual("/", simplify_path_v1("/../")) - self.assertEqual("/home/foo", simplify_path_v1("/home//foo/")) + root = None + pathsep = None + drive = None + if os.name == 'nt': + root = "" # Assumed to be ran on the C drive + pathsep = "\\" + drive = "C:\\" + elif os.name == 'posix': + root = "/" + pathsep = "/" + drive = "" + + self.assertEqual(drive + root, simplify_path_v1("/../")) + self.assertEqual(drive + root + pathsep.join(["home", "foo"]), simplify_path_v1("/home//foo/")) + + self.assertEqual("/", simplify_path_v2(".")) self.assertEqual("/", simplify_path_v2("/../")) self.assertEqual("/home/foo", simplify_path_v2("/home//foo/")) + self.assertEqual("/", simplify_path_v2("")) + self.assertEqual("/", simplify_path_v2("/home/../")) + + print_coverage() + diff --git a/word_break_image1.png b/word_break_image1.png new file mode 100644 index 000000000..ae218cd53 Binary files /dev/null and b/word_break_image1.png differ diff --git a/word_break_image2.png b/word_break_image2.png new file mode 100644 index 000000000..48e868406 Binary files /dev/null and b/word_break_image2.png differ