├── .coveragerc
├── .github
└── workflows
│ └── python-app.yml
├── .gitignore
├── .travis.yml
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── MANIFEST.in
├── README.md
├── algorithms
├── __init__.py
├── arrays
│ ├── __init__.py
│ ├── delete_nth.py
│ ├── flatten.py
│ ├── garage.py
│ ├── josephus.py
│ ├── limit.py
│ ├── longest_non_repeat.py
│ ├── max_ones_index.py
│ ├── merge_intervals.py
│ ├── missing_ranges.py
│ ├── move_zeros.py
│ ├── n_sum.py
│ ├── plus_one.py
│ ├── remove_duplicates.py
│ ├── rotate.py
│ ├── summarize_ranges.py
│ ├── three_sum.py
│ ├── top_1.py
│ ├── trimmean.py
│ └── two_sum.py
├── automata
│ ├── __init__.py
│ └── dfa.py
├── backtrack
│ ├── __init__.py
│ ├── add_operators.py
│ ├── anagram.py
│ ├── array_sum_combinations.py
│ ├── combination_sum.py
│ ├── factor_combinations.py
│ ├── find_words.py
│ ├── generate_abbreviations.py
│ ├── generate_parenthesis.py
│ ├── letter_combination.py
│ ├── palindrome_partitioning.py
│ ├── pattern_match.py
│ ├── permute.py
│ ├── permute_unique.py
│ ├── subsets.py
│ └── subsets_unique.py
├── bfs
│ ├── __init__.py
│ ├── count_islands.py
│ ├── maze_search.py
│ ├── shortest_distance_from_all_buildings.py
│ └── word_ladder.py
├── bit
│ ├── __init__.py
│ ├── add_bitwise_operator.py
│ ├── binary_gap.py
│ ├── bit_operation.py
│ ├── bytes_int_conversion.py
│ ├── count_flips_to_convert.py
│ ├── count_ones.py
│ ├── find_difference.py
│ ├── find_missing_number.py
│ ├── flip_bit_longest_sequence.py
│ ├── has_alternative_bit.py
│ ├── insert_bit.py
│ ├── power_of_two.py
│ ├── remove_bit.py
│ ├── reverse_bits.py
│ ├── single_number.py
│ ├── single_number2.py
│ ├── single_number3.py
│ ├── subsets.py
│ └── swap_pair.py
├── compression
│ ├── __init__.py
│ ├── elias.py
│ ├── huffman_coding.py
│ └── rle_compression.py
├── dfs
│ ├── __init__.py
│ ├── all_factors.py
│ ├── count_islands.py
│ ├── maze_search.py
│ ├── pacific_atlantic.py
│ ├── sudoku_solver.py
│ └── walls_and_gates.py
├── distribution
│ ├── __init__.py
│ └── histogram.py
├── dp
│ ├── __init__.py
│ ├── buy_sell_stock.py
│ ├── climbing_stairs.py
│ ├── coin_change.py
│ ├── combination_sum.py
│ ├── edit_distance.py
│ ├── egg_drop.py
│ ├── fib.py
│ ├── hosoya_triangle.py
│ ├── house_robber.py
│ ├── int_divide.py
│ ├── job_scheduling.py
│ ├── k_factor.py
│ ├── knapsack.py
│ ├── longest_common_subsequence.py
│ ├── longest_increasing.py
│ ├── matrix_chain_order.py
│ ├── max_product_subarray.py
│ ├── max_subarray.py
│ ├── min_cost_path.py
│ ├── num_decodings.py
│ ├── planting_trees.py
│ ├── regex_matching.py
│ ├── rod_cut.py
│ └── word_break.py
├── graph
│ ├── __init__.py
│ ├── all_pairs_shortest_path.py
│ ├── bellman_ford.py
│ ├── check_bipartite.py
│ ├── check_digraph_strongly_connected.py
│ ├── clone_graph.py
│ ├── count_connected_number_of_component.py
│ ├── cycle_detection.py
│ ├── dijkstra.py
│ ├── find_all_cliques.py
│ ├── find_path.py
│ ├── graph.py
│ ├── markov_chain.py
│ ├── maximum_flow.py
│ ├── maximum_flow_bfs.py
│ ├── maximum_flow_dfs.py
│ ├── minimum_spanning_tree.py
│ ├── path_between_two_vertices_in_digraph.py
│ ├── prims_minimum_spanning.py
│ ├── satisfiability.py
│ ├── strongly_connected_components_kosaraju.py
│ ├── tarjan.py
│ ├── transitive_closure_dfs.py
│ └── traversal.py
├── greedy
│ ├── __init__.py
│ └── max_contiguous_subsequence_sum.py
├── heap
│ ├── __init__.py
│ ├── binary_heap.py
│ ├── k_closest_points.py
│ ├── merge_sorted_k_lists.py
│ ├── skyline.py
│ └── sliding_window_max.py
├── linkedlist
│ ├── __init__.py
│ ├── add_two_numbers.py
│ ├── copy_random_pointer.py
│ ├── delete_node.py
│ ├── first_cyclic_node.py
│ ├── intersection.py
│ ├── is_cyclic.py
│ ├── is_palindrome.py
│ ├── is_sorted.py
│ ├── kth_to_last.py
│ ├── linkedlist.py
│ ├── merge_two_list.py
│ ├── partition.py
│ ├── remove_duplicates.py
│ ├── remove_range.py
│ ├── reverse.py
│ ├── rotate_list.py
│ └── swap_in_pairs.py
├── map
│ ├── __init__.py
│ ├── hashtable.py
│ ├── is_anagram.py
│ ├── is_isomorphic.py
│ ├── longest_common_subsequence.py
│ ├── longest_palindromic_subsequence.py
│ ├── randomized_set.py
│ ├── separate_chaining_hashtable.py
│ ├── valid_sudoku.py
│ └── word_pattern.py
├── maths
│ ├── __init__.py
│ ├── base_conversion.py
│ ├── chinese_remainder_theorem.py
│ ├── combination.py
│ ├── cosine_similarity.py
│ ├── decimal_to_binary_ip.py
│ ├── diffie_hellman_key_exchange.py
│ ├── euler_totient.py
│ ├── extended_gcd.py
│ ├── factorial.py
│ ├── fft.py
│ ├── find_order_simple.py
│ ├── find_primitive_root_simple.py
│ ├── gcd.py
│ ├── generate_strobogrammtic.py
│ ├── hailstone.py
│ ├── is_strobogrammatic.py
│ ├── krishnamurthy_number.py
│ ├── magic_number.py
│ ├── modular_exponential.py
│ ├── modular_inverse.py
│ ├── next_bigger.py
│ ├── next_perfect_square.py
│ ├── nth_digit.py
│ ├── num_digits.py
│ ├── num_perfect_squares.py
│ ├── polynomial.py
│ ├── power.py
│ ├── prime_check.py
│ ├── primes_sieve_of_eratosthenes.py
│ ├── pythagoras.py
│ ├── rabin_miller.py
│ ├── recursive_binomial_coefficient.py
│ ├── rsa.py
│ ├── sqrt_precision_factor.py
│ ├── summing_digits.py
│ └── symmetry_group_cycle_index.py
├── matrix
│ ├── __init__.py
│ ├── bomb_enemy.py
│ ├── cholesky_matrix_decomposition.py
│ ├── copy_transform.py
│ ├── count_paths.py
│ ├── crout_matrix_decomposition.py
│ ├── matrix_exponentiation.py
│ ├── matrix_inversion.py
│ ├── multiply.py
│ ├── rotate_image.py
│ ├── search_in_sorted_matrix.py
│ ├── sort_matrix_diagonally.py
│ ├── sparse_dot_vector.py
│ ├── sparse_mul.py
│ ├── spiral_traversal.py
│ ├── sudoku_validator.py
│ └── sum_sub_squares.py
├── ml
│ └── nearest_neighbor.py
├── queues
│ ├── __init__.py
│ ├── max_sliding_window.py
│ ├── moving_average.py
│ ├── priority_queue.py
│ ├── queue.py
│ ├── reconstruct_queue.py
│ └── zigzagiterator.py
├── search
│ ├── __init__.py
│ ├── binary_search.py
│ ├── find_min_rotate.py
│ ├── first_occurrence.py
│ ├── interpolation_search.py
│ ├── jump_search.py
│ ├── last_occurrence.py
│ ├── linear_search.py
│ ├── next_greatest_letter.py
│ ├── search_insert.py
│ ├── search_range.py
│ ├── search_rotate.py
│ ├── ternary_search.py
│ └── two_sum.py
├── set
│ ├── __init__.py
│ ├── find_keyboard_row.py
│ ├── randomized_set.py
│ └── set_covering.py
├── sort
│ ├── __init__.py
│ ├── bitonic_sort.py
│ ├── bogo_sort.py
│ ├── bubble_sort.py
│ ├── bucket_sort.py
│ ├── cocktail_shaker_sort.py
│ ├── comb_sort.py
│ ├── counting_sort.py
│ ├── cycle_sort.py
│ ├── exchange_sort.py
│ ├── gnome_sort.py
│ ├── heap_sort.py
│ ├── insertion_sort.py
│ ├── meeting_rooms.py
│ ├── merge_sort.py
│ ├── pancake_sort.py
│ ├── pigeonhole_sort.py
│ ├── quick_sort.py
│ ├── radix_sort.py
│ ├── selection_sort.py
│ ├── shell_sort.py
│ ├── sort_colors.py
│ ├── stooge_sort.py
│ ├── top_sort.py
│ └── wiggle_sort.py
├── stack
│ ├── __init__.py
│ ├── is_consecutive.py
│ ├── is_sorted.py
│ ├── longest_abs_path.py
│ ├── ordered_stack.py
│ ├── remove_min.py
│ ├── simplify_path.py
│ ├── stack.py
│ ├── stutter.py
│ ├── switch_pairs.py
│ └── valid_parenthesis.py
├── streaming
│ ├── __init__.py
│ ├── misra_gries.py
│ └── one_sparse_recovery.py
├── strings
│ ├── __init__.py
│ ├── add_binary.py
│ ├── atbash_cipher.py
│ ├── breaking_bad.py
│ ├── caesar_cipher.py
│ ├── check_pangram.py
│ ├── contain_string.py
│ ├── count_binary_substring.py
│ ├── decode_string.py
│ ├── delete_reoccurring.py
│ ├── domain_extractor.py
│ ├── encode_decode.py
│ ├── first_unique_char.py
│ ├── fizzbuzz.py
│ ├── group_anagrams.py
│ ├── int_to_roman.py
│ ├── is_palindrome.py
│ ├── is_rotated.py
│ ├── judge_circle.py
│ ├── knuth_morris_pratt.py
│ ├── license_number.py
│ ├── longest_common_prefix.py
│ ├── longest_palindromic_substring.py
│ ├── make_sentence.py
│ ├── merge_string_checker.py
│ ├── min_distance.py
│ ├── multiply_strings.py
│ ├── one_edit_distance.py
│ ├── panagram.py
│ ├── rabin_karp.py
│ ├── repeat_string.py
│ ├── repeat_substring.py
│ ├── reverse_string.py
│ ├── reverse_vowel.py
│ ├── reverse_words.py
│ ├── roman_to_int.py
│ ├── rotate.py
│ ├── strip_url_params.py
│ ├── strong_password.py
│ ├── text_justification.py
│ ├── unique_morse.py
│ ├── validate_coordinates.py
│ └── word_squares.py
├── tree
│ ├── __init__.py
│ ├── avl
│ │ ├── __init__.py
│ │ └── avl.py
│ ├── b_tree.py
│ ├── bin_tree_to_list.py
│ ├── binary_tree_paths.py
│ ├── bst
│ │ ├── BSTIterator.py
│ │ ├── array_to_bst.py
│ │ ├── bst.py
│ │ ├── bst_closest_value.py
│ │ ├── count_left_node.py
│ │ ├── delete_node.py
│ │ ├── depth_sum.py
│ │ ├── height.py
│ │ ├── is_bst.py
│ │ ├── kth_smallest.py
│ │ ├── lowest_common_ancestor.py
│ │ ├── num_empty.py
│ │ ├── predecessor.py
│ │ ├── serialize_deserialize.py
│ │ ├── successor.py
│ │ └── unique_bst.py
│ ├── construct_tree_postorder_preorder.py
│ ├── deepest_left.py
│ ├── fenwick_tree
│ │ └── fenwick_tree.py
│ ├── invert_tree.py
│ ├── is_balanced.py
│ ├── is_subtree.py
│ ├── is_symmetric.py
│ ├── longest_consecutive.py
│ ├── lowest_common_ancestor.py
│ ├── max_height.py
│ ├── max_path_sum.py
│ ├── min_height.py
│ ├── path_sum.py
│ ├── path_sum2.py
│ ├── pretty_print.py
│ ├── red_black_tree
│ │ └── red_black_tree.py
│ ├── same_tree.py
│ ├── segment_tree
│ │ ├── iterative_segment_tree.py
│ │ └── segment_tree.py
│ ├── traversal
│ │ ├── __init__.py
│ │ ├── inorder.py
│ │ ├── level_order.py
│ │ ├── postorder.py
│ │ ├── preorder.py
│ │ └── zigzag.py
│ ├── tree.py
│ └── trie
│ │ ├── add_and_search.py
│ │ └── trie.py
├── unionfind
│ └── count_islands.py
└── unix
│ ├── __init__.py
│ └── path
│ ├── full_path.py
│ ├── join_with_slash.py
│ ├── simplify_path.py
│ └── split.py
├── docs
├── Makefile
├── make.bat
├── requirements.txt
└── source
│ ├── _static
│ ├── algorithms_logo.png
│ └── logo
│ │ ├── 128pxblack.png
│ │ ├── 128pxblack.svg
│ │ ├── 128pxblue.png
│ │ ├── 128pxblue.svg
│ │ ├── 128pxorange.png
│ │ ├── 128pxorange.svg
│ │ ├── 256pxblack.png
│ │ ├── 256pxblack.svg
│ │ ├── 256pxblue.png
│ │ ├── 256pxblue.svg
│ │ ├── 256pxorange.png
│ │ ├── 256pxorange.svg
│ │ ├── 512pxblack.png
│ │ ├── 512pxblack.svg
│ │ ├── 512pxblue.png
│ │ ├── 512pxblue.svg
│ │ ├── 512pxorange.png
│ │ ├── 512pxorange.svg
│ │ ├── add
│ │ ├── logotype1black.png
│ │ ├── logotype1black.svg
│ │ ├── logotype1blue.png
│ │ ├── logotype1blue.svg
│ │ ├── logotype1orange.png
│ │ ├── logotype1orange.svg
│ │ ├── logotype2black.png
│ │ ├── logotype2black.svg
│ │ ├── logotype2blue.png
│ │ ├── logotype2blue.svg
│ │ ├── logotype2orange.png
│ │ └── logotype2orange.svg
│ ├── arrays.rst
│ ├── backtrack.rst
│ ├── bfs.rst
│ ├── bit.rst
│ ├── conf.py
│ ├── dfs.rst
│ ├── dp.rst
│ ├── examples.rst
│ ├── graph.rst
│ ├── heap.rst
│ ├── index.rst
│ ├── linkedlist.rst
│ ├── map.rst
│ ├── maths.rst
│ ├── matrix.rst
│ ├── queues.rst
│ ├── search.rst
│ ├── set.rst
│ ├── sort.rst
│ ├── stack.rst
│ ├── strings.rst
│ └── tree.rst
├── requirements.txt
├── setup.py
├── test_requirements.txt
├── tests
├── test_array.py
├── test_automata.py
├── test_backtrack.py
├── test_bfs.py
├── test_bit.py
├── test_compression.py
├── test_dfs.py
├── test_dp.py
├── test_graph.py
├── test_greedy.py
├── test_heap.py
├── test_histogram.py
├── test_iterative_segment_tree.py
├── test_linkedlist.py
├── test_map.py
├── test_maths.py
├── test_matrix.py
├── test_ml.py
├── test_monomial.py
├── test_polynomial.py
├── test_queues.py
├── test_search.py
├── test_set.py
├── test_sort.py
├── test_stack.py
├── test_streaming.py
├── test_strings.py
├── test_tree.py
└── test_unix.py
└── tox.ini
/.coveragerc:
--------------------------------------------------------------------------------
1 | [report]
2 | omit =
3 | */python?.?/*
4 | */site-packages/nose/*
5 | *__init__*
6 |
--------------------------------------------------------------------------------
/.github/workflows/python-app.yml:
--------------------------------------------------------------------------------
1 | # This workflow will install Python dependencies, run tests and lint with a single version of Python
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
3 |
4 | name: Python application
5 |
6 | on:
7 | push:
8 | branches: [ master ]
9 | pull_request:
10 | branches: [ master ]
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v2
19 | - name: Set up Python 3.10
20 | uses: actions/setup-python@v2
21 | with:
22 | python-version: "3.10"
23 | - name: Install dependencies
24 | run: |
25 | python -m pip install --upgrade pip
26 | pip install flake8 pytest
27 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
28 | - name: Lint with flake8
29 | run: |
30 | # stop the build if there are Python syntax errors or undefined names
31 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
32 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
33 | flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
34 | - name: Test with pytest
35 | run: |
36 | python -m pytest
37 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__/
2 | *.py[cod]
3 | *.iml
4 | *.xml
5 | .idea/
6 | .cache/
7 | .pytest_cache/
8 | .coverage
9 | # Setuptools distribution folder.
10 | /dist/
11 | # Python egg metadata, regenerated from source files by setuptools.
12 | /*.egg-info
13 | /*.egg
14 | # docs
15 | build/
16 | pythonenv3.8/
17 | .vscode/
18 | # Ignoring the virtual Environment when using GitHub Codespaces
19 | .venv/
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | group: travis_latest
2 | dist: xenial # Travis CI's default distro
3 | language: python
4 | cache:
5 | directories:
6 | - $HOME/.cache/pip
7 | matrix:
8 | include:
9 | - python: 3.6
10 | env: TOX_ENV=py36
11 | - python: 3.7
12 | env: TOX_ENV=py37
13 | install:
14 | - pip install -r test_requirements.txt
15 | before_script:
16 | # run black to check if some files would need reformatting
17 | - black --check . || true
18 | # stop the build if there are Python syntax errors or undefined names
19 | - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
20 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
21 | - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
22 | script:
23 | # Check python install package
24 | - pip install -e .
25 | - tox -e $TOX_ENV
26 | # Check python uninstall package
27 | - pip uninstall -y algorithms
28 | notifications:
29 | on_success: change
30 | on_failure: change # `always` will be the setting once code changes slow down
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Keon
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 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include README.md
2 | include LICENSE
3 | include algorithms/*
4 |
--------------------------------------------------------------------------------
/algorithms/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/cad4754bc71742c2d6fcbd3b92ae74834d359844/algorithms/__init__.py
--------------------------------------------------------------------------------
/algorithms/arrays/__init__.py:
--------------------------------------------------------------------------------
1 | from .delete_nth import *
2 | from .flatten import *
3 | from .garage import *
4 | from .josephus import *
5 | from .longest_non_repeat import *
6 | from .max_ones_index import *
7 | from .merge_intervals import *
8 | from .missing_ranges import *
9 | from .move_zeros import *
10 | from .plus_one import *
11 | from .rotate import *
12 | from .summarize_ranges import *
13 | from .three_sum import *
14 | from .trimmean import *
15 | from .top_1 import *
16 | from .two_sum import *
17 | from .limit import *
18 | from .n_sum import *
19 | from .remove_duplicates import *
--------------------------------------------------------------------------------
/algorithms/arrays/delete_nth.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a list lst and a number N, create a new list
3 | that contains each number of the list at most N times without reordering.
4 |
5 | For example if N = 2, and the input is [1,2,3,1,2,1,2,3], you take [1,2,3,1,2],
6 | drop the next [1,2] since this would lead to 1 and 2 being in the result 3 times, and then take 3,
7 | which leads to [1,2,3,1,2,3]
8 | """
9 | import collections
10 |
11 |
12 | # Time complexity O(n^2)
13 | def delete_nth_naive(array, n):
14 | ans = []
15 | for num in array:
16 | if ans.count(num) < n:
17 | ans.append(num)
18 | return ans
19 |
20 |
21 | # Time Complexity O(n), using hash tables.
22 | def delete_nth(array, n):
23 | result = []
24 | counts = collections.defaultdict(int) # keep track of occurrences
25 |
26 | for i in array:
27 |
28 | if counts[i] < n:
29 | result.append(i)
30 | counts[i] += 1
31 |
32 | return result
33 |
--------------------------------------------------------------------------------
/algorithms/arrays/flatten.py:
--------------------------------------------------------------------------------
1 | """
2 | Implement Flatten Arrays.
3 | Given an array that may contain nested arrays,
4 | produce a single resultant array.
5 | """
6 | from collections.abc import Iterable
7 |
8 |
9 | # return list
10 | def flatten(input_arr, output_arr=None):
11 | if output_arr is None:
12 | output_arr = []
13 | for ele in input_arr:
14 | if not isinstance(ele, str) and isinstance(ele, Iterable):
15 | flatten(ele, output_arr) #tail-recursion
16 | else:
17 | output_arr.append(ele) #produce the result
18 | return output_arr
19 |
20 |
21 | # returns iterator
22 | def flatten_iter(iterable):
23 | """
24 | Takes as input multi dimensional iterable and
25 | returns generator which produces one dimensional output.
26 | """
27 | for element in iterable:
28 | if not isinstance(element, str) and isinstance(element, Iterable):
29 | yield from flatten_iter(element)
30 | else:
31 | yield element
32 |
--------------------------------------------------------------------------------
/algorithms/arrays/josephus.py:
--------------------------------------------------------------------------------
1 | """
2 | There are people sitting in a circular fashion,
3 | print every third member while removing them,
4 | the next counter starts immediately after the member is removed.
5 | Print till all the members are exhausted.
6 |
7 | For example:
8 | Input: consider 123456789 members sitting in a circular fashion,
9 | Output: 369485271
10 | """
11 |
12 | def josephus(int_list, skip):
13 | skip = skip - 1 # list starts with 0 index
14 | idx = 0
15 | len_list = (len(int_list))
16 | while len_list > 0:
17 | idx = (skip + idx) % len_list # hash index to every 3rd
18 | yield int_list.pop(idx)
19 | len_list -= 1
20 |
--------------------------------------------------------------------------------
/algorithms/arrays/limit.py:
--------------------------------------------------------------------------------
1 | """
2 | Sometimes you need to limit array result to use. Such as you only need the
3 | value over 10 or, you need value under than 100. By use this algorithms, you
4 | can limit your array to specific value
5 |
6 | If array, Min, Max value was given, it returns array that contains values of
7 | given array which was larger than Min, and lower than Max. You need to give
8 | 'unlimit' to use only Min or Max.
9 |
10 | ex) limit([1,2,3,4,5], None, 3) = [1,2,3]
11 |
12 | Complexity = O(n)
13 | """
14 |
15 | # tl:dr -- array slicing by value
16 | def limit(arr, min_lim=None, max_lim=None):
17 | if len(arr) == 0:
18 | return arr
19 |
20 | if min_lim is None:
21 | min_lim = min(arr)
22 | if max_lim is None:
23 | max_lim = max(arr)
24 |
25 | return list(filter(lambda x: (min_lim <= x <= max_lim), arr))
26 |
--------------------------------------------------------------------------------
/algorithms/arrays/max_ones_index.py:
--------------------------------------------------------------------------------
1 | """
2 | Find the index of 0 to be replaced with 1 to get
3 | longest continuous sequence
4 | of 1s in a binary array.
5 | Returns index of 0 to be
6 | replaced with 1 to get longest
7 | continuous sequence of 1s.
8 | If there is no 0 in array, then
9 | it returns -1.
10 |
11 | e.g.
12 | let input array = [1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1]
13 | If we replace 0 at index 3 with 1, we get the longest continuous
14 | sequence of 1s in the array.
15 | So the function return => 3
16 | """
17 |
18 |
19 | def max_ones_index(arr):
20 |
21 | n = len(arr)
22 | max_count = 0
23 | max_index = 0
24 | prev_zero = -1
25 | prev_prev_zero = -1
26 |
27 | for curr in range(n):
28 |
29 | # If current element is 0,
30 | # then calculate the difference
31 | # between curr and prev_prev_zero
32 | if arr[curr] == 0:
33 | if curr - prev_prev_zero > max_count:
34 | max_count = curr - prev_prev_zero
35 | max_index = prev_zero
36 |
37 | prev_prev_zero = prev_zero
38 | prev_zero = curr
39 |
40 | if n - prev_prev_zero > max_count:
41 | max_index = prev_zero
42 |
43 | return max_index
44 |
--------------------------------------------------------------------------------
/algorithms/arrays/missing_ranges.py:
--------------------------------------------------------------------------------
1 | """
2 | Find missing ranges between low and high in the given array.
3 | Ex) [3, 5] lo=1 hi=10 => answer: [(1, 2), (4, 4), (6, 10)]
4 | """
5 |
6 | def missing_ranges(arr, lo, hi):
7 |
8 | res = []
9 | start = lo
10 |
11 | for n in arr:
12 |
13 | if n == start:
14 | start += 1
15 | elif n > start:
16 | res.append((start, n-1))
17 | start = n + 1
18 |
19 | if start <= hi: # after done iterating thru array,
20 | res.append((start, hi)) # append remainder to list
21 |
22 | return res
23 |
--------------------------------------------------------------------------------
/algorithms/arrays/move_zeros.py:
--------------------------------------------------------------------------------
1 | """
2 | Write an algorithm that takes an array and moves all of the zeros to the end,
3 | preserving the order of the other elements.
4 | move_zeros([false, 1, 0, 1, 2, 0, 1, 3, "a"])
5 | returns => [false, 1, 1, 2, 1, 3, "a", 0, 0]
6 |
7 | The time complexity of the below algorithm is O(n).
8 | """
9 |
10 |
11 | # False == 0 is True
12 | def move_zeros(array):
13 | result = []
14 | zeros = 0
15 |
16 | for i in array:
17 | if i == 0 and type(i) != bool: # not using `not i` to avoid `False`, `[]`, etc.
18 | zeros += 1
19 | else:
20 | result.append(i)
21 |
22 | result.extend([0] * zeros)
23 | return result
24 |
25 |
26 | print(move_zeros([False, 1, 0, 1, 2, 0, 1, 3, "a"]))
--------------------------------------------------------------------------------
/algorithms/arrays/plus_one.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a non-negative number represented as an array of digits,
3 | adding one to each numeral.
4 |
5 | The digits are stored big-endian, such that the most significant
6 | digit is at the head of the list.
7 | """
8 |
9 |
10 | def plus_one_v1(digits):
11 | """
12 | :type digits: List[int]
13 | :rtype: List[int]
14 | """
15 | digits[-1] = digits[-1] + 1
16 | res = []
17 | ten = 0
18 | i = len(digits)-1
19 | while i >= 0 or ten == 1:
20 | summ = 0
21 | if i >= 0:
22 | summ += digits[i]
23 | if ten:
24 | summ += 1
25 | res.append(summ % 10)
26 | ten = summ // 10
27 | i -= 1
28 | return res[::-1]
29 |
30 |
31 | def plus_one_v2(digits):
32 | n = len(digits)
33 | for i in range(n-1, -1, -1):
34 | if digits[i] < 9:
35 | digits[i] += 1
36 | return digits
37 | digits[i] = 0
38 | digits.insert(0, 1)
39 | return digits
40 |
41 |
42 | def plus_one_v3(num_arr):
43 |
44 | for idx in reversed(list(enumerate(num_arr))):
45 | num_arr[idx[0]] = (num_arr[idx[0]] + 1) % 10
46 | if num_arr[idx[0]]:
47 | return num_arr
48 | return [1] + num_arr
49 |
--------------------------------------------------------------------------------
/algorithms/arrays/remove_duplicates.py:
--------------------------------------------------------------------------------
1 | """
2 | This algorithm removes any duplicates from an array and returns a new array with those duplicates
3 | removed.
4 |
5 | For example:
6 |
7 | Input: [1, 1 ,1 ,2 ,2 ,3 ,4 ,4 ,"hey", "hey", "hello", True, True]
8 | Output: [1, 2, 3, 4, 'hey', 'hello']
9 | """
10 |
11 | def remove_duplicates(array):
12 | new_array = []
13 |
14 | for item in array:
15 | if item not in new_array:
16 | new_array.append(item)
17 |
18 | return new_array
--------------------------------------------------------------------------------
/algorithms/arrays/summarize_ranges.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a sorted integer array without duplicates,
3 | return the summary of its ranges.
4 |
5 | For example, given [0, 1, 2, 4, 5, 7], return [(0, 2), (4, 5), (7, 7)].
6 | """
7 |
8 |
9 | from typing import List
10 |
11 | def summarize_ranges(array: List[int]) -> List[str]:
12 | res = []
13 | if len(array) == 1:
14 | return [str(array[0])]
15 | it = iter(array)
16 | start = end = next(it)
17 | for num in it:
18 | if num - end == 1:
19 | end = num
20 | else:
21 | res.append((start, end) if start != end else (start,))
22 | start = end = num
23 | res.append((start, end) if start != end else (start,))
24 | return [f"{r[0]}-{r[1]}" if len(r) > 1 else str(r[0]) for r in res]
25 |
26 |
--------------------------------------------------------------------------------
/algorithms/arrays/top_1.py:
--------------------------------------------------------------------------------
1 | """
2 | This algorithm receives an array and returns most_frequent_value
3 | Also, sometimes it is possible to have multiple 'most_frequent_value's,
4 | so this function returns a list. This result can be used to find a
5 | representative value in an array.
6 |
7 | This algorithm gets an array, makes a dictionary of it,
8 | finds the most frequent count, and makes the result list.
9 |
10 | For example: top_1([1, 1, 2, 2, 3, 4]) will return [1, 2]
11 |
12 | (TL:DR) Get mathematical Mode
13 | Complexity: O(n)
14 | """
15 | def top_1(arr):
16 | values = {}
17 | #reserve each value which first appears on keys
18 | #reserve how many time each value appears by index number on values
19 | result = []
20 | f_val = 0
21 |
22 | for i in arr:
23 | if i in values:
24 | values[i] += 1
25 | else:
26 | values[i] = 1
27 |
28 | f_val = max(values.values())
29 |
30 | for i in values.keys():
31 | if values[i] == f_val:
32 | result.append(i)
33 | else:
34 | continue
35 |
36 | return result
37 |
--------------------------------------------------------------------------------
/algorithms/arrays/trimmean.py:
--------------------------------------------------------------------------------
1 | """
2 | When make reliable means, we need to neglect best and worst values.
3 | For example, when making average score on athletes we need this option.
4 | So, this algorithm affixes some percentage to neglect when making mean.
5 | For example, if you suggest 20%, it will neglect the best 10% of values
6 | and the worst 10% of values.
7 |
8 | This algorithm takes an array and percentage to neglect. After sorted,
9 | if index of array is larger or smaller than desired ratio, we don't
10 | compute it.
11 |
12 | Compleity: O(n)
13 | """
14 | def trimmean(arr, per):
15 | ratio = per/200
16 | # /100 for easy calculation by *, and /2 for easy adaption to best and worst parts.
17 | cal_sum = 0
18 | # sum value to be calculated to trimmean.
19 | arr.sort()
20 | neg_val = int(len(arr)*ratio)
21 | arr = arr[neg_val:len(arr)-neg_val]
22 | for i in arr:
23 | cal_sum += i
24 | return cal_sum/len(arr)
25 |
--------------------------------------------------------------------------------
/algorithms/arrays/two_sum.py:
--------------------------------------------------------------------------------
1 | """
2 | Given an array of integers, return indices of the two numbers
3 | such that they add up to a specific target.
4 |
5 | You may assume that each input would have exactly one solution,
6 | and you may not use the same element twice.
7 |
8 | Example:
9 | Given nums = [2, 7, 11, 15], target = 9,
10 |
11 | Because nums[0] + nums[1] = 2 + 7 = 9,
12 | return (0, 1)
13 | """
14 |
15 |
16 | def two_sum(array, target):
17 | dic = {}
18 | for i, num in enumerate(array):
19 | if num in dic:
20 | return dic[num], i
21 | else:
22 | dic[target - num] = i
23 | return None
24 |
--------------------------------------------------------------------------------
/algorithms/automata/__init__.py:
--------------------------------------------------------------------------------
1 | from .dfa import *
2 |
--------------------------------------------------------------------------------
/algorithms/automata/dfa.py:
--------------------------------------------------------------------------------
1 | def DFA(transitions, start, final, string):
2 |
3 | num = len(string)
4 | num_final = len(final)
5 | cur = start
6 |
7 | for i in range(num):
8 |
9 | if transitions[cur][string[i]] is None:
10 | return False
11 | else:
12 | cur = transitions[cur][string[i]]
13 |
14 | for i in range(num_final):
15 | if cur == final[i]:
16 | return True
17 | return False
18 |
--------------------------------------------------------------------------------
/algorithms/backtrack/__init__.py:
--------------------------------------------------------------------------------
1 | from .add_operators import *
2 | from .anagram import *
3 | from .array_sum_combinations import *
4 | from .combination_sum import *
5 | from .factor_combinations import *
6 | from .find_words import *
7 | from .generate_abbreviations import *
8 | from .generate_parenthesis import *
9 | from .letter_combination import *
10 | from .palindrome_partitioning import *
11 | from .pattern_match import *
12 | from .permute_unique import *
13 | from .permute import *
14 | from .subsets_unique import *
15 | from .subsets import *
16 |
--------------------------------------------------------------------------------
/algorithms/backtrack/anagram.py:
--------------------------------------------------------------------------------
1 | """
2 | Given two strings, determine if they are equal after reordering.
3 |
4 | Examples:
5 | "apple", "pleap" -> True
6 | "apple", "cherry" -> False
7 | """
8 |
9 |
10 | def anagram(s1, s2):
11 | c1 = [0] * 26
12 | c2 = [0] * 26
13 |
14 | for c in s1:
15 | pos = ord(c)-ord('a')
16 | c1[pos] = c1[pos] + 1
17 |
18 | for c in s2:
19 | pos = ord(c)-ord('a')
20 | c2[pos] = c2[pos] + 1
21 |
22 | return c1 == c2
23 |
--------------------------------------------------------------------------------
/algorithms/backtrack/combination_sum.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a set of candidate numbers (C) (without duplicates) and a target number
3 | (T), find all unique combinations in C where the candidate numbers sums to T.
4 |
5 | The same repeated number may be chosen from C unlimited number of times.
6 |
7 | Note:
8 | All numbers (including target) will be positive integers.
9 | The solution set must not contain duplicate combinations.
10 | For example, given candidate set [2, 3, 6, 7] and target 7,
11 | A solution set is:
12 | [
13 | [7],
14 | [2, 2, 3]
15 | ]
16 | """
17 |
18 |
19 | def combination_sum(candidates, target):
20 |
21 | def dfs(nums, target, index, path, res):
22 | if target < 0:
23 | return # backtracking
24 | if target == 0:
25 | res.append(path)
26 | return
27 | for i in range(index, len(nums)):
28 | dfs(nums, target-nums[i], i, path+[nums[i]], res)
29 |
30 | res = []
31 | candidates.sort()
32 | dfs(candidates, target, 0, [], res)
33 | return res
34 |
--------------------------------------------------------------------------------
/algorithms/backtrack/generate_abbreviations.py:
--------------------------------------------------------------------------------
1 | """
2 | given input word, return the list of abbreviations.
3 | ex)
4 | word => ['word', 'wor1', 'wo1d', 'wo2', 'w1rd', 'w1r1', 'w2d', 'w3', '1ord', '1or1', '1o1d', '1o2', '2rd', '2r1', '3d', '4']
5 | """
6 |
7 |
8 | def generate_abbreviations(word):
9 |
10 | def backtrack(result, word, pos, count, cur):
11 | if pos == len(word):
12 | if count > 0:
13 | cur += str(count)
14 | result.append(cur)
15 | return
16 |
17 | if count > 0: # add the current word
18 | backtrack(result, word, pos+1, 0, cur+str(count)+word[pos])
19 | else:
20 | backtrack(result, word, pos+1, 0, cur+word[pos])
21 | # skip the current word
22 | backtrack(result, word, pos+1, count+1, cur)
23 |
24 | result = []
25 | backtrack(result, word, 0, 0, "")
26 | return result
27 |
--------------------------------------------------------------------------------
/algorithms/backtrack/generate_parenthesis.py:
--------------------------------------------------------------------------------
1 | """
2 | Given n pairs of parentheses, write a function to generate
3 | all combinations of well-formed parentheses.
4 |
5 | For example, given n = 3, a solution set is:
6 |
7 | [
8 | "((()))",
9 | "(()())",
10 | "(())()",
11 | "()(())",
12 | "()()()"
13 | ]
14 | """
15 |
16 |
17 | def generate_parenthesis_v1(n):
18 | def add_pair(res, s, left, right):
19 | if left == 0 and right == 0:
20 | res.append(s)
21 | return
22 | if right > 0:
23 | add_pair(res, s + ")", left, right - 1)
24 | if left > 0:
25 | add_pair(res, s + "(", left - 1, right + 1)
26 |
27 | res = []
28 | add_pair(res, "", n, 0)
29 | return res
30 |
31 |
32 | def generate_parenthesis_v2(n):
33 | def add_pair(res, s, left, right):
34 | if left == 0 and right == 0:
35 | res.append(s)
36 | if left > 0:
37 | add_pair(res, s + "(", left - 1, right)
38 | if right > 0 and left < right:
39 | add_pair(res, s + ")", left, right - 1)
40 |
41 | res = []
42 | add_pair(res, "", n, n)
43 | return res
44 |
--------------------------------------------------------------------------------
/algorithms/backtrack/letter_combination.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a digit string, return all possible letter
3 | combinations that the number could represent.
4 |
5 | A mapping of digit to letters (just like on the telephone buttons) is given below:
6 | 2: "abc"
7 | 3: "def"
8 | 4: "ghi"
9 | 5: "jkl"
10 | 6: "mno"
11 | 7: "pqrs"
12 | 8: "tuv"
13 | 9: "wxyz"
14 |
15 | Input:Digit string "23"
16 | Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
17 | """
18 |
19 |
20 | def letter_combinations(digits):
21 | if digits == "":
22 | return []
23 | kmaps = {
24 | "2": "abc",
25 | "3": "def",
26 | "4": "ghi",
27 | "5": "jkl",
28 | "6": "mno",
29 | "7": "pqrs",
30 | "8": "tuv",
31 | "9": "wxyz"
32 | }
33 | ans = [""]
34 | for num in digits:
35 | tmp = []
36 | for an in ans:
37 | for char in kmaps[num]:
38 | tmp.append(an + char)
39 | ans = tmp
40 | return ans
41 |
--------------------------------------------------------------------------------
/algorithms/backtrack/permute_unique.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a collection of numbers that might contain duplicates,
3 | return all possible unique permutations.
4 |
5 | For example,
6 | [1,1,2] have the following unique permutations:
7 | [
8 | [1,1,2],
9 | [1,2,1],
10 | [2,1,1]
11 | ]
12 | """
13 |
14 |
15 | def permute_unique(nums):
16 | perms = [[]]
17 | for n in nums:
18 | new_perms = []
19 | for l in perms:
20 | for i in range(len(l)+1):
21 | new_perms.append(l[:i]+[n]+l[i:])
22 | if i < len(l) and l[i] == n:
23 | break # handles duplication
24 | perms = new_perms
25 | return perms
26 |
--------------------------------------------------------------------------------
/algorithms/backtrack/subsets.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a set of distinct integers, nums, return all possible subsets.
3 |
4 | Note: The solution set must not contain duplicate subsets.
5 |
6 | For example,
7 | If nums = [1,2,3], a solution is:
8 |
9 | [
10 | [3],
11 | [1],
12 | [2],
13 | [1,2,3],
14 | [1,3],
15 | [2,3],
16 | [1,2],
17 | []
18 | ]
19 | """
20 |
21 |
22 | def subsets(nums):
23 | """
24 | O(2**n)
25 | """
26 | def backtrack(res, nums, stack, pos):
27 | if pos == len(nums):
28 | res.append(list(stack))
29 | else:
30 | # take nums[pos]
31 | stack.append(nums[pos])
32 | backtrack(res, nums, stack, pos+1)
33 | stack.pop()
34 | # dont take nums[pos]
35 | backtrack(res, nums, stack, pos+1)
36 |
37 | res = []
38 | backtrack(res, nums, [], 0)
39 | return res
40 |
41 |
42 | """
43 | simplified backtrack
44 |
45 | def backtrack(res, nums, cur, pos):
46 | if pos >= len(nums):
47 | res.append(cur)
48 | else:
49 | backtrack(res, nums, cur+[nums[pos]], pos+1)
50 | backtrack(res, nums, cur, pos+1)
51 | """
52 |
53 |
54 | # Iteratively
55 | def subsets_v2(nums):
56 | res = [[]]
57 | for num in sorted(nums):
58 | res += [item+[num] for item in res]
59 | return res
60 |
--------------------------------------------------------------------------------
/algorithms/backtrack/subsets_unique.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a collection of integers that might contain duplicates, nums,
3 | return all possible subsets.
4 |
5 | Note: The solution set must not contain duplicate subsets.
6 |
7 | For example,
8 | If nums = [1,2,2], a solution is:
9 |
10 | [
11 | [2],
12 | [1],
13 | [1,2,2],
14 | [2,2],
15 | [1,2],
16 | []
17 | ]
18 | """
19 |
20 |
21 | def subsets_unique(nums):
22 |
23 | def backtrack(res, nums, stack, pos):
24 | if pos == len(nums):
25 | res.add(tuple(stack))
26 | else:
27 | # take
28 | stack.append(nums[pos])
29 | backtrack(res, nums, stack, pos+1)
30 | stack.pop()
31 |
32 | # don't take
33 | backtrack(res, nums, stack, pos+1)
34 |
35 | res = set()
36 | backtrack(res, nums, [], 0)
37 | return list(res)
38 |
--------------------------------------------------------------------------------
/algorithms/bfs/__init__.py:
--------------------------------------------------------------------------------
1 | from .count_islands import *
2 | from .maze_search import *
3 | from .shortest_distance_from_all_buildings import *
4 | from .word_ladder import *
5 |
--------------------------------------------------------------------------------
/algorithms/bit/__init__.py:
--------------------------------------------------------------------------------
1 | from .add_bitwise_operator import *
2 | from .count_ones import *
3 | from .find_missing_number import *
4 | from .power_of_two import *
5 | from .reverse_bits import *
6 | from .single_number import *
7 | from .single_number2 import *
8 | from .single_number3 import *
9 | from .subsets import *
10 | from .bit_operation import *
11 | from .swap_pair import *
12 | from .find_difference import *
13 | from .has_alternative_bit import *
14 | from .insert_bit import *
15 | from .remove_bit import *
16 | from .count_flips_to_convert import *
17 | from .flip_bit_longest_sequence import *
18 | from .binary_gap import *
19 | from .bytes_int_conversion import *
--------------------------------------------------------------------------------
/algorithms/bit/add_bitwise_operator.py:
--------------------------------------------------------------------------------
1 | """
2 | The following code adds two positive integers without using the '+' operator.
3 | The code uses bitwise operations to add two numbers.
4 |
5 | Input: 2 3
6 | Output: 5
7 | """
8 | def add_bitwise_operator(x, y):
9 |
10 | while y:
11 | carry = x & y
12 | x = x ^ y
13 | y = carry << 1
14 | return x
15 |
--------------------------------------------------------------------------------
/algorithms/bit/bit_operation.py:
--------------------------------------------------------------------------------
1 | """
2 | Fundamental bit operation:
3 | get_bit(num, i): get an exact bit at specific index
4 | set_bit(num, i): set a bit at specific index
5 | clear_bit(num, i): clear a bit at specific index
6 | update_bit(num, i, bit): update a bit at specific index
7 | """
8 |
9 | """
10 | This function shifts 1 over by i bits, creating a value being like 0001000. By
11 | performing an AND with num, we clear all bits other than the bit at bit i.
12 | Finally we compare that to 0
13 | """
14 | def get_bit(num, i):
15 | return (num & (1 << i)) != 0
16 |
17 | """
18 | This function shifts 1 over by i bits, creating a value being like 0001000. By
19 | performing an OR with num, only value at bit i will change.
20 | """
21 | def set_bit(num, i):
22 | return num | (1 << i)
23 |
24 | """
25 | This method operates in almost the reverse of set_bit
26 | """
27 | def clear_bit(num, i):
28 | mask = ~(1 << i)
29 | return num & mask
30 |
31 | """
32 | To set the ith bit to value, we first clear the bit at position i by using a
33 | mask. Then, we shift the intended value. Finally we OR these two numbers
34 | """
35 | def update_bit(num, i, bit):
36 | mask = ~(1 << i)
37 | return (num & mask) | (bit << i)
38 |
--------------------------------------------------------------------------------
/algorithms/bit/bytes_int_conversion.py:
--------------------------------------------------------------------------------
1 | from collections import deque
2 |
3 |
4 | def int_to_bytes_big_endian(num):
5 | bytestr = deque()
6 | while num > 0:
7 | # list.insert(0, ...) is inefficient
8 | bytestr.appendleft(num & 0xff)
9 | num >>= 8
10 | return bytes(bytestr)
11 |
12 |
13 | def int_to_bytes_little_endian(num):
14 | bytestr = []
15 | while num > 0:
16 | bytestr.append(num & 0xff)
17 | num >>= 8
18 | return bytes(bytestr)
19 |
20 |
21 | def bytes_big_endian_to_int(bytestr):
22 | num = 0
23 | for b in bytestr:
24 | num <<= 8
25 | num += b
26 | return num
27 |
28 |
29 | def bytes_little_endian_to_int(bytestr):
30 | num = 0
31 | e = 0
32 | for b in bytestr:
33 | num += b << e
34 | e += 8
35 | return num
36 |
--------------------------------------------------------------------------------
/algorithms/bit/count_flips_to_convert.py:
--------------------------------------------------------------------------------
1 | """
2 | Write a function to determine the minimal number of bits you would need to
3 | flip to convert integer A to integer B.
4 | For example:
5 | Input: 29 (or: 11101), 15 (or: 01111)
6 | Output: 2
7 | """
8 |
9 |
10 | def count_flips_to_convert(a, b):
11 |
12 | diff = a ^ b
13 |
14 | # count number of ones in diff
15 | count = 0
16 | while diff:
17 | diff &= (diff - 1)
18 | count += 1
19 | return count
20 |
--------------------------------------------------------------------------------
/algorithms/bit/count_ones.py:
--------------------------------------------------------------------------------
1 | """
2 | Write a function that takes an unsigned integer and
3 | returns the number of '1' bits it has
4 | (also known as the Hamming weight).
5 |
6 | For example, the 32-bit integer '11' has binary
7 | representation 00000000000000000000000000001011,
8 | so the function should return 3.
9 |
10 | T(n)- O(k) : k is the number of 1s present in binary representation.
11 | NOTE: this complexity is better than O(log n).
12 | e.g. for n = 00010100000000000000000000000000
13 | only 2 iterations are required.
14 |
15 | Number of loops is
16 | equal to the number of 1s in the binary representation."""
17 | def count_ones_recur(n):
18 | """Using Brian Kernighan's Algorithm. (Recursive Approach)"""
19 |
20 | if not n:
21 | return 0
22 | return 1 + count_ones_recur(n & (n-1))
23 |
24 |
25 | def count_ones_iter(n):
26 | """Using Brian Kernighan's Algorithm. (Iterative Approach)"""
27 |
28 | count = 0
29 | while n:
30 | n &= (n-1)
31 | count += 1
32 | return count
33 |
--------------------------------------------------------------------------------
/algorithms/bit/find_difference.py:
--------------------------------------------------------------------------------
1 | """
2 | Given two strings s and t which consist of only lowercase letters.
3 | String t is generated by random shuffling string s and then add one more letter
4 | at a random position. Find the letter that was added in t.
5 |
6 | For example:
7 | Input:
8 | s = "abcd"
9 | t = "abecd"
10 | Output: 'e'
11 |
12 | Explanation:
13 | 'e' is the letter that was added.
14 | """
15 |
16 | """
17 | We use the characteristic equation of XOR.
18 | A xor B xor C = A xor C xor B
19 | If A == C, then A xor C = 0
20 | and then, B xor 0 = B
21 | """
22 | def find_difference(s, t):
23 | ret = 0
24 | for ch in s + t:
25 | # ord(ch) return an integer representing the Unicode code point of that character
26 | ret = ret ^ ord(ch)
27 | # chr(i) Return the string representing a character whose Unicode code point is the integer i
28 | return chr(ret)
29 |
--------------------------------------------------------------------------------
/algorithms/bit/find_missing_number.py:
--------------------------------------------------------------------------------
1 | """
2 | Returns the missing number from a sequence of unique integers
3 | in range [0..n] in O(n) time and space. The difference between
4 | consecutive integers cannot be more than 1. If the sequence is
5 | already complete, the next integer in the sequence will be returned.
6 |
7 | For example:
8 | Input: nums = [4, 1, 3, 0, 6, 5, 2]
9 | Output: 7
10 | """
11 | def find_missing_number(nums):
12 |
13 | missing = 0
14 | for i, num in enumerate(nums):
15 | missing ^= num
16 | missing ^= i + 1
17 |
18 | return missing
19 |
20 |
21 | def find_missing_number2(nums):
22 |
23 | num_sum = sum(nums)
24 | n = len(nums)
25 | total_sum = n*(n+1) // 2
26 | missing = total_sum - num_sum
27 | return missing
28 |
--------------------------------------------------------------------------------
/algorithms/bit/flip_bit_longest_sequence.py:
--------------------------------------------------------------------------------
1 | """
2 | You have an integer and you can flip exactly one bit from a 0 to 1.
3 | Write code to find the length of the longest sequence of 1s you could create.
4 | For example:
5 | Input: 1775 ( or: 11011101111)
6 | Output: 8
7 | """
8 |
9 |
10 | def flip_bit_longest_seq(num):
11 |
12 | curr_len = 0
13 | prev_len = 0
14 | max_len = 0
15 |
16 | while num:
17 | if num & 1 == 1: # last digit is 1
18 | curr_len += 1
19 |
20 | elif num & 1 == 0: # last digit is 0
21 | if num & 2 == 0: # second last digit is 0
22 | prev_len = 0
23 | else:
24 | prev_len = curr_len
25 | curr_len = 0
26 |
27 | max_len = max(max_len, prev_len + curr_len)
28 | num = num >> 1 # right shift num
29 |
30 | return max_len + 1
31 |
--------------------------------------------------------------------------------
/algorithms/bit/has_alternative_bit.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a positive integer, check whether it has alternating bits: namely,
3 | if two adjacent bits will always have different values.
4 |
5 | For example:
6 | Input: 5
7 | Output: True because the binary representation of 5 is: 101.
8 |
9 | Input: 7
10 | Output: False because the binary representation of 7 is: 111.
11 |
12 | Input: 11
13 | Output: False because the binary representation of 11 is: 1011.
14 |
15 | Input: 10
16 | Output: True because The binary representation of 10 is: 1010.
17 | """
18 |
19 | # Time Complexity - O(number of bits in n)
20 | def has_alternative_bit(n):
21 | first_bit = 0
22 | second_bit = 0
23 | while n:
24 | first_bit = n & 1
25 | if n >> 1:
26 | second_bit = (n >> 1) & 1
27 | if not first_bit ^ second_bit:
28 | return False
29 | else:
30 | return True
31 | n = n >> 1
32 | return True
33 |
34 | # Time Complexity - O(1)
35 | def has_alternative_bit_fast(n):
36 | mask1 = int('aaaaaaaa', 16) # for bits ending with zero (...1010)
37 | mask2 = int('55555555', 16) # for bits ending with one (...0101)
38 | return mask1 == (n + (n ^ mask1)) or mask2 == (n + (n ^ mask2))
39 |
--------------------------------------------------------------------------------
/algorithms/bit/power_of_two.py:
--------------------------------------------------------------------------------
1 | """
2 | given an integer, write a function to determine if it is a power of two
3 | """
4 | def is_power_of_two(n):
5 | """
6 | :type n: int
7 | :rtype: bool
8 | """
9 | return n > 0 and not n & (n-1)
10 |
--------------------------------------------------------------------------------
/algorithms/bit/remove_bit.py:
--------------------------------------------------------------------------------
1 | """
2 | Remove_bit(num, i): remove a bit at specific position.
3 | For example:
4 |
5 | Input: num = 10101 (21)
6 | remove_bit(num, 2): output = 1001 (9)
7 | remove_bit(num, 4): output = 101 (5)
8 | remove_bit(num, 0): output = 1010 (10)
9 | """
10 |
11 | def remove_bit(num, i):
12 | mask = num >> (i + 1)
13 | mask = mask << i
14 | right = ((1 << i) - 1) & num
15 | return mask | right
16 |
--------------------------------------------------------------------------------
/algorithms/bit/reverse_bits.py:
--------------------------------------------------------------------------------
1 | """
2 | Reverse bits of a given 32 bits unsigned integer.
3 |
4 | For example, given input 43261596
5 | (represented in binary as 00000010100101000001111010011100),
6 | return 964176192
7 | (represented in binary as 00111001011110000010100101000000).
8 | """
9 | def reverse_bits(n):
10 | m = 0
11 | i = 0
12 | while i < 32:
13 | m = (m << 1) + (n & 1)
14 | n >>= 1
15 | i += 1
16 | return m
17 |
--------------------------------------------------------------------------------
/algorithms/bit/single_number.py:
--------------------------------------------------------------------------------
1 | """
2 | Given an array of integers, every element appears
3 | twice except for one. Find that single one.
4 |
5 | NOTE: This also works for finding a number occurring odd
6 | number of times, where all the other numbers appear
7 | even number of times.
8 |
9 | Note:
10 | Your algorithm should have a linear runtime complexity.
11 | Could you implement it without using extra memory?
12 | """
13 | def single_number(nums):
14 | """
15 | Returns single number, if found.
16 | Else if all numbers appear twice, returns 0.
17 | :type nums: List[int]
18 | :rtype: int
19 | """
20 | i = 0
21 | for num in nums:
22 | i ^= num
23 | return i
24 |
--------------------------------------------------------------------------------
/algorithms/bit/single_number2.py:
--------------------------------------------------------------------------------
1 | """
2 | Given an array of integers, every element appears
3 | three times except for one, which appears exactly once.
4 | Find that single one.
5 |
6 | Note:
7 | Your algorithm should have a linear runtime complexity.
8 | Could you implement it without using extra memory?
9 |
10 |
11 | Solution:
12 | 32 bits for each integer.
13 | Consider 1 bit in it, the sum of each integer's corresponding bit
14 | (except for the single number)
15 | should be 0 if mod by 3. Hence, we sum the bits of all
16 | integers and mod by 3,
17 | the remaining should be the exact bit of the single number.
18 | In this way, you get the 32 bits of the single number.
19 | """
20 |
21 | # Another awesome answer
22 | def single_number2(nums):
23 | ones, twos = 0, 0
24 | for i in range(len(nums)):
25 | ones = (ones ^ nums[i]) & ~twos
26 | twos = (twos ^ nums[i]) & ~ones
27 | return ones
28 |
--------------------------------------------------------------------------------
/algorithms/bit/swap_pair.py:
--------------------------------------------------------------------------------
1 | """
2 | Swap_pair: A function swap odd and even bits in an integer with as few instructions
3 | as possible (Ex bit and bit 1 are swapped, bit 2 and bit 3 are swapped)
4 |
5 | For example:
6 | 22: 010110 --> 41: 101001
7 | 10: 1010 --> 5 : 0101
8 | """
9 |
10 | """
11 | We can approach this as operating on the odds bit first, and then the even bits.
12 | We can mask all odd bits with 10101010 in binary ('AA') then shift them right by 1
13 | Similarly, we mask all even bit with 01010101 in binary ('55') then shift them left
14 | by 1. Finally, we merge these two values by OR operation.
15 | """
16 | def swap_pair(num):
17 | # odd bit arithmetic right shift 1 bit
18 | odd = (num & int('AAAAAAAA', 16)) >> 1
19 | # even bit left shift 1 bit
20 | even = (num & int('55555555', 16)) << 1
21 | return odd | even
22 |
--------------------------------------------------------------------------------
/algorithms/compression/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/cad4754bc71742c2d6fcbd3b92ae74834d359844/algorithms/compression/__init__.py
--------------------------------------------------------------------------------
/algorithms/dfs/__init__.py:
--------------------------------------------------------------------------------
1 | from .all_factors import *
2 | from .count_islands import *
3 | from .pacific_atlantic import *
4 | from .sudoku_solver import *
5 | from .walls_and_gates import *
6 | from .maze_search import *
7 |
--------------------------------------------------------------------------------
/algorithms/dfs/count_islands.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a 2d grid map of '1's (land) and '0's (water),
3 | count the number of islands.
4 | An island is surrounded by water and is formed by
5 | connecting adjacent lands horizontally or vertically.
6 | You may assume all four edges of the grid are all surrounded by water.
7 |
8 | Example 1:
9 |
10 | 11110
11 | 11010
12 | 11000
13 | 00000
14 | Answer: 1
15 |
16 | Example 2:
17 |
18 | 11000
19 | 11000
20 | 00100
21 | 00011
22 | Answer: 3
23 | """
24 |
25 | def num_islands(grid):
26 | count = 0
27 | for i in range(len(grid)):
28 | for j, col in enumerate(grid[i]):
29 | if col == 1:
30 | dfs(grid, i, j)
31 | count += 1
32 | return count
33 |
34 |
35 | def dfs(grid, i, j):
36 | if (i < 0 or i >= len(grid)) or (j < 0 or j >= len(grid[0])):
37 | return
38 | if grid[i][j] != 1:
39 | return
40 | grid[i][j] = 0
41 | dfs(grid, i+1, j)
42 | dfs(grid, i-1, j)
43 | dfs(grid, i, j+1)
44 | dfs(grid, i, j-1)
45 |
--------------------------------------------------------------------------------
/algorithms/distribution/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/cad4754bc71742c2d6fcbd3b92ae74834d359844/algorithms/distribution/__init__.py
--------------------------------------------------------------------------------
/algorithms/distribution/histogram.py:
--------------------------------------------------------------------------------
1 | """
2 | Histogram function.
3 |
4 | Histogram is an accurate representation of the distribution of numerical data.
5 | It is an estimate of the probability distribution of a continuous variable.
6 | https://en.wikipedia.org/wiki/Histogram
7 |
8 | Example:
9 | list_1 = [3, 3, 2, 1]
10 | :return {1: 1, 2: 1, 3: 2}
11 |
12 | list_2 = [2, 3, 5, 5, 5, 6, 4, 3, 7]
13 | :return {2: 1, 3: 2, 4: 1, 5: 3, 6: 1, 7: 1}
14 | """
15 |
16 |
17 | def get_histogram(input_list: list) -> dict:
18 | """
19 | Get histogram representation
20 | :param input_list: list with different and unordered values
21 | :return histogram: dict with histogram of input_list
22 | """
23 | # Create dict to store histogram
24 | histogram = {}
25 | # For each list value, add one to the respective histogram dict position
26 | for i in input_list:
27 | histogram[i] = histogram.get(i, 0) + 1
28 | return histogram
29 |
--------------------------------------------------------------------------------
/algorithms/dp/__init__.py:
--------------------------------------------------------------------------------
1 | from .buy_sell_stock import *
2 | from .climbing_stairs import *
3 | from .coin_change import *
4 | from .combination_sum import *
5 | from .edit_distance import *
6 | from .egg_drop import *
7 | from .fib import *
8 | from .hosoya_triangle import *
9 | from .house_robber import *
10 | from .job_scheduling import *
11 | from .knapsack import *
12 | from .longest_increasing import *
13 | from .matrix_chain_order import *
14 | from .max_product_subarray import *
15 | from .max_subarray import *
16 | from .min_cost_path import *
17 | from .num_decodings import *
18 | from .regex_matching import *
19 | from .rod_cut import *
20 | from .word_break import *
21 | from .int_divide import *
22 | from .k_factor import *
23 | from .planting_trees import *
24 |
--------------------------------------------------------------------------------
/algorithms/dp/climbing_stairs.py:
--------------------------------------------------------------------------------
1 | """
2 | You are climbing a stair case.
3 | It takes `steps` number of steps to reach to the top.
4 |
5 | Each time you can either climb 1 or 2 steps.
6 | In how many distinct ways can you climb to the top?
7 |
8 | Note: Given argument `steps` will be a positive integer.
9 | """
10 |
11 |
12 | # O(n) space
13 |
14 | def climb_stairs(steps):
15 | """
16 | :type steps: int
17 | :rtype: int
18 | """
19 | arr = [1, 1]
20 | for _ in range(1, steps):
21 | arr.append(arr[-1] + arr[-2])
22 | return arr[-1]
23 |
24 |
25 | # the above function can be optimized as:
26 | # O(1) space
27 |
28 | def climb_stairs_optimized(steps):
29 | """
30 | :type steps: int
31 | :rtype: int
32 | """
33 | a_steps = b_steps = 1
34 | for _ in range(steps):
35 | a_steps, b_steps = b_steps, a_steps + b_steps
36 | return a_steps
37 |
--------------------------------------------------------------------------------
/algorithms/dp/coin_change.py:
--------------------------------------------------------------------------------
1 | """
2 | Problem
3 | Given a value `value`, if we want to make change for `value` cents, and we have infinite
4 | supply of each of coins = {S1, S2, .. , Sm} valued `coins`, how many ways can we make the change?
5 | The order of `coins` doesn't matter.
6 | For example, for `value` = 4 and `coins` = [1, 2, 3], there are four solutions:
7 | [1, 1, 1, 1], [1, 1, 2], [2, 2], [1, 3].
8 | So output should be 4.
9 |
10 | For `value` = 10 and `coins` = [2, 5, 3, 6], there are five solutions:
11 |
12 | [2, 2, 2, 2, 2], [2, 2, 3, 3], [2, 2, 6], [2, 3, 5] and [5, 5].
13 | So the output should be 5.
14 |
15 | Time complexity: O(n * m) where n is the `value` and m is the number of `coins`
16 | Space complexity: O(n)
17 | """
18 |
19 | def count(coins, value):
20 | """ Find number of combination of `coins` that adds upp to `value`
21 |
22 | Keyword arguments:
23 | coins -- int[]
24 | value -- int
25 | """
26 | # initialize dp array and set base case as 1
27 | dp_array = [1] + [0] * value
28 |
29 | # fill dp in a bottom up manner
30 | for coin in coins:
31 | for i in range(coin, value+1):
32 | dp_array[i] += dp_array[i-coin]
33 |
34 | return dp_array[value]
35 |
--------------------------------------------------------------------------------
/algorithms/dp/house_robber.py:
--------------------------------------------------------------------------------
1 | """
2 | You are a professional robber planning to rob houses along a street.
3 | Each house has a certain amount of money stashed,
4 | the only constraint stopping you from robbing each of them
5 | is that adjacent houses have security system connected and
6 | it will automatically contact the police if two adjacent houses
7 | were broken into on the same night.
8 |
9 | Given a list of non-negative integers representing the amount of money
10 | of each house, determine the maximum amount of money you
11 | can rob tonight without alerting the police.
12 | """
13 |
14 |
15 | def house_robber(houses):
16 | last, now = 0, 0
17 | for house in houses:
18 | last, now = now, max(last + house, now)
19 | return now
20 |
--------------------------------------------------------------------------------
/algorithms/dp/int_divide.py:
--------------------------------------------------------------------------------
1 | """
2 | Given positive integer decompose, find an algorithm to find the number of
3 | non-negative number division, or decomposition.
4 |
5 | The complexity is O(n^2).
6 |
7 | Example 1:
8 | Input: 4
9 | Output: 5
10 | Explaination:
11 | 4=4
12 | 4=3+1
13 | 4=2+2
14 | 4=2+1+1
15 | 4=1+1+1+1
16 |
17 | Example :
18 | Input: 7
19 | Output: 15
20 | Explaination:
21 | 7=7
22 | 7=6+1
23 | 7=5+2
24 | 7=5+1+1
25 | 7=4+3
26 | 7=4+2+1
27 | 7=4+1+1+1
28 | 7=3+3+1
29 | 7=3+2+2
30 | 7=3+2+1+1
31 | 7=3+1+1+1+1
32 | 7=2+2+2+1
33 | 7=2+2+1+1+1
34 | 7=2+1+1+1+1+1
35 | 7=1+1+1+1+1+1+1
36 |
37 | """
38 |
39 |
40 | def int_divide(decompose):
41 | """Find number of decompositions from `decompose`
42 |
43 | decompose -- integer
44 | """
45 | arr = [[0 for i in range(decompose + 1)] for j in range(decompose + 1)]
46 | arr[1][1] = 1
47 | for i in range(1, decompose + 1):
48 | for j in range(1, decompose + 1):
49 | if i < j:
50 | arr[i][j] = arr[i][i]
51 | elif i == j:
52 | arr[i][j] = 1 + arr[i][j - 1]
53 | else:
54 | arr[i][j] = arr[i][j - 1] + arr[i - j][j]
55 | return arr[decompose][decompose]
56 |
--------------------------------------------------------------------------------
/algorithms/dp/knapsack.py:
--------------------------------------------------------------------------------
1 | """
2 | Given the capacity of the knapsack and items specified by weights and values,
3 | return the maximum summarized value of the items that can be fit in the
4 | knapsack.
5 |
6 | Example:
7 | capacity = 5, items(value, weight) = [(60, 5), (50, 3), (70, 4), (30, 2)]
8 | result = 80 (items valued 50 and 30 can both be fit in the knapsack)
9 |
10 | The time complexity is O(n * m) and the space complexity is O(m), where n is
11 | the total number of items and m is the knapsack's capacity.
12 | """
13 |
14 |
15 | class Item:
16 |
17 | def __init__(self, value, weight):
18 | self.value = value
19 | self.weight = weight
20 |
21 |
22 | def get_maximum_value(items, capacity):
23 | dp = [0] * (capacity + 1)
24 | for item in items:
25 | for cur_weight in reversed(range(item.weight, capacity+1)):
26 | dp[cur_weight] = max(dp[cur_weight], item.value + dp[cur_weight - item.weight])
27 | return dp[capacity]
28 |
29 |
--------------------------------------------------------------------------------
/algorithms/dp/max_subarray.py:
--------------------------------------------------------------------------------
1 |
2 | def max_subarray(array):
3 | max_so_far = max_now = array[0]
4 | for i in range(1, len(array)):
5 | max_now = max(array[i], max_now + array[i])
6 | max_so_far = max(max_so_far, max_now)
7 | return max_so_far
8 |
9 | a = [1, 2, -3, 4, 5, -7, 23]
10 | print(a)
11 | print(max_subarray(a))
12 |
--------------------------------------------------------------------------------
/algorithms/dp/rod_cut.py:
--------------------------------------------------------------------------------
1 | """A Dynamic Programming solution for Rod cutting problem
2 | """
3 |
4 | INT_MIN = -32767
5 |
6 | def cut_rod(price):
7 | """
8 | Returns the best obtainable price for a rod of length n and
9 | price[] as prices of different pieces
10 | """
11 | n = len(price)
12 | val = [0]*(n+1)
13 |
14 | # Build the table val[] in bottom up manner and return
15 | # the last entry from the table
16 | for i in range(1, n+1):
17 | max_val = INT_MIN
18 | for j in range(i):
19 | max_val = max(max_val, price[j] + val[i-j-1])
20 | val[i] = max_val
21 |
22 | return val[n]
23 |
24 | # Driver program to test above functions
25 | arr = [1, 5, 8, 9, 10, 17, 17, 20]
26 | print("Maximum Obtainable Value is " + str(cut_rod(arr)))
27 |
28 | # This code is contributed by Bhavya Jain
29 |
--------------------------------------------------------------------------------
/algorithms/dp/word_break.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a non-empty string s and a dictionary wordDict
3 | containing a list of non-empty words,
4 | determine if word can be segmented into a space-separated
5 | sequence of one or more dictionary words.
6 | You may assume the dictionary does not contain duplicate words.
7 |
8 | For example, given
9 | word = "leetcode",
10 | dict = ["leet", "code"].
11 |
12 | Return true because "leetcode" can be segmented as "leet code".
13 |
14 | word = abc word_dict = ["a","bc"]
15 | True False False False
16 |
17 | """
18 |
19 |
20 | # TC: O(N^2) SC: O(N)
21 | def word_break(word, word_dict):
22 | """
23 | :type word: str
24 | :type word_dict: Set[str]
25 | :rtype: bool
26 | """
27 | dp_array = [False] * (len(word)+1)
28 | dp_array[0] = True
29 | for i in range(1, len(word)+1):
30 | for j in range(0, i):
31 | if dp_array[j] and word[j:i] in word_dict:
32 | dp_array[i] = True
33 | break
34 | return dp_array[-1]
35 |
36 |
37 | if __name__ == "__main__":
38 | STR = "keonkim"
39 | dic = ["keon", "kim"]
40 |
41 | print(word_break(str, dic))
42 |
--------------------------------------------------------------------------------
/algorithms/graph/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Collection of algorithms on graphs.
3 | """
4 |
5 | from .tarjan import *
6 | from .check_bipartite import *
7 | from .maximum_flow import *
8 | from .maximum_flow_bfs import *
9 | from .maximum_flow_dfs import *
10 | from .all_pairs_shortest_path import *
11 | from .bellman_ford import *
12 | from .prims_minimum_spanning import *
13 |
--------------------------------------------------------------------------------
/algorithms/graph/all_pairs_shortest_path.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a n*n adjacency array.
3 | it will give you all pairs shortest path length.
4 | use deepcopy to preserve the original information.
5 |
6 | Time complexity : O(E^3)
7 |
8 | example
9 |
10 | a = [[0 , 0.1 , 0.101, 0.142, 0.277],
11 | [0.465, 0 , 0.191, 0.192, 0.587],
12 | [0.245, 0.554, 0 , 0.333, 0.931],
13 | [1.032, 0.668, 0.656, 0 , 0.151],
14 | [0.867, 0.119, 0.352, 0.398, 0]]
15 |
16 | result
17 |
18 | [[0 , 0.1 , 0.101, 0.142, 0.277],
19 | [0.436, 0 , 0.191, 0.192, 0.343],
20 | [0.245, 0.345, 0 , 0.333, 0.484],
21 | [0.706, 0.27 , 0.461, 0 , 0.151],
22 | [0.555, 0.119, 0.31 , 0.311, 0]]
23 |
24 | """
25 | import copy
26 |
27 | def all_pairs_shortest_path(adjacency_matrix):
28 | """
29 | Given a matrix of the edge weights between respective nodes, returns a
30 | matrix containing the shortest distance distance between the two nodes.
31 | """
32 |
33 | new_array = copy.deepcopy(adjacency_matrix)
34 |
35 | size = len(new_array)
36 | for k in range(size):
37 | for i in range(size):
38 | for j in range(size):
39 | if new_array[i][j] > new_array[i][k] + new_array[k][j]:
40 | new_array[i][j] = new_array[i][k] + new_array[k][j]
41 |
42 | return new_array
43 |
--------------------------------------------------------------------------------
/algorithms/graph/check_bipartite.py:
--------------------------------------------------------------------------------
1 | """
2 | Bipartite graph is a graph whose vertices can be divided into two disjoint and independent sets.
3 | (https://en.wikipedia.org/wiki/Bipartite_graph)
4 | """
5 |
6 | def check_bipartite(adj_list):
7 | """
8 | Determine if the given graph is bipartite.
9 |
10 | Time complexity is O(|E|)
11 | Space complexity is O(|V|)
12 | """
13 |
14 | vertices = len(adj_list)
15 |
16 | # Divide vertexes in the graph into set_type 0 and 1
17 | # Initialize all set_types as -1
18 | set_type = [-1 for v in range(vertices)]
19 | set_type[0] = 0
20 |
21 | queue = [0]
22 |
23 | while queue:
24 | current = queue.pop(0)
25 |
26 | # If there is a self-loop, it cannot be bipartite
27 | if adj_list[current][current]:
28 | return False
29 |
30 | for adjacent in range(vertices):
31 | if adj_list[current][adjacent]:
32 | if set_type[adjacent] == set_type[current]:
33 | return False
34 |
35 | if set_type[adjacent] == -1:
36 | # set type of u opposite of v
37 | set_type[adjacent] = 1 - set_type[current]
38 | queue.append(adjacent)
39 |
40 | return True
41 |
--------------------------------------------------------------------------------
/algorithms/graph/markov_chain.py:
--------------------------------------------------------------------------------
1 | """
2 | Implements a markov chain. Chains are described using a dictionary:
3 |
4 | my_chain = {
5 | 'A': {'A': 0.6,
6 | 'E': 0.4},
7 | 'E': {'A': 0.7,
8 | 'E': 0.3}
9 | }
10 | """
11 |
12 | import random
13 |
14 | def __choose_state(state_map):
15 | """
16 | Choose the next state randomly
17 | """
18 | choice = random.random()
19 | probability_reached = 0
20 | for state, probability in state_map.items():
21 | probability_reached += probability
22 | if probability_reached > choice:
23 | return state
24 | return None
25 |
26 | def next_state(chain, current_state):
27 | """
28 | Given a markov-chain, randomly chooses the next state given the current state.
29 | """
30 | next_state_map = chain.get(current_state)
31 | return __choose_state(next_state_map)
32 |
33 | def iterating_markov_chain(chain, state):
34 | """
35 | Yield a sequence of states given a markov chain and the initial state
36 | """
37 | while True:
38 | state = next_state(chain, state)
39 | yield state
40 |
--------------------------------------------------------------------------------
/algorithms/graph/prims_minimum_spanning.py:
--------------------------------------------------------------------------------
1 | '''
2 | This Prim's Algorithm Code is for finding weight of minimum spanning tree
3 | of a connected graph.
4 | For argument graph, it should be a dictionary type such as:
5 |
6 | graph = {
7 | 'a': [ [3, 'b'], [8,'c'] ],
8 | 'b': [ [3, 'a'], [5, 'd'] ],
9 | 'c': [ [8, 'a'], [2, 'd'], [4, 'e'] ],
10 | 'd': [ [5, 'b'], [2, 'c'], [6, 'e'] ],
11 | 'e': [ [4, 'c'], [6, 'd'] ]
12 | }
13 |
14 | where 'a','b','c','d','e' are nodes (these can be 1,2,3,4,5 as well)
15 | '''
16 |
17 |
18 | import heapq # for priority queue
19 |
20 | def prims_minimum_spanning(graph_used):
21 | """
22 | Prim's algorithm to find weight of minimum spanning tree
23 | """
24 | vis=[]
25 | heap=[[0,1]]
26 | prim = set()
27 | mincost=0
28 |
29 | while len(heap) > 0:
30 | cost, node = heapq.heappop(heap)
31 | if node in vis:
32 | continue
33 |
34 | mincost += cost
35 | prim.add(node)
36 | vis.append(node)
37 |
38 | for distance, adjacent in graph_used[node]:
39 | if adjacent not in vis:
40 | heapq.heappush(heap, [distance, adjacent])
41 |
42 | return mincost
43 |
--------------------------------------------------------------------------------
/algorithms/greedy/__init__.py:
--------------------------------------------------------------------------------
1 | from .max_contiguous_subsequence_sum import *
2 |
--------------------------------------------------------------------------------
/algorithms/heap/__init__.py:
--------------------------------------------------------------------------------
1 | from .binary_heap import *
2 | from .skyline import *
3 | from .sliding_window_max import *
4 | from .merge_sorted_k_lists import *
5 | from .k_closest_points import *
6 |
--------------------------------------------------------------------------------
/algorithms/heap/sliding_window_max.py:
--------------------------------------------------------------------------------
1 | """
2 | Given an array nums, there is a sliding window of size k
3 | which is moving from the very left of the array to the very right.
4 | You can only see the k numbers in the window.
5 | Each time the sliding window moves right by one position.
6 |
7 | For example,
8 | Given nums = [1,3,-1,-3,5,3,6,7], and k = 3.
9 |
10 | Window position Max
11 | --------------- -----
12 | [1 3 -1] -3 5 3 6 7 3
13 | 1 [3 -1 -3] 5 3 6 7 3
14 | 1 3 [-1 -3 5] 3 6 7 5
15 | 1 3 -1 [-3 5 3] 6 7 5
16 | 1 3 -1 -3 [5 3 6] 7 6
17 | 1 3 -1 -3 5 [3 6 7] 7
18 | Therefore, return the max sliding window as [3,3,5,5,6,7].
19 | """
20 | import collections
21 |
22 |
23 | def max_sliding_window(nums, k):
24 | """
25 | :type nums: List[int]
26 | :type k: int
27 | :rtype: List[int]
28 | """
29 | if not nums:
30 | return nums
31 | queue = collections.deque()
32 | res = []
33 | for num in nums:
34 | if len(queue) < k:
35 | queue.append(num)
36 | else:
37 | res.append(max(queue))
38 | queue.popleft()
39 | queue.append(num)
40 | res.append(max(queue))
41 | return res
42 |
--------------------------------------------------------------------------------
/algorithms/linkedlist/__init__.py:
--------------------------------------------------------------------------------
1 | from .reverse import *
2 | from .is_sorted import *
3 | from .remove_range import *
4 | from .swap_in_pairs import *
5 | from .rotate_list import *
6 | from .is_cyclic import *
7 | from .merge_two_list import *
8 | from .is_palindrome import *
9 | from .copy_random_pointer import *
10 |
--------------------------------------------------------------------------------
/algorithms/linkedlist/copy_random_pointer.py:
--------------------------------------------------------------------------------
1 | """
2 | A linked list is given such that each node contains an additional random
3 | pointer which could point to any node in the list or null.
4 |
5 | Return a deep copy of the list.
6 | """
7 | from collections import defaultdict
8 |
9 |
10 | class RandomListNode(object):
11 | def __init__(self, label):
12 | self.label = label
13 | self.next = None
14 | self.random = None
15 |
16 |
17 | def copy_random_pointer_v1(head):
18 | """
19 | :type head: RandomListNode
20 | :rtype: RandomListNode
21 | """
22 | dic = dict()
23 | m = n = head
24 | while m:
25 | dic[m] = RandomListNode(m.label)
26 | m = m.next
27 | while n:
28 | dic[n].next = dic.get(n.next)
29 | dic[n].random = dic.get(n.random)
30 | n = n.next
31 | return dic.get(head)
32 |
33 |
34 | # O(n)
35 | def copy_random_pointer_v2(head):
36 | """
37 | :type head: RandomListNode
38 | :rtype: RandomListNode
39 | """
40 | copy = defaultdict(lambda: RandomListNode(0))
41 | copy[None] = None
42 | node = head
43 | while node:
44 | copy[node].label = node.label
45 | copy[node].next = copy[node.next]
46 | copy[node].random = copy[node.random]
47 | node = node.next
48 | return copy[head]
49 |
--------------------------------------------------------------------------------
/algorithms/linkedlist/is_cyclic.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a linked list, determine if it has a cycle in it.
3 |
4 | Follow up:
5 | Can you solve it without using extra space?
6 | """
7 | class Node:
8 |
9 | def __init__(self, x):
10 | self.val = x
11 | self.next = None
12 |
13 | def is_cyclic(head):
14 | """
15 | :type head: Node
16 | :rtype: bool
17 | """
18 | if not head:
19 | return False
20 | runner = head
21 | walker = head
22 | while runner.next and runner.next.next:
23 | runner = runner.next.next
24 | walker = walker.next
25 | if runner == walker:
26 | return True
27 | return False
28 |
--------------------------------------------------------------------------------
/algorithms/linkedlist/is_sorted.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a linked list, is_sort function returns true if the list is in sorted
3 | (increasing) order and return false otherwise. An empty list is considered
4 | to be sorted.
5 |
6 | For example:
7 | Null :List is sorted
8 | 1 2 3 4 :List is sorted
9 | 1 2 -1 3 :List is not sorted
10 | """
11 | def is_sorted(head):
12 | if not head:
13 | return True
14 | current = head
15 | while current.next:
16 | if current.val > current.next.val:
17 | return False
18 | current = current.next
19 | return True
20 |
--------------------------------------------------------------------------------
/algorithms/linkedlist/linkedlist.py:
--------------------------------------------------------------------------------
1 | # Pros
2 | # Linked Lists have constant-time insertions and deletions in any position,
3 | # in comparison, arrays require O(n) time to do the same thing.
4 | # Linked lists can continue to expand without having to specify
5 | # their size ahead of time (remember our lectures on Array sizing
6 | # from the Array Sequence section of the course!)
7 |
8 | # Cons
9 | # To access an element in a linked list, you need to take O(k) time
10 | # to go from the head of the list to the kth element.
11 | # In contrast, arrays have constant time operations to access
12 | # elements in an array.
13 |
14 | class DoublyLinkedListNode(object):
15 | def __init__(self, value):
16 | self.value = value
17 | self.next = None
18 | self.prev = None
19 |
20 |
21 | class SinglyLinkedListNode(object):
22 | def __init__(self, value):
23 | self.value = value
24 | self.next = None
25 |
--------------------------------------------------------------------------------
/algorithms/linkedlist/merge_two_list.py:
--------------------------------------------------------------------------------
1 | """
2 | Merge two sorted linked lists and return it as a new list. The new list should
3 | be made by splicing together the nodes of the first two lists.
4 |
5 | For example:
6 | Input: 1->2->4, 1->3->4
7 | Output: 1->1->2->3->4->4
8 | """
9 | class Node:
10 |
11 | def __init__(self, x):
12 | self.val = x
13 | self.next = None
14 |
15 | def merge_two_list(l1, l2):
16 | ret = cur = Node(0)
17 | while l1 and l2:
18 | if l1.val < l2.val:
19 | cur.next = l1
20 | l1 = l1.next
21 | else:
22 | cur.next = l2
23 | l2 = l2.next
24 | cur = cur.next
25 | cur.next = l1 or l2
26 | return ret.next
27 |
28 | # recursively
29 | def merge_two_list_recur(l1, l2):
30 | if not l1 or not l2:
31 | return l1 or l2
32 | if l1.val < l2.val:
33 | l1.next = merge_two_list_recur(l1.next, l2)
34 | return l1
35 | else:
36 | l2.next = merge_two_list_recur(l1, l2.next)
37 | return l2
38 |
--------------------------------------------------------------------------------
/algorithms/linkedlist/remove_range.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a linked list, remove_range function accepts a starting and ending index
3 | as parameters and removes the elements at those indexes (inclusive) from the list
4 |
5 | For example:
6 | List: [8, 13, 17, 4, 9, 12, 98, 41, 7, 23, 0, 92]
7 | remove_range(list, 3, 8);
8 | List becomes: [8, 13, 17, 23, 0, 92]
9 |
10 | legal range of the list (0 < start index < end index < size of list).
11 | """
12 | def remove_range(head, start, end):
13 | assert(start <= end)
14 | # Case: remove node at head
15 | if start == 0:
16 | for i in range(0, end+1):
17 | if head != None:
18 | head = head.next
19 | else:
20 | current = head
21 | # Move pointer to start position
22 | for i in range(0,start-1):
23 | current = current.next
24 | # Remove data until the end
25 | for i in range(0, end-start + 1):
26 | if current != None and current.next != None:
27 | current.next = current.next.next
28 | return head
29 |
--------------------------------------------------------------------------------
/algorithms/linkedlist/reverse.py:
--------------------------------------------------------------------------------
1 | """
2 | Reverse a singly linked list. For example:
3 |
4 | 1 --> 2 --> 3 --> 4
5 | After reverse:
6 | 4 --> 3 --> 2 --> 1
7 | """
8 | #
9 | # Iterative solution
10 | # T(n)- O(n)
11 | #
12 | def reverse_list(head):
13 | """
14 | :type head: ListNode
15 | :rtype: ListNode
16 | """
17 | if not head or not head.next:
18 | return head
19 | prev = None
20 | while head:
21 | current = head
22 | head = head.next
23 | current.next = prev
24 | prev = current
25 | return prev
26 |
27 |
28 | #
29 | # Recursive solution
30 | # T(n)- O(n)
31 | #
32 | def reverse_list_recursive(head):
33 | """
34 | :type head: ListNode
35 | :rtype: ListNode
36 | """
37 | if head is None or head.next is None:
38 | return head
39 | p = head.next
40 | head.next = None
41 | revrest = reverse_list_recursive(p)
42 | p.next = head
43 | return revrest
44 |
--------------------------------------------------------------------------------
/algorithms/linkedlist/rotate_list.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a list, rotate the list to the right by k places,
3 | where k is non-negative.
4 |
5 | For example:
6 | Given 1->2->3->4->5->NULL and k = 2,
7 | return 4->5->1->2->3->NULL.
8 | """
9 |
10 | # Definition for singly-linked list.
11 | # class ListNode(object):
12 | # def __init__(self, x):
13 | # self.val = x
14 | # self.next = None
15 |
16 |
17 | def rotate_right(head, k):
18 | """
19 | :type head: ListNode
20 | :type k: int
21 | :rtype: ListNode
22 | """
23 | if not head or not head.next:
24 | return head
25 | current = head
26 | length = 1
27 | # count length of the list
28 | while current.next:
29 | current = current.next
30 | length += 1
31 | # make it circular
32 | current.next = head
33 | k = k % length
34 | # rotate until length-k
35 | for i in range(length-k):
36 | current = current.next
37 | head = current.next
38 | current.next = None
39 | return head
40 |
--------------------------------------------------------------------------------
/algorithms/linkedlist/swap_in_pairs.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a linked list, swap every two adjacent nodes
3 | and return its head.
4 |
5 | For example,
6 | Given 1->2->3->4, you should return the list as 2->1->4->3.
7 |
8 | Your algorithm should use only constant space.
9 | You may not modify the values in the list,
10 | only nodes itself can be changed.
11 | """
12 | class Node(object):
13 | def __init__(self, x):
14 | self.val = x
15 | self.next = None
16 |
17 | def swap_pairs(head):
18 | if not head:
19 | return head
20 | start = Node(0)
21 | start.next = head
22 | current = start
23 | while current.next and current.next.next:
24 | first = current.next
25 | second = current.next.next
26 | first.next = second.next
27 | current.next = second
28 | current.next.next = first
29 | current = current.next.next
30 | return start.next
31 |
--------------------------------------------------------------------------------
/algorithms/map/__init__.py:
--------------------------------------------------------------------------------
1 | from .hashtable import *
2 | from .separate_chaining_hashtable import *
3 | from .word_pattern import *
4 | from .is_isomorphic import *
5 | from .is_anagram import *
6 | from .longest_palindromic_subsequence import *
7 |
--------------------------------------------------------------------------------
/algorithms/map/is_anagram.py:
--------------------------------------------------------------------------------
1 | """
2 | Given two strings s and t , write a function to determine if t is an anagram of s.
3 |
4 | Example 1:
5 | Input: s = "anagram", t = "nagaram"
6 | Output: true
7 |
8 | Example 2:
9 | Input: s = "rat", t = "car"
10 | Output: false
11 |
12 | Note:
13 | You may assume the string contains only lowercase alphabets.
14 |
15 | Reference: https://leetcode.com/problems/valid-anagram/description/
16 | """
17 | def is_anagram(s, t):
18 | """
19 | :type s: str
20 | :type t: str
21 | :rtype: bool
22 | """
23 | maps = {}
24 | mapt = {}
25 | for i in s:
26 | maps[i] = maps.get(i, 0) + 1
27 | for i in t:
28 | mapt[i] = mapt.get(i, 0) + 1
29 | return maps == mapt
30 |
--------------------------------------------------------------------------------
/algorithms/map/is_isomorphic.py:
--------------------------------------------------------------------------------
1 | """
2 | Given two strings s and t, determine if they are isomorphic.
3 | Two strings are isomorphic if the characters in s can be replaced to get t.
4 | All occurrences of a character must be replaced with another character while
5 | preserving the order of characters. No two characters may map to the same
6 | character but a character may map to itself.
7 |
8 | Example 1:
9 | Input: s = "egg", t = "add"
10 | Output: true
11 |
12 | Example 2:
13 | Input: s = "foo", t = "bar"
14 | Output: false
15 |
16 | Example 3:
17 | Input: s = "paper", t = "title"
18 | Output: true
19 | Reference: https://leetcode.com/problems/isomorphic-strings/description/
20 | """
21 | def is_isomorphic(s, t):
22 | """
23 | :type s: str
24 | :type t: str
25 | :rtype: bool
26 | """
27 | if len(s) != len(t):
28 | return False
29 | dict = {}
30 | set_value = set()
31 | for i in range(len(s)):
32 | if s[i] not in dict:
33 | if t[i] in set_value:
34 | return False
35 | dict[s[i]] = t[i]
36 | set_value.add(t[i])
37 | else:
38 | if dict[s[i]] != t[i]:
39 | return False
40 | return True
41 |
--------------------------------------------------------------------------------
/algorithms/map/longest_common_subsequence.py:
--------------------------------------------------------------------------------
1 | """
2 | Given string a and b, with b containing all distinct characters,
3 | find the longest common sub sequence's length.
4 |
5 | Expected complexity O(n logn).
6 | """
7 |
8 |
9 | def max_common_sub_string(s1, s2):
10 | # Assuming s2 has all unique chars
11 | s2dic = {s2[i]: i for i in range(len(s2))}
12 | maxr = 0
13 | subs = ''
14 | i = 0
15 | while i < len(s1):
16 | if s1[i] in s2dic:
17 | j = s2dic[s1[i]]
18 | k = i
19 | while j < len(s2) and k < len(s1) and s1[k] == s2[j]:
20 | k += 1
21 | j += 1
22 | if k - i > maxr:
23 | maxr = k-i
24 | subs = s1[i:k]
25 | i = k
26 | else:
27 | i += 1
28 | return subs
29 |
--------------------------------------------------------------------------------
/algorithms/map/longest_palindromic_subsequence.py:
--------------------------------------------------------------------------------
1 | def longest_palindromic_subsequence(s):
2 |
3 | k = len(s)
4 | olist = [0] * k # 申请长度为n的列表,并初始化
5 | nList = [0] * k # 同上
6 | logestSubStr = ""
7 | logestLen = 0
8 |
9 | for j in range(0, k):
10 | for i in range(0, j + 1):
11 | if j - i <= 1:
12 | if s[i] == s[j]:
13 | nList[i] = 1 # 当 j 时,第 i 个子串为回文子串
14 | len_t = j - i + 1
15 | if logestLen < len_t: # 判断长度
16 | logestSubStr = s[i:j + 1]
17 | logestLen = len_t
18 | else:
19 | if s[i] == s[j] and olist[i+1]: # 当j-i>1时,判断s[i]是否等于s[j],并判断当j-1时,第i+1个子串是否为回文子串
20 | nList[i] = 1 # 当 j 时,第 i 个子串为回文子串
21 | len_t = j - i + 1
22 | if logestLen < len_t:
23 | logestSubStr = s[i:j + 1]
24 | logestLen = len_t
25 | olist = nList # 覆盖旧的列表
26 | nList = [0] * k # 新的列表清空
27 | # ~ from icecream import ic
28 | # ~ ic(s, logestSubStr)
29 | return logestLen#, logestSubStr
30 |
--------------------------------------------------------------------------------
/algorithms/map/valid_sudoku.py:
--------------------------------------------------------------------------------
1 | """
2 | Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules.
3 |
4 | The Sudoku board could be partially filled, where empty cells are filled with
5 | the character '.'.
6 | """
7 |
8 | def is_valid_sudoku(self, board):
9 | seen = []
10 | for i, row in enumerate(board):
11 | for j, c in enumerate(row):
12 | if c != '.':
13 | seen += [(c,j),(i,c),(i/3,j/3,c)]
14 | return len(seen) == len(set(seen))
15 |
--------------------------------------------------------------------------------
/algorithms/maths/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Collection of mathematical algorithms and functions.
3 | """
4 | from .base_conversion import *
5 | from .decimal_to_binary_ip import *
6 | from .euler_totient import *
7 | from .extended_gcd import *
8 | from .factorial import *
9 | from .gcd import *
10 | from .generate_strobogrammtic import *
11 | from .is_strobogrammatic import *
12 | from .modular_exponential import *
13 | from .next_perfect_square import *
14 | from .prime_check import *
15 | from .primes_sieve_of_eratosthenes import *
16 | from .pythagoras import *
17 | from .rabin_miller import *
18 | from .rsa import *
19 | from .combination import *
20 | from .cosine_similarity import *
21 | from .find_order_simple import *
22 | from .find_primitive_root_simple import *
23 | from .diffie_hellman_key_exchange import *
24 | from .num_digits import *
25 | from .power import *
26 | from .magic_number import *
27 | from .krishnamurthy_number import *
28 | from .num_perfect_squares import *
29 |
--------------------------------------------------------------------------------
/algorithms/maths/base_conversion.py:
--------------------------------------------------------------------------------
1 | """
2 | Integer base conversion algorithm
3 |
4 | int_to_base(5, 2) return '101'.
5 | base_to_int('F', 16) return 15.
6 |
7 | """
8 |
9 | import string
10 |
11 | def int_to_base(num, base):
12 | """
13 | :type num: int
14 | :type base: int
15 | :rtype: str
16 | """
17 | is_negative = False
18 | if num == 0:
19 | return '0'
20 | if num < 0:
21 | is_negative = True
22 | num *= -1
23 | digit = string.digits + string.ascii_uppercase
24 | res = ''
25 | while num > 0:
26 | res += digit[num % base]
27 | num //= base
28 | if is_negative:
29 | return '-' + res[::-1]
30 | return res[::-1]
31 |
32 |
33 | def base_to_int(str_to_convert, base):
34 | """
35 | Note : You can use int() built-in function instead of this.
36 | :type str_to_convert: str
37 | :type base: int
38 | :rtype: int
39 | """
40 |
41 | digit = {}
42 | for ind, char in enumerate(string.digits + string.ascii_uppercase):
43 | digit[char] = ind
44 | multiplier = 1
45 | res = 0
46 | for char in str_to_convert[::-1]:
47 | res += digit[char] * multiplier
48 | multiplier *= base
49 | return res
50 |
--------------------------------------------------------------------------------
/algorithms/maths/combination.py:
--------------------------------------------------------------------------------
1 | """
2 | Functions to calculate nCr (ie how many ways to choose r items from n items)
3 | """
4 | def combination(n, r):
5 | """This function calculates nCr."""
6 | if n == r or r == 0:
7 | return 1
8 | return combination(n-1, r-1) + combination(n-1, r)
9 |
10 | def combination_memo(n, r):
11 | """This function calculates nCr using memoization method."""
12 | memo = {}
13 | def recur(n, r):
14 | if n == r or r == 0:
15 | return 1
16 | if (n, r) not in memo:
17 | memo[(n, r)] = recur(n - 1, r - 1) + recur(n - 1, r)
18 | return memo[(n, r)]
19 | return recur(n, r)
20 |
--------------------------------------------------------------------------------
/algorithms/maths/cosine_similarity.py:
--------------------------------------------------------------------------------
1 | """
2 | Calculate cosine similarity between given two 1d list.
3 | Two list must have the same length.
4 |
5 | Example:
6 | cosine_similarity([1, 1, 1], [1, 2, -1]) # output : 0.47140452079103173
7 | """
8 | import math
9 |
10 |
11 | def _l2_distance(vec):
12 | """
13 | Calculate l2 distance from two given vectors.
14 | """
15 | norm = 0.
16 | for element in vec:
17 | norm += element * element
18 | norm = math.sqrt(norm)
19 | return norm
20 |
21 |
22 | def cosine_similarity(vec1, vec2):
23 | """
24 | Calculate cosine similarity between given two vectors
25 | :type vec1: list
26 | :type vec2: list
27 | """
28 | if len(vec1) != len(vec2):
29 | raise ValueError("The two vectors must be the same length. Got shape " + str(len(vec1))
30 | + " and " + str(len(vec2)))
31 |
32 | norm_a = _l2_distance(vec1)
33 | norm_b = _l2_distance(vec2)
34 |
35 | similarity = 0.
36 |
37 | # Calculate the dot product of two vectors
38 | for vec1_element, vec2_element in zip(vec1, vec2):
39 | similarity += vec1_element * vec2_element
40 |
41 | similarity /= (norm_a * norm_b)
42 |
43 | return similarity
44 |
--------------------------------------------------------------------------------
/algorithms/maths/decimal_to_binary_ip.py:
--------------------------------------------------------------------------------
1 | """
2 | Given an ip address in dotted-decimal representation, determine the
3 | binary representation. For example,
4 | decimal_to_binary(255.0.0.5) returns 11111111.00000000.00000000.00000101
5 | accepts string
6 | returns string
7 | """
8 |
9 | def decimal_to_binary_util(val):
10 | """
11 | Convert 8-bit decimal number to binary representation
12 | :type val: str
13 | :rtype: str
14 | """
15 | bits = [128, 64, 32, 16, 8, 4, 2, 1]
16 | val = int(val)
17 | binary_rep = ''
18 | for bit in bits:
19 | if val >= bit:
20 | binary_rep += str(1)
21 | val -= bit
22 | else:
23 | binary_rep += str(0)
24 |
25 | return binary_rep
26 |
27 | def decimal_to_binary_ip(ip):
28 | """
29 | Convert dotted-decimal ip address to binary representation with help of decimal_to_binary_util
30 | """
31 | values = ip.split('.')
32 | binary_list = []
33 | for val in values:
34 | binary_list.append(decimal_to_binary_util(val))
35 | return '.'.join(binary_list)
36 |
--------------------------------------------------------------------------------
/algorithms/maths/euler_totient.py:
--------------------------------------------------------------------------------
1 | """
2 | Euler's totient function, also known as phi-function ϕ(n),
3 | counts the number of integers between 1 and n inclusive,
4 | which are coprime to n.
5 | (Two numbers are coprime if their greatest common divisor (GCD) equals 1).
6 | """
7 | def euler_totient(n):
8 | """Euler's totient function or Phi function.
9 | Time Complexity: O(sqrt(n))."""
10 | result = n
11 | for i in range(2, int(n ** 0.5) + 1):
12 | if n % i == 0:
13 | while n % i == 0:
14 | n //= i
15 | result -= result // i
16 | if n > 1:
17 | result -= result // n
18 | return result
19 |
--------------------------------------------------------------------------------
/algorithms/maths/extended_gcd.py:
--------------------------------------------------------------------------------
1 | """
2 | Provides extended GCD functionality for finding co-prime numbers s and t such that:
3 | num1 * s + num2 * t = GCD(num1, num2).
4 | Ie the coefficients of Bézout's identity.
5 | """
6 | def extended_gcd(num1, num2):
7 | """Extended GCD algorithm.
8 | Return s, t, g
9 | such that num1 * s + num2 * t = GCD(num1, num2)
10 | and s and t are co-prime.
11 | """
12 |
13 | old_s, s = 1, 0
14 | old_t, t = 0, 1
15 | old_r, r = num1, num2
16 |
17 | while r != 0:
18 | quotient = old_r / r
19 |
20 | old_r, r = r, old_r - quotient * r
21 | old_s, s = s, old_s - quotient * s
22 | old_t, t = t, old_t - quotient * t
23 |
24 | return old_s, old_t, old_r
25 |
--------------------------------------------------------------------------------
/algorithms/maths/factorial.py:
--------------------------------------------------------------------------------
1 | """
2 | Calculates the factorial with the added functionality of calculating it modulo mod.
3 | """
4 | def factorial(n, mod=None):
5 | """Calculates factorial iteratively.
6 | If mod is not None, then return (n! % mod)
7 | Time Complexity - O(n)"""
8 | if not (isinstance(n, int) and n >= 0):
9 | raise ValueError("'n' must be a non-negative integer.")
10 | if mod is not None and not (isinstance(mod, int) and mod > 0):
11 | raise ValueError("'mod' must be a positive integer")
12 | result = 1
13 | if n == 0:
14 | return 1
15 | for i in range(2, n+1):
16 | result *= i
17 | if mod:
18 | result %= mod
19 | return result
20 |
21 |
22 | def factorial_recur(n, mod=None):
23 | """Calculates factorial recursively.
24 | If mod is not None, then return (n! % mod)
25 | Time Complexity - O(n)"""
26 | if not (isinstance(n, int) and n >= 0):
27 | raise ValueError("'n' must be a non-negative integer.")
28 | if mod is not None and not (isinstance(mod, int) and mod > 0):
29 | raise ValueError("'mod' must be a positive integer")
30 | if n == 0:
31 | return 1
32 | result = n * factorial(n - 1, mod)
33 | if mod:
34 | result %= mod
35 | return result
36 |
--------------------------------------------------------------------------------
/algorithms/maths/fft.py:
--------------------------------------------------------------------------------
1 | """
2 | Implementation of the Cooley-Tukey, which is the most common FFT algorithm.
3 |
4 | Input: an array of complex values which has a size of N, where N is an integer power of 2
5 | Output: an array of complex values which is the discrete fourier transform of the input
6 |
7 | Example 1
8 | Input: [2.0+2j, 1.0+3j, 3.0+1j, 2.0+2j]
9 | Output: [8+8j, 2j, 2-2j, -2+0j]
10 |
11 |
12 | Pseudocode: https://en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm
13 | """
14 | from cmath import exp, pi
15 |
16 | def fft(x):
17 | """ Recursive implementation of the Cooley-Tukey"""
18 | N = len(x)
19 | if N == 1:
20 | return x
21 |
22 | # get the elements at even/odd indices
23 | even = fft(x[0::2])
24 | odd = fft(x[1::2])
25 |
26 | y = [0 for i in range(N)]
27 | for k in range(N//2):
28 | q = exp(-2j*pi*k/N)*odd[k]
29 | y[k] = even[k] + q
30 | y[k + N//2] = even[k] - q
31 |
32 | return y
33 |
--------------------------------------------------------------------------------
/algorithms/maths/find_order_simple.py:
--------------------------------------------------------------------------------
1 | """
2 | For positive integer n and given integer a that satisfies gcd(a, n) = 1,
3 | the order of a modulo n is the smallest positive integer k that satisfies
4 | pow (a, k) % n = 1. In other words, (a^k) ≡ 1 (mod n).
5 | Order of a certain number may or may not be exist. If not, return -1.
6 |
7 | Total time complexity O(nlog(n)):
8 | O(n) for iteration loop,
9 | O(log(n)) for built-in power function
10 | """
11 |
12 | import math
13 |
14 | def find_order(a, n):
15 | """
16 | Find order for positive integer n and given integer a that satisfies gcd(a, n) = 1.
17 | """
18 | if (a == 1) & (n == 1):
19 | # Exception Handeling : 1 is the order of of 1
20 | return 1
21 | if math.gcd(a, n) != 1:
22 | print ("a and n should be relative prime!")
23 | return -1
24 | for i in range(1, n):
25 | if pow(a, i) % n == 1:
26 | return i
27 | return -1
28 |
--------------------------------------------------------------------------------
/algorithms/maths/hailstone.py:
--------------------------------------------------------------------------------
1 | """
2 | Implementation of hailstone function which generates a sequence for some n by following these rules:
3 | * n == 1 : done
4 | * n is even : the next n = n/2
5 | * n is odd : the next n = 3n + 1
6 | """
7 |
8 | def hailstone(n):
9 | """
10 | Return the 'hailstone sequence' from n to 1
11 | n: The starting point of the hailstone sequence
12 | """
13 |
14 | sequence = [n]
15 | while n > 1:
16 | if n%2 != 0:
17 | n = 3*n + 1
18 | else:
19 | n = int(n/2)
20 | sequence.append(n)
21 | return sequence
22 |
--------------------------------------------------------------------------------
/algorithms/maths/is_strobogrammatic.py:
--------------------------------------------------------------------------------
1 | """
2 | A strobogrammatic number is a number that looks
3 | the same when rotated 180 degrees (looked at upside down).
4 |
5 | Write a function to determine if a number is strobogrammatic.
6 | The number is represented as a string.
7 |
8 | For example, the numbers "69", "88", and "818" are all strobogrammatic.
9 | """
10 |
11 |
12 | def is_strobogrammatic(num):
13 | """
14 | :type num: str
15 | :rtype: bool
16 | """
17 | comb = "00 11 88 69 96"
18 | i = 0
19 | j = len(num) - 1
20 | while i <= j:
21 | if comb.find(num[i]+num[j]) == -1:
22 | return False
23 | i += 1
24 | j -= 1
25 | return True
26 |
27 |
28 | def is_strobogrammatic2(num: str):
29 | """Another implementation."""
30 | return num == num[::-1].replace('6', '#').replace('9', '6').replace('#', '9')
31 |
--------------------------------------------------------------------------------
/algorithms/maths/magic_number.py:
--------------------------------------------------------------------------------
1 | """
2 | Magic Number
3 | A number is said to be a magic number,
4 | if summing the digits of the number and then recursively repeating this process for the given sum
5 | untill the number becomes a single digit number equal to 1.
6 |
7 | Example:
8 | Number = 50113 => 5+0+1+1+3=10 => 1+0=1 [This is a Magic Number]
9 | Number = 1234 => 1+2+3+4=10 => 1+0=1 [This is a Magic Number]
10 | Number = 199 => 1+9+9=19 => 1+9=10 => 1+0=1 [This is a Magic Number]
11 | Number = 111 => 1+1+1=3 [This is NOT a Magic Number]
12 |
13 | The following function checks for Magic numbers and returns a Boolean accordingly.
14 | """
15 |
16 | def magic_number(n):
17 | """ Checks if n is a magic number """
18 | total_sum = 0
19 |
20 | # will end when n becomes 0
21 | # AND
22 | # sum becomes single digit.
23 | while n > 0 or total_sum > 9:
24 | # when n becomes 0 but we have a total_sum,
25 | # we update the value of n with the value of the sum digits
26 | if n == 0:
27 | n = total_sum # only when sum of digits isn't single digit
28 | total_sum = 0
29 | total_sum += n % 10
30 | n //= 10
31 |
32 | # Return true if sum becomes 1
33 | return total_sum == 1
34 |
--------------------------------------------------------------------------------
/algorithms/maths/modular_exponential.py:
--------------------------------------------------------------------------------
1 | def modular_exponential(base, exponent, mod):
2 | """Computes (base ^ exponent) % mod.
3 | Time complexity - O(log n)
4 | Use similar to Python in-built function pow."""
5 | if exponent < 0:
6 | raise ValueError("Exponent must be positive.")
7 | base %= mod
8 | result = 1
9 |
10 | while exponent > 0:
11 | # If the last bit is 1, add 2^k.
12 | if exponent & 1:
13 | result = (result * base) % mod
14 | exponent = exponent >> 1
15 | # Utilize modular multiplication properties to combine the computed mod C values.
16 | base = (base * base) % mod
17 |
18 | return result
19 |
--------------------------------------------------------------------------------
/algorithms/maths/modular_inverse.py:
--------------------------------------------------------------------------------
1 | # extended_gcd(a, b) modified from
2 | # https://github.com/keon/algorithms/blob/master/algorithms/maths/extended_gcd.py
3 |
4 | def extended_gcd(a: int, b: int) -> [int, int, int]:
5 | """Extended GCD algorithm.
6 | Return s, t, g
7 | such that a * s + b * t = GCD(a, b)
8 | and s and t are co-prime.
9 | """
10 |
11 | old_s, s = 1, 0
12 | old_t, t = 0, 1
13 | old_r, r = a, b
14 |
15 | while r != 0:
16 | quotient = old_r // r
17 |
18 | old_r, r = r, old_r - quotient * r
19 | old_s, s = s, old_s - quotient * s
20 | old_t, t = t, old_t - quotient * t
21 |
22 | return old_s, old_t, old_r
23 |
24 |
25 | def modular_inverse(a: int, m: int) -> int:
26 | """
27 | Returns x such that a * x = 1 (mod m)
28 | a and m must be coprime
29 | """
30 |
31 | s, _, g = extended_gcd(a, m)
32 | if g != 1:
33 | raise ValueError("a and m must be coprime")
34 | return s % m
35 |
--------------------------------------------------------------------------------
/algorithms/maths/next_perfect_square.py:
--------------------------------------------------------------------------------
1 | """
2 | This program will look for the next perfect square.
3 | Check the argument to see if it is a perfect square itself, if it is not then return -1 otherwise
4 | look for the next perfect square.
5 | for instance if you pass 121 then the script should return the next perfect square which is 144.
6 | """
7 |
8 | def find_next_square(sq):
9 | root = sq ** 0.5
10 | if root.is_integer():
11 | return (root + 1)**2
12 | return -1
13 |
14 | def find_next_square2(sq):
15 | """ Alternative method, works by evaluating anything non-zero as True (0.000001 --> True) """
16 | root = sq**0.5
17 | return -1 if root % 1 else (root+1)**2
18 |
--------------------------------------------------------------------------------
/algorithms/maths/nth_digit.py:
--------------------------------------------------------------------------------
1 | def find_nth_digit(n):
2 | """find the nth digit of given number.
3 | 1. find the length of the number where the nth digit is from.
4 | 2. find the actual number where the nth digit is from
5 | 3. find the nth digit and return
6 | """
7 | length = 1
8 | count = 9
9 | start = 1
10 | while n > length * count:
11 | n -= length * count
12 | length += 1
13 | count *= 10
14 | start *= 10
15 | start += (n-1) / length
16 | s = str(start)
17 | return int(s[(n-1) % length])
18 |
--------------------------------------------------------------------------------
/algorithms/maths/num_digits.py:
--------------------------------------------------------------------------------
1 | """
2 | num_digits() method will return the number of digits of a number in O(1) time using
3 | math.log10() method.
4 | """
5 |
6 | import math
7 |
8 | def num_digits(n):
9 | n=abs(n)
10 | if n==0:
11 | return 1
12 | return int(math.log10(n))+1
13 |
--------------------------------------------------------------------------------
/algorithms/maths/power.py:
--------------------------------------------------------------------------------
1 | """
2 | Performs exponentiation, similarly to the built-in pow() or ** functions.
3 | Allows also for calculating the exponentiation modulo.
4 | """
5 | def power(a: int, n: int, mod: int = None):
6 | """
7 | Iterative version of binary exponentiation
8 |
9 | Calculate a ^ n
10 | if mod is specified, return the result modulo mod
11 |
12 | Time Complexity : O(log(n))
13 | Space Complexity : O(1)
14 | """
15 | ans = 1
16 | while n:
17 | if n & 1:
18 | ans = ans * a
19 | a = a * a
20 | if mod:
21 | ans %= mod
22 | a %= mod
23 | n >>= 1
24 | return ans
25 |
26 |
27 | def power_recur(a: int, n: int, mod: int = None):
28 | """
29 | Recursive version of binary exponentiation
30 |
31 | Calculate a ^ n
32 | if mod is specified, return the result modulo mod
33 |
34 | Time Complexity : O(log(n))
35 | Space Complexity : O(log(n))
36 | """
37 | if n == 0:
38 | ans = 1
39 | elif n == 1:
40 | ans = a
41 | else:
42 | ans = power_recur(a, n // 2, mod)
43 | ans = ans * ans
44 | if n % 2:
45 | ans = ans * a
46 | if mod:
47 | ans %= mod
48 | return ans
49 |
--------------------------------------------------------------------------------
/algorithms/maths/prime_check.py:
--------------------------------------------------------------------------------
1 | def prime_check(n):
2 | """Return True if n is a prime number
3 | Else return False.
4 | """
5 |
6 | if n <= 1:
7 | return False
8 | if n == 2 or n == 3:
9 | return True
10 | if n % 2 == 0 or n % 3 == 0:
11 | return False
12 | j = 5
13 | while j * j <= n:
14 | if n % j == 0 or n % (j + 2) == 0:
15 | return False
16 | j += 6
17 | return True
18 |
--------------------------------------------------------------------------------
/algorithms/maths/pythagoras.py:
--------------------------------------------------------------------------------
1 | """
2 | Given the lengths of two of the three sides of a right angled triangle, this function returns the
3 | length of the third side.
4 | """
5 |
6 | def pythagoras(opposite, adjacent, hypotenuse):
7 | """
8 | Returns length of a third side of a right angled triangle.
9 | Passing "?" will indicate the unknown side.
10 | """
11 | try:
12 | if opposite == str("?"):
13 | return ("Opposite = " + str(((hypotenuse**2) - (adjacent**2))**0.5))
14 | if adjacent == str("?"):
15 | return ("Adjacent = " + str(((hypotenuse**2) - (opposite**2))**0.5))
16 | if hypotenuse == str("?"):
17 | return ("Hypotenuse = " + str(((opposite**2) + (adjacent**2))**0.5))
18 | return "You already know the answer!"
19 | except:
20 | raise ValueError("invalid argument(s) were given.")
21 |
--------------------------------------------------------------------------------
/algorithms/maths/recursive_binomial_coefficient.py:
--------------------------------------------------------------------------------
1 | def recursive_binomial_coefficient(n,k):
2 | """Calculates the binomial coefficient, C(n,k), with n>=k using recursion
3 | Time complexity is O(k), so can calculate fairly quickly for large values of k.
4 |
5 | >>> recursive_binomial_coefficient(5,0)
6 | 1
7 |
8 | >>> recursive_binomial_coefficient(8,2)
9 | 28
10 |
11 | >>> recursive_binomial_coefficient(500,300)
12 | 5054949849935535817667719165973249533761635252733275327088189563256013971725761702359997954491403585396607971745777019273390505201262259748208640
13 |
14 | """
15 |
16 | if k>n:
17 | raise ValueError('Invalid Inputs, ensure that n >= k')
18 | #function is only defined for n>=k
19 | if k == 0 or n == k:
20 | #C(n,0) = C(n,n) = 1, so this is our base case.
21 | return 1
22 | if k > n/2:
23 | #C(n,k) = C(n,n-k), so if n/2 is sufficiently small, we can reduce the problem size.
24 | return recursive_binomial_coefficient(n,n-k)
25 | #else, we know C(n,k) = (n/k)C(n-1,k-1), so we can use this to reduce our problem size.
26 | return int((n/k)*recursive_binomial_coefficient(n-1,k-1))
27 |
--------------------------------------------------------------------------------
/algorithms/maths/sqrt_precision_factor.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a positive integer N and a precision factor P,
3 | it produces an output
4 | with a maximum error P from the actual square root of N.
5 |
6 | Example:
7 | Given N = 5 and P = 0.001, can produce output x such that
8 | 2.235 < x < 2.237. Actual square root of 5 being 2.236.
9 | """
10 |
11 |
12 | def square_root(n, epsilon=0.001):
13 | """Return square root of n, with maximum absolute error epsilon"""
14 | guess = n / 2
15 |
16 | while abs(guess * guess - n) > epsilon:
17 | guess = (guess + (n / guess)) / 2
18 |
19 | return guess
20 |
--------------------------------------------------------------------------------
/algorithms/maths/summing_digits.py:
--------------------------------------------------------------------------------
1 | """
2 | Recently, I encountered an interview question whose description was as below:
3 |
4 | The number 89 is the first integer with more than one digit whose digits when raised up to
5 | consecutive powers give the same number. For example, 89 = 8**1 + 9**2 gives the number 89.
6 |
7 | The next number after 89 with this property is 135 = 1**1 + 3**2 + 5**3 = 135.
8 |
9 | Write a function that returns a list of numbers with the above property. The function will
10 | receive range as parameter.
11 | """
12 |
13 | def sum_dig_pow(low, high):
14 | result = []
15 |
16 | for number in range(low, high + 1):
17 | exponent = 1 # set to 1
18 | summation = 0 # set to 1
19 | number_as_string = str(number)
20 |
21 | tokens = list(map(int, number_as_string)) # parse the string into individual digits
22 |
23 | for k in tokens:
24 | summation = summation + (k ** exponent)
25 | exponent += 1
26 |
27 | if summation == number:
28 | result.append(number)
29 | return result
30 |
31 |
32 | # Some test cases:
33 | assert sum_dig_pow(1, 10) == [1, 2, 3, 4, 5, 6, 7, 8, 9]
34 | assert sum_dig_pow(1, 100) == [1, 2, 3, 4, 5, 6, 7, 8, 9, 89]
35 |
--------------------------------------------------------------------------------
/algorithms/matrix/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/cad4754bc71742c2d6fcbd3b92ae74834d359844/algorithms/matrix/__init__.py
--------------------------------------------------------------------------------
/algorithms/matrix/matrix_exponentiation.py:
--------------------------------------------------------------------------------
1 | def multiply(matA: list, matB: list) -> list:
2 | """
3 | Multiplies two square matrices matA and matB of size n x n
4 | Time Complexity: O(n^3)
5 | """
6 | n = len(matA)
7 | matC = [[0 for i in range(n)] for j in range(n)]
8 |
9 | for i in range(n):
10 | for j in range(n):
11 | for k in range(n):
12 | matC[i][j] += matA[i][k] * matB[k][j]
13 |
14 | return matC
15 |
16 |
17 | def identity(n: int) -> list:
18 | """
19 | Returns the Identity matrix of size n x n
20 | Time Complexity: O(n^2)
21 | """
22 | I = [[0 for i in range(n)] for j in range(n)]
23 |
24 | for i in range(n):
25 | I[i][i] = 1
26 |
27 | return I
28 |
29 |
30 | def matrix_exponentiation(mat: list, n: int) -> list:
31 | """
32 | Calculates mat^n by repeated squaring
33 | Time Complexity: O(d^3 log(n))
34 | d: dimension of the square matrix mat
35 | n: power the matrix is raised to
36 | """
37 | if n == 0:
38 | return identity(len(mat))
39 | elif n % 2 == 1:
40 | return multiply(matrix_exponentiation(mat, n - 1), mat)
41 | else:
42 | tmp = matrix_exponentiation(mat, n // 2)
43 | return multiply(tmp, tmp)
44 |
--------------------------------------------------------------------------------
/algorithms/matrix/multiply.py:
--------------------------------------------------------------------------------
1 | """
2 | This algorithm takes two compatible two dimensional matrix
3 | and return their product
4 | Space complexity: O(n^2)
5 | Possible edge case: the number of columns of multiplicand not consistent with
6 | the number of rows of multiplier, will raise exception
7 | """
8 |
9 |
10 | def multiply(multiplicand: list, multiplier: list) -> list:
11 | """
12 | :type A: List[List[int]]
13 | :type B: List[List[int]]
14 | :rtype: List[List[int]]
15 | """
16 | multiplicand_row, multiplicand_col = len(
17 | multiplicand), len(multiplicand[0])
18 | multiplier_row, multiplier_col = len(multiplier), len(multiplier[0])
19 | if(multiplicand_col != multiplier_row):
20 | raise Exception(
21 | "Multiplicand matrix not compatible with Multiplier matrix.")
22 | # create a result matrix
23 | result = [[0] * multiplier_col for i in range(multiplicand_row)]
24 | for i in range(multiplicand_row):
25 | for j in range(multiplier_col):
26 | for k in range(len(multiplier)):
27 | result[i][j] += multiplicand[i][k] * multiplier[k][j]
28 | return result
29 |
--------------------------------------------------------------------------------
/algorithms/matrix/rotate_image.py:
--------------------------------------------------------------------------------
1 | """
2 | You are given an n x n 2D mat representing an image.
3 |
4 | Rotate the image by 90 degrees (clockwise).
5 |
6 | Follow up:
7 | Could you do this in-place?
8 | """
9 |
10 |
11 | # clockwise rotate
12 | # first reverse up to down, then swap the symmetry
13 | # 1 2 3 7 8 9 7 4 1
14 | # 4 5 6 => 4 5 6 => 8 5 2
15 | # 7 8 9 1 2 3 9 6 3
16 |
17 | def rotate(mat):
18 | if not mat:
19 | return mat
20 | mat.reverse()
21 | for i in range(len(mat)):
22 | for j in range(i):
23 | mat[i][j], mat[j][i] = mat[j][i], mat[i][j]
24 | return mat
25 |
26 |
27 | if __name__ == "__main__":
28 | mat = [[1, 2, 3],
29 | [4, 5, 6],
30 | [7, 8, 9]]
31 | print(mat)
32 | rotate(mat)
33 | print(mat)
34 |
--------------------------------------------------------------------------------
/algorithms/matrix/search_in_sorted_matrix.py:
--------------------------------------------------------------------------------
1 | #
2 | # Search a key in a row wise and column wise sorted (non-decreasing) matrix.
3 | # m- Number of rows in the matrix
4 | # n- Number of columns in the matrix
5 | # T(n)- O(m+n)
6 | #
7 |
8 |
9 | def search_in_a_sorted_matrix(mat, m, n, key):
10 | i, j = m-1, 0
11 | while i >= 0 and j < n:
12 | if key == mat[i][j]:
13 | print('Key %s found at row- %s column- %s' % (key, i+1, j+1))
14 | return
15 | if key < mat[i][j]:
16 | i -= 1
17 | else:
18 | j += 1
19 | print('Key %s not found' % (key))
20 |
21 |
22 | def main():
23 | mat = [
24 | [2, 5, 7],
25 | [4, 8, 13],
26 | [9, 11, 15],
27 | [12, 17, 20]
28 | ]
29 | key = 13
30 | print(mat)
31 | search_in_a_sorted_matrix(mat, len(mat), len(mat[0]), key)
32 |
33 |
34 | if __name__ == '__main__':
35 | main()
36 |
--------------------------------------------------------------------------------
/algorithms/matrix/sum_sub_squares.py:
--------------------------------------------------------------------------------
1 | # Function to find sum of all
2 | # sub-squares of size k x k in a given
3 | # square matrix of size n x n
4 | def sum_sub_squares(matrix, k):
5 | n = len(matrix)
6 | result = [[0 for i in range(k)] for j in range(k)]
7 |
8 | if k > n:
9 | return
10 | for i in range(n - k + 1):
11 | l = 0
12 | for j in range(n - k + 1):
13 | sum = 0
14 |
15 | # Calculate and print sum of current sub-square
16 | for p in range(i, k + i):
17 | for q in range(j, k + j):
18 | sum += matrix[p][q]
19 |
20 | result[i][l] = sum
21 | l += 1
22 |
23 | return result
24 |
--------------------------------------------------------------------------------
/algorithms/ml/nearest_neighbor.py:
--------------------------------------------------------------------------------
1 | import math
2 |
3 | def distance(x,y):
4 | """[summary]
5 | HELPER-FUNCTION
6 | calculates the (eulidean) distance between vector x and y.
7 |
8 | Arguments:
9 | x {[tuple]} -- [vector]
10 | y {[tuple]} -- [vector]
11 | """
12 | assert len(x) == len(y), "The vector must have same length"
13 | result = ()
14 | sum = 0
15 | for i in range(len(x)):
16 | result += (x[i] -y[i],)
17 | for component in result:
18 | sum += component**2
19 | return math.sqrt(sum)
20 |
21 |
22 | def nearest_neighbor(x, tSet):
23 | """[summary]
24 | Implements the nearest neighbor algorithm
25 |
26 | Arguments:
27 | x {[tupel]} -- [vector]
28 | tSet {[dict]} -- [training set]
29 |
30 | Returns:
31 | [type] -- [result of the AND-function]
32 | """
33 | assert isinstance(x, tuple) and isinstance(tSet, dict)
34 | current_key = ()
35 | min_d = float('inf')
36 | for key in tSet:
37 | d = distance(x, key)
38 | if d < min_d:
39 | min_d = d
40 | current_key = key
41 | return tSet[current_key]
42 |
--------------------------------------------------------------------------------
/algorithms/queues/__init__.py:
--------------------------------------------------------------------------------
1 | from .queue import *
2 | from .max_sliding_window import *
3 | from .reconstruct_queue import *
4 | from .priority_queue import *
5 |
--------------------------------------------------------------------------------
/algorithms/queues/max_sliding_window.py:
--------------------------------------------------------------------------------
1 | """
2 | Given an array and a number k
3 | Find the max elements of each of its sub-arrays of length k.
4 |
5 | Keep indexes of good candidates in deque d.
6 | The indexes in d are from the current window, they're increasing,
7 | and their corresponding nums are decreasing.
8 | Then the first deque element is the index of the largest window value.
9 |
10 | For each index i:
11 |
12 | 1. Pop (from the end) indexes of smaller elements (they'll be useless).
13 | 2. Append the current index.
14 | 3. Pop (from the front) the index i - k, if it's still in the deque
15 | (it falls out of the window).
16 | 4. If our window has reached size k,
17 | append the current window maximum to the output.
18 | """
19 |
20 | import collections
21 |
22 |
23 | def max_sliding_window(arr, k):
24 | qi = collections.deque() # queue storing indexes of elements
25 | result = []
26 | for i, n in enumerate(arr):
27 | while qi and arr[qi[-1]] < n:
28 | qi.pop()
29 | qi.append(i)
30 | if qi[0] == i - k:
31 | qi.popleft()
32 | if i >= k - 1:
33 | result.append(arr[qi[0]])
34 | return result
35 |
--------------------------------------------------------------------------------
/algorithms/queues/moving_average.py:
--------------------------------------------------------------------------------
1 | from __future__ import division
2 | from collections import deque
3 |
4 |
5 | class MovingAverage(object):
6 | def __init__(self, size):
7 | """
8 | Initialize your data structure here.
9 | :type size: int
10 | """
11 | self.queue = deque(maxlen=size)
12 |
13 | def next(self, val):
14 | """
15 | :type val: int
16 | :rtype: float
17 | """
18 | self.queue.append(val)
19 | return sum(self.queue) / len(self.queue)
20 |
21 |
22 | # Given a stream of integers and a window size,
23 | # calculate the moving average of all integers in the sliding window.
24 | if __name__ == '__main__':
25 | m = MovingAverage(3)
26 | assert m.next(1) == 1
27 | assert m.next(10) == (1 + 10) / 2
28 | assert m.next(3) == (1 + 10 + 3) / 3
29 | assert m.next(5) == (10 + 3 + 5) / 3
30 |
--------------------------------------------------------------------------------
/algorithms/queues/reconstruct_queue.py:
--------------------------------------------------------------------------------
1 | # Suppose you have a random list of people standing in a queue.
2 | # Each person is described by a pair of integers (h, k),
3 | # where h is the height of the person and k is the number of people
4 | # in front of this person who have a height greater than or equal to h.
5 | # Write an algorithm to reconstruct the queue.
6 |
7 | # Note:
8 | # The number of people is less than 1,100.
9 |
10 | # Example
11 |
12 | # Input:
13 | # [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
14 |
15 | # Output:
16 | # [[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]
17 |
18 | def reconstruct_queue(people):
19 | """
20 | :type people: List[List[int]]
21 | :rtype: List[List[int]]
22 | """
23 | queue = []
24 | people.sort(key=lambda x: (-x[0], x[1]))
25 | for h, k in people:
26 | queue.insert(k, [h, k])
27 | return queue
28 |
--------------------------------------------------------------------------------
/algorithms/queues/zigzagiterator.py:
--------------------------------------------------------------------------------
1 | class ZigZagIterator:
2 | def __init__(self, v1, v2):
3 | """
4 | Initialize your data structure here.
5 | :type v1: List[int]
6 | :type v2: List[int]
7 | """
8 | self.queue = [_ for _ in (v1, v2) if _]
9 | print(self.queue)
10 |
11 | def next(self):
12 | """
13 | :rtype: int
14 | """
15 | v = self.queue.pop(0)
16 | ret = v.pop(0)
17 | if v:
18 | self.queue.append(v)
19 | return ret
20 |
21 | def has_next(self):
22 | """
23 | :rtype: bool
24 | """
25 | if self.queue:
26 | return True
27 | return False
28 |
29 |
30 | l1 = [1, 2]
31 | l2 = [3, 4, 5, 6]
32 | it = ZigZagIterator(l1, l2)
33 | while it.has_next():
34 | print(it.next())
35 |
--------------------------------------------------------------------------------
/algorithms/search/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | Collection of search algorithms: finding the needle in a haystack.
3 | """
4 |
5 | from .binary_search import *
6 | from .ternary_search import *
7 | from .first_occurrence import *
8 | from .last_occurrence import *
9 | from .linear_search import *
10 | from .search_insert import *
11 | from .two_sum import *
12 | from .search_range import *
13 | from .find_min_rotate import *
14 | from .search_rotate import *
15 | from .jump_search import *
16 | from .next_greatest_letter import *
17 | from .interpolation_search import *
18 |
--------------------------------------------------------------------------------
/algorithms/search/find_min_rotate.py:
--------------------------------------------------------------------------------
1 | """
2 | Suppose an array sorted in ascending order is rotated at some pivot unknown
3 | to you beforehand. (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).
4 |
5 | Find the minimum element. The complexity must be O(logN)
6 |
7 | You may assume no duplicate exists in the array.
8 | """
9 | def find_min_rotate(array):
10 | """
11 | Finds the minimum element in a sorted array that has been rotated.
12 | """
13 | low = 0
14 | high = len(array) - 1
15 | while low < high:
16 | mid = (low + high) // 2
17 | if array[mid] > array[high]:
18 | low = mid + 1
19 | else:
20 | high = mid
21 |
22 | return array[low]
23 |
24 | def find_min_rotate_recur(array, low, high):
25 | """
26 | Finds the minimum element in a sorted array that has been rotated.
27 | """
28 | mid = (low + high) // 2
29 | if mid == low:
30 | return array[low]
31 | if array[mid] > array[high]:
32 | return find_min_rotate_recur(array, mid + 1, high)
33 | return find_min_rotate_recur(array, low, mid)
34 |
--------------------------------------------------------------------------------
/algorithms/search/first_occurrence.py:
--------------------------------------------------------------------------------
1 | """
2 | Find first occurance of a number in a sorted array (increasing order)
3 | Approach- Binary Search
4 | T(n)- O(log n)
5 | """
6 | def first_occurrence(array, query):
7 | """
8 | Returns the index of the first occurance of the given element in an array.
9 | The array has to be sorted in increasing order.
10 | """
11 |
12 | low, high = 0, len(array) - 1
13 | while low <= high:
14 | mid = low + (high-low)//2 #Now mid will be ininteger range
15 | #print("lo: ", lo, " hi: ", hi, " mid: ", mid)
16 | if low == high:
17 | break
18 | if array[mid] < query:
19 | low = mid + 1
20 | else:
21 | high = mid
22 | if array[low] == query:
23 | return low
24 |
--------------------------------------------------------------------------------
/algorithms/search/jump_search.py:
--------------------------------------------------------------------------------
1 | """
2 | Jump Search
3 |
4 | Find an element in a sorted array.
5 | """
6 |
7 | import math
8 |
9 | def jump_search(arr,target):
10 | """
11 | Worst-case Complexity: O(√n) (root(n))
12 | All items in list must be sorted like binary search
13 |
14 | Find block that contains target value and search it linearly in that block
15 | It returns a first target value in array
16 |
17 | reference: https://en.wikipedia.org/wiki/Jump_search
18 | """
19 |
20 | length = len(arr)
21 | block_size = int(math.sqrt(length))
22 | block_prev = 0
23 | block= block_size
24 |
25 | # return -1 means that array doesn't contain target value
26 | # find block that contains target value
27 |
28 | if arr[length - 1] < target:
29 | return -1
30 | while block <= length and arr[block - 1] < target:
31 | block_prev = block
32 | block += block_size
33 |
34 | # find target value in block
35 |
36 | while arr[block_prev] < target :
37 | block_prev += 1
38 | if block_prev == min(block, length) :
39 | return -1
40 |
41 | # if there is target value in array, return it
42 |
43 | if arr[block_prev] == target :
44 | return block_prev
45 | return -1
46 |
--------------------------------------------------------------------------------
/algorithms/search/last_occurrence.py:
--------------------------------------------------------------------------------
1 | """
2 | Find last occurance of a number in a sorted array (increasing order)
3 | Approach- Binary Search
4 | T(n)- O(log n)
5 | """
6 | def last_occurrence(array, query):
7 | """
8 | Returns the index of the last occurance of the given element in an array.
9 | The array has to be sorted in increasing order.
10 | """
11 | low, high = 0, len(array) - 1
12 | while low <= high:
13 | mid = (high + low) // 2
14 | if (array[mid] == query and mid == len(array)-1) or \
15 | (array[mid] == query and array[mid+1] > query):
16 | return mid
17 | if array[mid] <= query:
18 | low = mid + 1
19 | else:
20 | high = mid - 1
21 |
--------------------------------------------------------------------------------
/algorithms/search/linear_search.py:
--------------------------------------------------------------------------------
1 | """
2 | Linear search works in any array.
3 | T(n): O(n)
4 | """
5 |
6 | def linear_search(array, query):
7 | """
8 | Find the index of the given element in the array.
9 | There are no restrictions on the order of the elements in the array.
10 | If the element couldn't be found, returns -1.
11 | """
12 | for i, value in enumerate(array):
13 | if value == query:
14 | return i
15 | return -1
16 |
--------------------------------------------------------------------------------
/algorithms/search/search_insert.py:
--------------------------------------------------------------------------------
1 | """
2 | Helper methods for implementing insertion sort.
3 | """
4 |
5 | def search_insert(array, val):
6 | """
7 | Given a sorted array and a target value, return the index if the target is
8 | found. If not, return the index where it would be if it were inserted in order.
9 |
10 | For example:
11 | [1,3,5,6], 5 -> 2
12 | [1,3,5,6], 2 -> 1
13 | [1,3,5,6], 7 -> 4
14 | [1,3,5,6], 0 -> 0
15 | """
16 | low = 0
17 | high = len(array) - 1
18 | while low <= high:
19 | mid = low + (high - low) // 2
20 | if val > array[mid]:
21 | low = mid + 1
22 | else:
23 | high = mid - 1
24 | return low
25 |
--------------------------------------------------------------------------------
/algorithms/search/search_range.py:
--------------------------------------------------------------------------------
1 | """
2 | Given an array of integers nums sorted in ascending order, find the starting
3 | and ending position of a given target value. If the target is not found in the
4 | array, return [-1, -1].
5 |
6 | For example:
7 | Input: nums = [5,7,7,8,8,8,10], target = 8
8 | Output: [3,5]
9 | Input: nums = [5,7,7,8,8,8,10], target = 11
10 | Output: [-1,-1]
11 | """
12 | def search_range(nums, target):
13 | """
14 | :type nums: List[int]
15 | :type target: int
16 | :rtype: List[int]
17 | """
18 | low = 0
19 | high = len(nums) - 1
20 | # breaks at low == high
21 | # both pointing to first occurence of target
22 | while low < high:
23 | mid = low + (high - low) // 2
24 | if target <= nums[mid]:
25 | high = mid
26 | else:
27 | low = mid + 1
28 |
29 | for j in range(len(nums) - 1, -1, -1):
30 | if nums[j] == target:
31 | return [low, j]
32 |
33 | return [-1, -1]
34 |
--------------------------------------------------------------------------------
/algorithms/set/__init__.py:
--------------------------------------------------------------------------------
1 | from .find_keyboard_row import *
2 |
--------------------------------------------------------------------------------
/algorithms/set/find_keyboard_row.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a List of words, return the words that can be typed using letters of
3 | alphabet on only one row's of American keyboard.
4 |
5 | For example:
6 | Input: ["Hello", "Alaska", "Dad", "Peace"]
7 | Output: ["Alaska", "Dad"]
8 |
9 | Reference: https://leetcode.com/problems/keyboard-row/description/
10 | """
11 |
12 | def find_keyboard_row(words):
13 | """
14 | :type words: List[str]
15 | :rtype: List[str]
16 | """
17 | keyboard = [
18 | set('qwertyuiop'),
19 | set('asdfghjkl'),
20 | set('zxcvbnm'),
21 | ]
22 | result = []
23 | for word in words:
24 | for key in keyboard:
25 | if set(word.lower()).issubset(key):
26 | result.append(word)
27 | return result
28 |
--------------------------------------------------------------------------------
/algorithms/sort/__init__.py:
--------------------------------------------------------------------------------
1 | from .bitonic_sort import *
2 | from .bogo_sort import *
3 | from .bubble_sort import *
4 | from .comb_sort import *
5 | from .counting_sort import *
6 | from .cycle_sort import *
7 | from .exchange_sort import *
8 | from .heap_sort import *
9 | from .insertion_sort import *
10 | from .merge_sort import *
11 | from .pancake_sort import *
12 | from .pigeonhole_sort import *
13 | from .quick_sort import *
14 | from .selection_sort import *
15 | from .top_sort import *
16 | from .bucket_sort import *
17 | from .shell_sort import *
18 | from .stooge_sort import *
19 | from .radix_sort import *
20 | from .gnome_sort import *
21 | from .cocktail_shaker_sort import *
22 |
--------------------------------------------------------------------------------
/algorithms/sort/bogo_sort.py:
--------------------------------------------------------------------------------
1 | import random
2 |
3 | def bogo_sort(arr, simulation=False):
4 | """Bogo Sort
5 | Best Case Complexity: O(n)
6 | Worst Case Complexity: O(∞)
7 | Average Case Complexity: O(n(n-1)!)
8 | """
9 |
10 | iteration = 0
11 | if simulation:
12 | print("iteration",iteration,":",*arr)
13 |
14 | def is_sorted(arr):
15 | #check the array is inorder
16 | i = 0
17 | arr_len = len(arr)
18 | while i+1 < arr_len:
19 | if arr[i] > arr[i+1]:
20 | return False
21 | i += 1
22 |
23 |
24 | return True
25 | while not is_sorted(arr):
26 | random.shuffle(arr)
27 |
28 | if simulation:
29 | iteration = iteration + 1
30 | print("iteration",iteration,":",*arr)
31 |
32 | return arr
33 |
--------------------------------------------------------------------------------
/algorithms/sort/bubble_sort.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | https://en.wikipedia.org/wiki/Bubble_sort
4 |
5 | Worst-case performance: O(N^2)
6 |
7 | If you call bubble_sort(arr,True), you can see the process of the sort
8 | Default is simulation = False
9 |
10 | """
11 |
12 |
13 | def bubble_sort(arr, simulation=False):
14 | def swap(i, j):
15 | arr[i], arr[j] = arr[j], arr[i]
16 |
17 | n = len(arr)
18 | swapped = True
19 |
20 | iteration = 0
21 | if simulation:
22 | print("iteration",iteration,":",*arr)
23 | x = -1
24 | while swapped:
25 | swapped = False
26 | x = x + 1
27 | for i in range(1, n-x):
28 | if arr[i - 1] > arr[i]:
29 | swap(i - 1, i)
30 | swapped = True
31 | if simulation:
32 | iteration = iteration + 1
33 | print("iteration",iteration,":",*arr)
34 |
35 | return arr
36 |
--------------------------------------------------------------------------------
/algorithms/sort/bucket_sort.py:
--------------------------------------------------------------------------------
1 | def bucket_sort(arr):
2 | ''' Bucket Sort
3 | Complexity: O(n^2)
4 | The complexity is dominated by nextSort
5 | '''
6 | # The number of buckets and make buckets
7 | num_buckets = len(arr)
8 | buckets = [[] for bucket in range(num_buckets)]
9 | # Assign values into bucket_sort
10 | for value in arr:
11 | index = value * num_buckets // (max(arr) + 1)
12 | buckets[index].append(value)
13 | # Sort
14 | sorted_list = []
15 | for i in range(num_buckets):
16 | sorted_list.extend(next_sort(buckets[i]))
17 | return sorted_list
18 |
19 | def next_sort(arr):
20 | # We will use insertion sort here.
21 | for i in range(1, len(arr)):
22 | j = i - 1
23 | key = arr[i]
24 | while arr[j] > key and j >= 0:
25 | arr[j+1] = arr[j]
26 | j = j - 1
27 | arr[j + 1] = key
28 | return arr
29 |
--------------------------------------------------------------------------------
/algorithms/sort/cocktail_shaker_sort.py:
--------------------------------------------------------------------------------
1 | def cocktail_shaker_sort(arr):
2 | """
3 | Cocktail_shaker_sort
4 | Sorting a given array
5 | mutation of bubble sort
6 |
7 | reference: https://en.wikipedia.org/wiki/Cocktail_shaker_sort
8 |
9 | Worst-case performance: O(N^2)
10 | """
11 |
12 | def swap(i, j):
13 | arr[i], arr[j] = arr[j], arr[i]
14 |
15 | n = len(arr)
16 | swapped = True
17 | while swapped:
18 | swapped = False
19 | for i in range(1, n):
20 | if arr[i - 1] > arr[i]:
21 | swap(i - 1, i)
22 | swapped = True
23 | if swapped == False:
24 | return arr
25 | swapped = False
26 | for i in range(n-1,0,-1):
27 | if arr[i - 1] > arr[i]:
28 | swap(i - 1, i)
29 | swapped = True
30 | return arr
31 |
--------------------------------------------------------------------------------
/algorithms/sort/comb_sort.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | https://en.wikipedia.org/wiki/Comb_sort
4 |
5 | Worst-case performance: O(N^2)
6 |
7 | """
8 |
9 |
10 | def comb_sort(arr):
11 | def swap(i, j):
12 | arr[i], arr[j] = arr[j], arr[i]
13 |
14 | n = len(arr)
15 | gap = n
16 | shrink = 1.3
17 | sorted = False
18 | while not sorted:
19 | gap = int(gap / shrink)
20 | if gap > 1:
21 | sorted = False
22 | else:
23 | gap = 1
24 | sorted = True
25 |
26 | i = 0
27 | while i + gap < n:
28 | if arr[i] > arr[i + gap]:
29 | swap(i, i + gap)
30 | sorted = False
31 | i = i + 1
32 | return arr
33 |
--------------------------------------------------------------------------------
/algorithms/sort/exchange_sort.py:
--------------------------------------------------------------------------------
1 | def exchange_sort(arr):
2 | """
3 | Reference : https://en.wikipedia.org/wiki/Sorting_algorithm#Exchange_sort
4 | Complexity : O(n^2)
5 | """
6 | arr_len = len(arr)
7 | for i in range(arr_len-1):
8 | for j in range(i+1, arr_len):
9 | if(arr[i] > arr[j]):
10 | arr[i], arr[j] = arr[j], arr[i]
11 | return arr
12 |
--------------------------------------------------------------------------------
/algorithms/sort/gnome_sort.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | Gnome Sort
4 | Best case performance is O(n)
5 | Worst case performance is O(n^2)
6 |
7 | """
8 |
9 |
10 | def gnome_sort(arr):
11 | n = len(arr)
12 | index = 0
13 | while index < n:
14 | if index == 0 or arr[index] >= arr[index-1]:
15 | index = index + 1
16 | else:
17 | arr[index], arr[index-1] = arr[index-1], arr[index]
18 | index = index - 1
19 | return arr
20 |
--------------------------------------------------------------------------------
/algorithms/sort/insertion_sort.py:
--------------------------------------------------------------------------------
1 | def insertion_sort(arr, simulation=False):
2 | """ Insertion Sort
3 | Complexity: O(n^2)
4 | """
5 |
6 | iteration = 0
7 | if simulation:
8 | print("iteration",iteration,":",*arr)
9 |
10 | for i in range(len(arr)):
11 | cursor = arr[i]
12 | pos = i
13 |
14 | while pos > 0 and arr[pos - 1] > cursor:
15 | # Swap the number down the list
16 | arr[pos] = arr[pos - 1]
17 | pos = pos - 1
18 | # Break and do the final swap
19 | arr[pos] = cursor
20 |
21 | if simulation:
22 | iteration = iteration + 1
23 | print("iteration",iteration,":",*arr)
24 |
25 | return arr
26 |
--------------------------------------------------------------------------------
/algorithms/sort/meeting_rooms.py:
--------------------------------------------------------------------------------
1 | """
2 | Given an array of meeting time intervals consisting of
3 | start and end times [[s1,e1],[s2,e2],...] (si < ei),
4 | determine if a person could attend all meetings.
5 |
6 | For example,
7 | Given [[0, 30],[5, 10],[15, 20]],
8 | return false.
9 | """
10 |
11 |
12 | def can_attend_meetings(intervals):
13 | """
14 | :type intervals: List[Interval]
15 | :rtype: bool
16 | """
17 | intervals = sorted(intervals, key=lambda x: x.start)
18 | for i in range(1, len(intervals)):
19 | if intervals[i].start < intervals[i - 1].end:
20 | return False
21 | return True
22 |
--------------------------------------------------------------------------------
/algorithms/sort/pancake_sort.py:
--------------------------------------------------------------------------------
1 | def pancake_sort(arr):
2 | """
3 | Pancake_sort
4 | Sorting a given array
5 | mutation of selection sort
6 |
7 | reference: https://www.geeksforgeeks.org/pancake-sorting/
8 |
9 | Overall time complexity : O(N^2)
10 | """
11 |
12 | len_arr = len(arr)
13 | if len_arr <= 1:
14 | return arr
15 | for cur in range(len(arr), 1, -1):
16 | #Finding index of maximum number in arr
17 | index_max = arr.index(max(arr[0:cur]))
18 | if index_max+1 != cur:
19 | #Needs moving
20 | if index_max != 0:
21 | #reverse from 0 to index_max
22 | arr[:index_max+1] = reversed(arr[:index_max+1])
23 | # Reverse list
24 | arr[:cur] = reversed(arr[:cur])
25 | return arr
26 |
--------------------------------------------------------------------------------
/algorithms/sort/pigeonhole_sort.py:
--------------------------------------------------------------------------------
1 | """
2 |
3 | https://en.wikipedia.org/wiki/Pigeonhole_sort
4 |
5 | Time complexity: O(n + Range) where n = number of elements and Range = possible values in the array
6 |
7 | Suitable for lists where the number of elements and key values are mostly the same.
8 |
9 | """
10 |
11 |
12 | def pigeonhole_sort(arr):
13 | Max = max(arr)
14 | Min = min(arr)
15 | size = Max - Min + 1
16 |
17 | holes = [0]*size
18 |
19 | for i in arr:
20 | holes[i-Min] += 1
21 |
22 | i = 0
23 | for count in range(size):
24 | while holes[count] > 0:
25 | holes[count] -= 1
26 | arr[i] = count + Min
27 | i += 1
28 | return arr
29 |
--------------------------------------------------------------------------------
/algorithms/sort/quick_sort.py:
--------------------------------------------------------------------------------
1 | def quick_sort(arr, simulation=False):
2 | """ Quick sort
3 | Complexity: best O(n log(n)) avg O(n log(n)), worst O(N^2)
4 | """
5 |
6 | iteration = 0
7 | if simulation:
8 | print("iteration",iteration,":",*arr)
9 | arr, _ = quick_sort_recur(arr, 0, len(arr) - 1, iteration, simulation)
10 | return arr
11 |
12 | def quick_sort_recur(arr, first, last, iteration, simulation):
13 | if first < last:
14 | pos = partition(arr, first, last)
15 | # Start our two recursive calls
16 | if simulation:
17 | iteration = iteration + 1
18 | print("iteration",iteration,":",*arr)
19 |
20 | _, iteration = quick_sort_recur(arr, first, pos - 1, iteration, simulation)
21 | _, iteration = quick_sort_recur(arr, pos + 1, last, iteration, simulation)
22 |
23 | return arr, iteration
24 |
25 | def partition(arr, first, last):
26 | wall = first
27 | for pos in range(first, last):
28 | if arr[pos] < arr[last]: # last is the pivot
29 | arr[pos], arr[wall] = arr[wall], arr[pos]
30 | wall += 1
31 | arr[wall], arr[last] = arr[last], arr[wall]
32 | return wall
33 |
--------------------------------------------------------------------------------
/algorithms/sort/radix_sort.py:
--------------------------------------------------------------------------------
1 | """
2 | radix sort
3 | complexity: O(nk + n) . n is the size of input list and k is the digit length of the number
4 | """
5 | def radix_sort(arr, simulation=False):
6 | position = 1
7 | max_number = max(arr)
8 |
9 | iteration = 0
10 | if simulation:
11 | print("iteration", iteration, ":", *arr)
12 |
13 | while position <= max_number:
14 | queue_list = [list() for _ in range(10)]
15 |
16 | for num in arr:
17 | digit_number = num // position % 10
18 | queue_list[digit_number].append(num)
19 |
20 | index = 0
21 | for numbers in queue_list:
22 | for num in numbers:
23 | arr[index] = num
24 | index += 1
25 |
26 | if simulation:
27 | iteration = iteration + 1
28 | print("iteration", iteration, ":", *arr)
29 |
30 | position *= 10
31 | return arr
32 |
--------------------------------------------------------------------------------
/algorithms/sort/selection_sort.py:
--------------------------------------------------------------------------------
1 | def selection_sort(arr, simulation=False):
2 | """ Selection Sort
3 | Complexity: O(n^2)
4 | """
5 | iteration = 0
6 | if simulation:
7 | print("iteration",iteration,":",*arr)
8 |
9 | for i in range(len(arr)):
10 | minimum = i
11 |
12 | for j in range(i + 1, len(arr)):
13 | # "Select" the correct value
14 | if arr[j] < arr[minimum]:
15 | minimum = j
16 |
17 | arr[minimum], arr[i] = arr[i], arr[minimum]
18 |
19 | if simulation:
20 | iteration = iteration + 1
21 | print("iteration",iteration,":",*arr)
22 |
23 | return arr
24 |
--------------------------------------------------------------------------------
/algorithms/sort/shell_sort.py:
--------------------------------------------------------------------------------
1 | def shell_sort(arr):
2 | ''' Shell Sort
3 | Complexity: O(n^2)
4 | '''
5 | n = len(arr)
6 | # Initialize size of the gap
7 | gap = n//2
8 |
9 | while gap > 0:
10 | y_index = gap
11 | while y_index < len(arr):
12 | y = arr[y_index]
13 | x_index = y_index - gap
14 | while x_index >= 0 and y < arr[x_index]:
15 | arr[x_index + gap] = arr[x_index]
16 | x_index = x_index - gap
17 | arr[x_index + gap] = y
18 | y_index = y_index + 1
19 | gap = gap//2
20 |
21 | return arr
22 |
--------------------------------------------------------------------------------
/algorithms/sort/sort_colors.py:
--------------------------------------------------------------------------------
1 | """
2 | Given an array with n objects colored red,
3 | white or blue, sort them so that objects of the same color
4 | are adjacent, with the colors in the order red, white and blue.
5 |
6 | Here, we will use the integers 0, 1, and 2 to represent
7 | the color red, white, and blue respectively.
8 |
9 | Note:
10 | You are not suppose to use the library's sort function for this problem.
11 | """
12 |
13 |
14 | def sort_colors(nums):
15 | i = j = 0
16 | for k in range(len(nums)):
17 | v = nums[k]
18 | nums[k] = 2
19 | if v < 2:
20 | nums[j] = 1
21 | j += 1
22 | if v == 0:
23 | nums[i] = 0
24 | i += 1
25 |
26 |
27 | if __name__ == "__main__":
28 | nums = [0, 1, 1, 1, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 2, 2]
29 | sort_colors(nums)
30 | print(nums)
31 |
--------------------------------------------------------------------------------
/algorithms/sort/stooge_sort.py:
--------------------------------------------------------------------------------
1 | '''
2 |
3 | Stooge Sort
4 | Time Complexity : O(n2.709)
5 | Reference: https://www.geeksforgeeks.org/stooge-sort/
6 |
7 | '''
8 |
9 |
10 |
11 | def stoogesort(arr, l, h):
12 | if l >= h:
13 | return
14 |
15 | # If first element is smaller
16 | # than last, swap them
17 | if arr[l]>arr[h]:
18 | t = arr[l]
19 | arr[l] = arr[h]
20 | arr[h] = t
21 |
22 | # If there are more than 2 elements in
23 | # the array
24 | if h-l + 1 > 2:
25 | t = (int)((h-l + 1)/3)
26 |
27 | # Recursively sort first 2 / 3 elements
28 | stoogesort(arr, l, (h-t))
29 |
30 | # Recursively sort last 2 / 3 elements
31 | stoogesort(arr, l + t, (h))
32 |
33 | # Recursively sort first 2 / 3 elements
34 | # again to confirm
35 | stoogesort(arr, l, (h-t))
36 |
37 |
38 | if __name__ == "__main__":
39 | array = [1,3,64,5,7,8]
40 | n = len(array)
41 | stoogesort(array, 0, n-1)
42 | for i in range(0, n):
43 | print(array[i], end = ' ')
44 |
--------------------------------------------------------------------------------
/algorithms/sort/wiggle_sort.py:
--------------------------------------------------------------------------------
1 | """
2 | Given an unsorted array nums, reorder it such that nums[0] < nums[1] > nums[2] < nums[3]....
3 | """
4 | def wiggle_sort(nums):
5 | for i in range(len(nums)):
6 | if (i % 2 == 1) == (nums[i-1] > nums[i]):
7 | nums[i-1], nums[i] = nums[i], nums[i-1]
8 |
9 | if __name__ == "__main__":
10 | array = [3, 5, 2, 1, 6, 4]
11 |
12 | print(array)
13 | wiggle_sort(array)
14 | print(array)
15 |
16 |
17 |
--------------------------------------------------------------------------------
/algorithms/stack/__init__.py:
--------------------------------------------------------------------------------
1 | from .stack import *
2 | from .is_consecutive import *
3 | from .is_sorted import *
4 | from .remove_min import *
5 | from .stutter import *
6 | from .switch_pairs import *
7 | from .valid_parenthesis import *
8 | from .simplify_path import *
9 | from .stack import *
10 | from .ordered_stack import *
11 |
--------------------------------------------------------------------------------
/algorithms/stack/is_sorted.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a stack, a function is_sorted accepts a stack as a parameter and returns
3 | true if the elements in the stack occur in ascending increasing order from
4 | bottom, and false otherwise. That is, the smallest element should be at bottom
5 |
6 | For example:
7 | bottom [6, 3, 5, 1, 2, 4] top
8 | The function should return false
9 | bottom [1, 2, 3, 4, 5, 6] top
10 | The function should return true
11 | """
12 |
13 |
14 | def is_sorted(stack):
15 | storage_stack = []
16 | for i in range(len(stack)):
17 | if len(stack) == 0:
18 | break
19 | first_val = stack.pop()
20 | if len(stack) == 0:
21 | break
22 | second_val = stack.pop()
23 | if first_val < second_val:
24 | return False
25 | storage_stack.append(first_val)
26 | stack.append(second_val)
27 |
28 | # Backup stack
29 | for i in range(len(storage_stack)):
30 | stack.append(storage_stack.pop())
31 |
32 | return True
33 |
--------------------------------------------------------------------------------
/algorithms/stack/ordered_stack.py:
--------------------------------------------------------------------------------
1 | # The stack remains always ordered such that the highest value
2 | # is at the top and the lowest at the bottom
3 |
4 |
5 | class OrderedStack:
6 | def __init__(self):
7 | self.items = []
8 |
9 | def is_empty(self):
10 | return self.items == []
11 |
12 | def push_t(self, item):
13 | self.items.append(item)
14 |
15 | # push method to maintain order when pushing new elements
16 | def push(self, item):
17 | temp_stack = OrderedStack()
18 | if self.is_empty() or item > self.peek():
19 | self.push_t(item)
20 | else:
21 | while item < self.peek() and not self.is_empty():
22 | temp_stack.push_t(self.pop())
23 | self.push_t(item)
24 | while not temp_stack.is_empty():
25 | self.push_t(temp_stack.pop())
26 |
27 | def pop(self):
28 | if self.is_empty():
29 | raise IndexError("Stack is empty")
30 | return self.items.pop()
31 |
32 | def peek(self):
33 | return self.items[len(self.items) - 1]
34 |
35 | def size(self):
36 | return len(self.items)
37 |
--------------------------------------------------------------------------------
/algorithms/stack/remove_min.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a stack, a function remove_min accepts a stack as a parameter
3 | and removes the smallest value from the stack.
4 |
5 | For example:
6 | bottom [2, 8, 3, -6, 7, 3] top
7 | After remove_min(stack):
8 | bottom [2, 8, 3, 7, 3] top
9 |
10 | """
11 |
12 |
13 | def remove_min(stack):
14 | storage_stack = []
15 | if len(stack) == 0: # Stack is empty
16 | return stack
17 | # Find the smallest value
18 | min = stack.pop()
19 | stack.append(min)
20 | for i in range(len(stack)):
21 | val = stack.pop()
22 | if val <= min:
23 | min = val
24 | storage_stack.append(val)
25 | # Back up stack and remove min value
26 | for i in range(len(storage_stack)):
27 | val = storage_stack.pop()
28 | if val != min:
29 | stack.append(val)
30 | return stack
31 |
--------------------------------------------------------------------------------
/algorithms/stack/simplify_path.py:
--------------------------------------------------------------------------------
1 | """
2 | Given an absolute path for a file (Unix-style), simplify it.
3 |
4 | For example,
5 | path = "/home/", => "/home"
6 | path = "/a/./b/../../c/", => "/c"
7 |
8 | * Did you consider the case where path = "/../"?
9 | In this case, you should return "/".
10 | * Another corner case is the path might contain multiple slashes '/' together,
11 | such as "/home//foo/". In this case, you should ignore redundant
12 | slashes and return "/home/foo".
13 | """
14 | def simplify_path(path):
15 | """
16 | :type path: str
17 | :rtype: str
18 | """
19 | skip = {'..', '.', ''}
20 | stack = []
21 | paths = path.split('/')
22 | for tok in paths:
23 | if tok == '..':
24 | if stack:
25 | stack.pop()
26 | elif tok not in skip:
27 | stack.append(tok)
28 | return '/' + '/'.join(stack)
29 |
--------------------------------------------------------------------------------
/algorithms/stack/valid_parenthesis.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a string containing just the characters
3 | '(', ')', '{', '}', '[' and ']',
4 | determine if the input string is valid.
5 |
6 | The brackets must close in the correct order,
7 | "()" and "()[]{}" are all valid but "(]" and "([)]" are not.
8 | """
9 |
10 |
11 | def is_valid(s: str) -> bool:
12 | stack = []
13 | dic = {")": "(",
14 | "}": "{",
15 | "]": "["}
16 | for char in s:
17 | if char in dic.values():
18 | stack.append(char)
19 | elif char in dic:
20 | if not stack or dic[char] != stack.pop():
21 | return False
22 | return not stack
23 |
--------------------------------------------------------------------------------
/algorithms/streaming/__init__.py:
--------------------------------------------------------------------------------
1 | from .one_sparse_recovery import *
2 | from .misra_gries import *
3 |
--------------------------------------------------------------------------------
/algorithms/strings/add_binary.py:
--------------------------------------------------------------------------------
1 | """
2 | Given two binary strings,
3 | return their sum (also a binary string).
4 |
5 | For example,
6 | a = "11"
7 | b = "1"
8 | Return "100".
9 | """
10 |
11 |
12 | def add_binary(a, b):
13 | s = ""
14 | c, i, j = 0, len(a)-1, len(b)-1
15 | zero = ord('0')
16 | while (i >= 0 or j >= 0 or c == 1):
17 | if (i >= 0):
18 | c += ord(a[i]) - zero
19 | i -= 1
20 | if (j >= 0):
21 | c += ord(b[j]) - zero
22 | j -= 1
23 | s = chr(c % 2 + zero) + s
24 | c //= 2
25 |
26 | return s
27 |
--------------------------------------------------------------------------------
/algorithms/strings/atbash_cipher.py:
--------------------------------------------------------------------------------
1 | """
2 | Atbash cipher is mapping the alphabet to it's reverse.
3 | So if we take "a" as it is the first letter, we change it to the last - z.
4 |
5 | Example:
6 | Attack at dawn --> Zggzxp zg wzdm
7 |
8 | Complexity: O(n)
9 | """
10 |
11 | def atbash(s):
12 | translated = ""
13 | for i in range(len(s)):
14 | n = ord(s[i])
15 |
16 | if s[i].isalpha():
17 |
18 | if s[i].isupper():
19 | x = n - ord('A')
20 | translated += chr(ord('Z') - x)
21 |
22 | if s[i].islower():
23 | x = n - ord('a')
24 | translated += chr(ord('z') - x)
25 | else:
26 | translated += s[i]
27 | return translated
--------------------------------------------------------------------------------
/algorithms/strings/caesar_cipher.py:
--------------------------------------------------------------------------------
1 |
2 | """
3 | Julius Caesar protected his confidential information by encrypting it using a cipher.
4 | Caesar's cipher shifts each letter by a number of letters. If the shift takes you
5 | past the end of the alphabet, just rotate back to the front of the alphabet.
6 | In the case of a rotation by 3, w, x, y and z would map to z, a, b and c.
7 | Original alphabet: abcdefghijklmnopqrstuvwxyz
8 | Alphabet rotated +3: defghijklmnopqrstuvwxyzabc
9 | """
10 | def caesar_cipher(s, k):
11 | result = ""
12 | for char in s:
13 | n = ord(char)
14 | if 64 < n < 91:
15 | n = ((n - 65 + k) % 26) + 65
16 | if 96 < n < 123:
17 | n = ((n - 97 + k) % 26) + 97
18 | result = result + chr(n)
19 | return result
20 |
--------------------------------------------------------------------------------
/algorithms/strings/check_pangram.py:
--------------------------------------------------------------------------------
1 | """
2 | Algorithm that checks if a given string is a pangram or not
3 | """
4 |
5 | def check_pangram(input_string):
6 | alphabet = "abcdefghijklmnopqrstuvwxyz"
7 | for ch in alphabet:
8 | if ch not in input_string.lower():
9 | return False
10 | return True
--------------------------------------------------------------------------------
/algorithms/strings/contain_string.py:
--------------------------------------------------------------------------------
1 | """
2 | Implement strStr().
3 |
4 | Return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.
5 |
6 | Example 1:
7 | Input: haystack = "hello", needle = "ll"
8 | Output: 2
9 |
10 | Example 2:
11 | Input: haystack = "aaaaa", needle = "bba"
12 | Output: -1
13 | Reference: https://leetcode.com/problems/implement-strstr/description/
14 | """
15 | def contain_string(haystack, needle):
16 | if len(needle) == 0:
17 | return 0
18 | if len(needle) > len(haystack):
19 | return -1
20 | for i in range(len(haystack)):
21 | if len(haystack) - i < len(needle):
22 | return -1
23 | if haystack[i:i+len(needle)] == needle:
24 | return i
25 | return -1
26 |
--------------------------------------------------------------------------------
/algorithms/strings/count_binary_substring.py:
--------------------------------------------------------------------------------
1 | """
2 | Give a string s, count the number of non-empty (contiguous) substrings that have
3 | the same number of 0's and 1's, and all the 0's and all the 1's in these substrings are grouped consecutively.
4 |
5 | Substrings that occur multiple times are counted the number of times they occur.
6 | Example 1:
7 | Input: "00110011"
8 | Output: 6
9 | Explanation: There are 6 substrings that have equal number of consecutive 1's and 0's: "0011", "01", "1100", "10", "0011", and "01".
10 |
11 | Notice that some of these substrings repeat and are counted the number of times they occur.
12 |
13 | Also, "00110011" is not a valid substring because all the 0's (and 1's) are not grouped together.
14 |
15 | Example 2:
16 | Input: "10101"
17 | Output: 4
18 | Explanation: There are 4 substrings: "10", "01", "10", "01" that have equal number of consecutive 1's and 0's.
19 | Reference: https://leetcode.com/problems/count-binary-substrings/description/
20 | """
21 | def count_binary_substring(s):
22 | cur = 1
23 | pre = 0
24 | count = 0
25 | for i in range(1, len(s)):
26 | if s[i] != s[i - 1]:
27 | count = count + min(pre, cur)
28 | pre = cur
29 | cur = 1
30 | else:
31 | cur = cur + 1
32 | count = count + min(pre, cur)
33 | return count
34 |
--------------------------------------------------------------------------------
/algorithms/strings/delete_reoccurring.py:
--------------------------------------------------------------------------------
1 | """
2 | QUESTION: Given a string as your input, delete any reoccurring
3 | character, and return the new string.
4 |
5 | This is a Google warmup interview question that was asked duirng phone screening
6 | at my university.
7 | """
8 |
9 | # time complexity O(n)
10 | def delete_reoccurring_characters(string):
11 | seen_characters = set()
12 | output_string = ''
13 | for char in string:
14 | if char not in seen_characters:
15 | seen_characters.add(char)
16 | output_string += char
17 | return output_string
18 |
19 |
--------------------------------------------------------------------------------
/algorithms/strings/domain_extractor.py:
--------------------------------------------------------------------------------
1 | """
2 | Write a function that when given a URL as a string, parses out just the domain name and returns it as a string.
3 |
4 | Examples:
5 | domain_name("http://github.com/SaadBenn") == "github"
6 | domain_name("http://www.zombie-bites.com") == "zombie-bites"
7 | domain_name("https://www.cnet.com") == "cnet"
8 |
9 | Note: The idea is not to use any built-in libraries such as re (regular expression) or urlparse except .split() built-in function
10 | """
11 |
12 | # Non pythonic way
13 | def domain_name_1(url):
14 | #grab only the non http(s) part
15 | full_domain_name = url.split('//')[-1]
16 | #grab the actual one depending on the len of the list
17 | actual_domain = full_domain_name.split('.')
18 |
19 | # case when www is in the url
20 | if (len(actual_domain) > 2):
21 | return actual_domain[1]
22 | # case when www is not in the url
23 | return actual_domain[0]
24 |
25 |
26 | # pythonic one liner
27 | def domain_name_2(url):
28 | return url.split("//")[-1].split("www.")[-1].split(".")[0]
29 |
30 |
--------------------------------------------------------------------------------
/algorithms/strings/encode_decode.py:
--------------------------------------------------------------------------------
1 | """ Design an algorithm to encode a list of strings to a string.
2 | The encoded mystring is then sent over the network and is decoded
3 | back to the original list of strings.
4 | """
5 |
6 | # Implement the encode and decode methods.
7 |
8 | def encode(strs):
9 | """Encodes a list of strings to a single string.
10 | :type strs: List[str]
11 | :rtype: str
12 | """
13 | res = ''
14 | for string in strs.split():
15 | res += str(len(string)) + ":" + string
16 | return res
17 |
18 | def decode(s):
19 | """Decodes a single string to a list of strings.
20 | :type s: str
21 | :rtype: List[str]
22 | """
23 | strs = []
24 | i = 0
25 | while i < len(s):
26 | index = s.find(":", i)
27 | size = int(s[i:index])
28 | strs.append(s[index+1: index+1+size])
29 | i = index+1+size
30 | return strs
--------------------------------------------------------------------------------
/algorithms/strings/first_unique_char.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a string, find the first non-repeating character in it and return it's
3 | index. If it doesn't exist, return -1.
4 |
5 | For example:
6 | s = "leetcode"
7 | return 0.
8 |
9 | s = "loveleetcode",
10 | return 2.
11 |
12 | Reference: https://leetcode.com/problems/first-unique-character-in-a-string/description/
13 | """
14 | def first_unique_char(s):
15 | """
16 | :type s: str
17 | :rtype: int
18 | """
19 | if (len(s) == 1):
20 | return 0
21 | ban = []
22 | for i in range(len(s)):
23 | if all(s[i] != s[k] for k in range(i + 1, len(s))) == True and s[i] not in ban:
24 | return i
25 | else:
26 | ban.append(s[i])
27 | return -1
28 |
--------------------------------------------------------------------------------
/algorithms/strings/group_anagrams.py:
--------------------------------------------------------------------------------
1 | """
2 | Given an array of strings, group anagrams together.
3 |
4 | For example, given: ["eat", "tea", "tan", "ate", "nat", "bat"],
5 | Return:
6 |
7 | [
8 | ["ate", "eat","tea"],
9 | ["nat","tan"],
10 | ["bat"]
11 | ]
12 | """
13 |
14 |
15 | def group_anagrams(strs):
16 | d = {}
17 | ans = []
18 | k = 0
19 | for str in strs:
20 | sstr = ''.join(sorted(str))
21 | if sstr not in d:
22 | d[sstr] = k
23 | k += 1
24 | ans.append([])
25 | ans[-1].append(str)
26 | else:
27 | ans[d[sstr]].append(str)
28 | return ans
29 |
--------------------------------------------------------------------------------
/algorithms/strings/int_to_roman.py:
--------------------------------------------------------------------------------
1 | """
2 | Given an integer, convert it to a roman numeral.
3 | Input is guaranteed to be within the range from 1 to 3999.
4 | """
5 |
6 | def int_to_roman(num):
7 | """
8 | :type num: int
9 | :rtype: str
10 | """
11 | m = ["", "M", "MM", "MMM"];
12 | c = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"];
13 | x = ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"];
14 | i = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"];
15 | return m[num//1000] + c[(num%1000)//100] + x[(num%100)//10] + i[num%10];
16 |
--------------------------------------------------------------------------------
/algorithms/strings/is_rotated.py:
--------------------------------------------------------------------------------
1 | """
2 | Given two strings s1 and s2, determine if s2 is a rotated version of s1.
3 | For example,
4 | is_rotated("hello", "llohe") returns True
5 | is_rotated("hello", "helol") returns False
6 |
7 | accepts two strings
8 | returns bool
9 | Reference: https://leetcode.com/problems/rotate-string/description/
10 | """
11 |
12 | def is_rotated(s1, s2):
13 | if len(s1) == len(s2):
14 | return s2 in s1 + s1
15 | else:
16 | return False
17 |
18 | """
19 | Another solution: brutal force
20 | Complexity: O(N^2)
21 | """
22 | def is_rotated_v1(s1, s2):
23 | if len(s1) != len(s2):
24 | return False
25 | if len(s1) == 0:
26 | return True
27 |
28 | for c in range(len(s1)):
29 | if all(s1[(c + i) % len(s1)] == s2[i] for i in range(len(s1))):
30 | return True
31 | return False
32 |
--------------------------------------------------------------------------------
/algorithms/strings/judge_circle.py:
--------------------------------------------------------------------------------
1 | """
2 | Initially, there is a Robot at position (0, 0). Given a sequence of its moves,
3 | judge if this robot makes a circle, which means it moves back to the original place.
4 |
5 | The move sequence is represented by a string. And each move is represent by a
6 | character. The valid robot moves are R (Right), L (Left), U (Up) and D (down).
7 | The output should be true or false representing whether the robot makes a circle.
8 |
9 | Example 1:
10 | Input: "UD"
11 | Output: true
12 | Example 2:
13 | Input: "LL"
14 | Output: false
15 | """
16 | def judge_circle(moves):
17 | dict_moves = {
18 | 'U' : 0,
19 | 'D' : 0,
20 | 'R' : 0,
21 | 'L' : 0
22 | }
23 | for char in moves:
24 | dict_moves[char] = dict_moves[char] + 1
25 | return dict_moves['L'] == dict_moves['R'] and dict_moves['U'] == dict_moves['D']
26 |
--------------------------------------------------------------------------------
/algorithms/strings/license_number.py:
--------------------------------------------------------------------------------
1 |
2 | def license_number(key, k):
3 | res, alnum = [], []
4 | for char in key:
5 | if char != "-":
6 | alnum.append(char)
7 | for i, char in enumerate(reversed(alnum)):
8 | res.append(char)
9 | if (i+1) % k == 0 and i != len(alnum)-1:
10 | res.append("-")
11 | return "".join(res[::-1])
12 |
--------------------------------------------------------------------------------
/algorithms/strings/longest_palindromic_substring.py:
--------------------------------------------------------------------------------
1 | '''
2 | Given string s, find the longest palindromic substring.
3 |
4 | Example1:
5 |
6 | * input: "dasdasdasdasdasdadsa"
7 | * output: "asdadsa"
8 |
9 | Example2:
10 |
11 | * input: "acdbbdaa"
12 | * output: "dbbd"
13 |
14 | Manacher's algorithm
15 |
16 | '''
17 |
18 | def longest_palindrome(s):
19 | if len(s) < 2:
20 | return s
21 |
22 | n_str = '#' + '#'.join(s) + '#'
23 | p = [0] * len(n_str)
24 | mx, loc = 0, 0
25 | index, maxlen = 0, 0
26 | for i in range(len(n_str)):
27 | if i < mx and 2 * loc - i < len(n_str):
28 | p[i] = min(mx - i, p[2 * loc - i])
29 | else:
30 | p[i] = 1
31 |
32 | while p[i] + i < len(n_str) and i - p[i] >= 0 and n_str[
33 | i - p[i]] == n_str[i + p[i]]:
34 | p[i] += 1
35 |
36 | if i + p[i] > mx:
37 | mx = i + p[i]
38 | loc = i
39 |
40 | if p[i] > maxlen:
41 | index = i
42 | maxlen = p[i]
43 | s = n_str[index - p[index] + 1:index + p[index]]
44 | return s.replace('#', '')
45 |
--------------------------------------------------------------------------------
/algorithms/strings/make_sentence.py:
--------------------------------------------------------------------------------
1 | """
2 | For a given string and dictionary, how many sentences can you make from the
3 | string, such that all the words are contained in the dictionary.
4 |
5 | eg: for given string -> "appletablet"
6 | "apple", "tablet"
7 | "applet", "able", "t"
8 | "apple", "table", "t"
9 | "app", "let", "able", "t"
10 |
11 | "applet", {app, let, apple, t, applet} => 3
12 | "thing", {"thing"} -> 1
13 | """
14 |
15 | count = 0
16 |
17 |
18 | def make_sentence(str_piece, dictionaries):
19 | global count
20 | if len(str_piece) == 0:
21 | return True
22 | for i in range(0, len(str_piece)):
23 | prefix, suffix = str_piece[0:i], str_piece[i:]
24 | if prefix in dictionaries:
25 | if suffix in dictionaries or make_sentence(suffix, dictionaries):
26 | count += 1
27 | return True
28 |
--------------------------------------------------------------------------------
/algorithms/strings/multiply_strings.py:
--------------------------------------------------------------------------------
1 | """
2 | Given two non-negative integers num1 and num2 represented as strings,
3 | return the product of num1 and num2.
4 |
5 | Note:
6 |
7 | The length of both num1 and num2 is < 110.
8 | Both num1 and num2 contains only digits 0-9.
9 | Both num1 and num2 does not contain any leading zero.
10 | You must not use any built-in BigInteger library or convert
11 | the inputs to integer directly.
12 | """
13 |
14 |
15 | def multiply(num1: "str", num2: "str") -> "str":
16 | interm = []
17 | zero = ord('0')
18 | i_pos = 1
19 | for i in reversed(num1):
20 | j_pos = 1
21 | add = 0
22 | for j in reversed(num2):
23 | mult = (ord(i)-zero) * (ord(j)-zero) * j_pos * i_pos
24 | j_pos *= 10
25 | add += mult
26 | i_pos *= 10
27 | interm.append(add)
28 | return str(sum(interm))
29 |
30 |
31 | if __name__ == "__main__":
32 | print(multiply("1", "23"))
33 | print(multiply("23", "23"))
34 | print(multiply("100", "23"))
35 | print(multiply("100", "10000"))
36 |
--------------------------------------------------------------------------------
/algorithms/strings/one_edit_distance.py:
--------------------------------------------------------------------------------
1 | """
2 | Given two strings S and T, determine if they are both one edit distance apart.
3 | """
4 |
5 |
6 | def is_one_edit(s, t):
7 | """
8 | :type s: str
9 | :type t: str
10 | :rtype: bool
11 | """
12 | if len(s) > len(t):
13 | return is_one_edit(t, s)
14 | if len(t) - len(s) > 1 or t == s:
15 | return False
16 | for i in range(len(s)):
17 | if s[i] != t[i]:
18 | return s[i+1:] == t[i+1:] or s[i:] == t[i+1:]
19 | return True
20 |
21 |
22 | def is_one_edit2(s, t):
23 | l1, l2 = len(s), len(t)
24 | if l1 > l2:
25 | return is_one_edit2(t, s)
26 | if len(t) - len(s) > 1 or t == s:
27 | return False
28 | for i in range(len(s)):
29 | if s[i] != t[i]:
30 | if l1 == l2:
31 | s = s[:i]+t[i]+s[i+1:] # modify
32 | else:
33 | s = s[:i]+t[i]+s[i:] # insertion
34 | break
35 | return s == t or s == t[:-1]
36 |
--------------------------------------------------------------------------------
/algorithms/strings/panagram.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a string, check whether it is a panagram or not.
3 |
4 | A panagram is a sentence that uses every letter at least once.
5 |
6 | The most famous example is: "he quick brown fox jumps over the lazy dog.
7 |
8 | Note:
9 | A panagram in one language isn't necessarily a panagram in another. This
10 | module assumes the english language. Hence, the Finnish panagram
11 | 'Törkylempijävongahdus' won't pass for a panagram despite being considered
12 | a perfect panagram in its language. However, the Swedish panagram
13 | 'Yxmördaren Julia Blomqvist på fäktning i Schweiz' will pass despite
14 | including letters not used in the english alphabet. This is because the
15 | Swedish alphabet only extends the Latin one.
16 | """
17 |
18 | from string import ascii_lowercase
19 |
20 | def panagram(string):
21 | """
22 | Returns whether the input string is an English panagram or not.
23 |
24 | Parameters:
25 | string (str): A sentence in the form of a string.
26 |
27 | Returns:
28 | A boolean with the result.
29 | """
30 | letters = set(ascii_lowercase)
31 | for c in string:
32 | try:
33 | letters.remove(c.lower())
34 | except:
35 | pass
36 | return len(letters) == 0
--------------------------------------------------------------------------------
/algorithms/strings/repeat_string.py:
--------------------------------------------------------------------------------
1 | """
2 | Given two strings A and B, find the minimum number of times A has to be repeated such that B is a substring of it. If no such solution, return -1.
3 |
4 | For example, with A = "abcd" and B = "cdabcdab".
5 |
6 | Return 3, because by repeating A three times (“abcdabcdabcd”), B is a substring of it; and B is not a substring of A repeated two times ("abcdabcd").
7 |
8 | Note:
9 | The length of A and B will be between 1 and 10000.
10 |
11 | Reference: https://leetcode.com/problems/repeated-string-match/description/
12 | """
13 | def repeat_string(A, B):
14 | count = 1
15 | tmp = A
16 | max_count = (len(B) / len(A)) + 1
17 | while not(B in tmp):
18 | tmp = tmp + A
19 | if (count > max_count):
20 | count = -1
21 | break
22 | count = count + 1
23 |
24 | return count
25 |
--------------------------------------------------------------------------------
/algorithms/strings/repeat_substring.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a non-empty string check if it can be constructed by taking
3 | a substring of it and appending multiple copies of the substring together.
4 |
5 | For example:
6 | Input: "abab"
7 | Output: True
8 | Explanation: It's the substring "ab" twice.
9 |
10 | Input: "aba"
11 | Output: False
12 |
13 | Input: "abcabcabcabc"
14 | Output: True
15 | Explanation: It's the substring "abc" four times.
16 |
17 | Reference: https://leetcode.com/problems/repeated-substring-pattern/description/
18 | """
19 | def repeat_substring(s):
20 | """
21 | :type s: str
22 | :rtype: bool
23 | """
24 | str = (s + s)[1:-1]
25 | return s in str
26 |
--------------------------------------------------------------------------------
/algorithms/strings/reverse_string.py:
--------------------------------------------------------------------------------
1 | def recursive(s):
2 | l = len(s)
3 | if l < 2:
4 | return s
5 | return recursive(s[l//2:]) + recursive(s[:l//2])
6 |
7 | def iterative(s):
8 | r = list(s)
9 | i, j = 0, len(s) - 1
10 | while i < j:
11 | r[i], r[j] = r[j], r[i]
12 | i += 1
13 | j -= 1
14 | return "".join(r)
15 |
16 | def pythonic(s):
17 | r = list(reversed(s))
18 | return "".join(r)
19 |
20 | def ultra_pythonic(s):
21 | return s[::-1]
22 |
--------------------------------------------------------------------------------
/algorithms/strings/reverse_vowel.py:
--------------------------------------------------------------------------------
1 |
2 | def reverse_vowel(s):
3 | vowels = "AEIOUaeiou"
4 | i, j = 0, len(s)-1
5 | s = list(s)
6 | while i < j:
7 | while i < j and s[i] not in vowels:
8 | i += 1
9 | while i < j and s[j] not in vowels:
10 | j -= 1
11 | s[i], s[j] = s[j], s[i]
12 | i, j = i + 1, j - 1
13 | return "".join(s)
14 |
--------------------------------------------------------------------------------
/algorithms/strings/reverse_words.py:
--------------------------------------------------------------------------------
1 |
2 | def reverse(array, i, j):
3 | while i < j:
4 | array[i], array[j] = array[j], array[i]
5 | i += 1
6 | j -= 1
7 |
8 |
9 | def reverse_words(string):
10 | arr = string.strip().split() # arr is list of words
11 | n = len(arr)
12 | reverse(arr, 0, n-1)
13 |
14 | return " ".join(arr)
15 |
16 |
17 | if __name__ == "__main__":
18 | test = "I am keon kim and I like pizza"
19 | print(test)
20 | print(reverse_words(test))
21 |
--------------------------------------------------------------------------------
/algorithms/strings/roman_to_int.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a roman numeral, convert it to an integer.
3 | Input is guaranteed to be within the range from 1 to 3999.
4 | """
5 |
6 |
7 | def roman_to_int(s:"str")->"int":
8 | number = 0
9 | roman = {'M':1000, 'D':500, 'C': 100, 'L':50, 'X':10, 'V':5, 'I':1}
10 | for i in range(len(s)-1):
11 | if roman[s[i]] < roman[s[i+1]]:
12 | number -= roman[s[i]]
13 | else:
14 | number += roman[s[i]]
15 | return number + roman[s[-1]]
16 |
17 |
18 | if __name__ == "__main__":
19 | roman = "DCXXI"
20 | print(roman_to_int(roman))
21 |
--------------------------------------------------------------------------------
/algorithms/strings/rotate.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a strings s and int k, return a string that rotates k times
3 |
4 | k can be any positive integer.
5 |
6 | For example,
7 | rotate("hello", 2) return "llohe"
8 | rotate("hello", 5) return "hello"
9 | rotate("hello", 6) return "elloh"
10 | rotate("hello", 7) return "llohe"
11 | rotate("hello", 102) return "lohel"
12 |
13 | """
14 | def rotate(s, k):
15 | long_string = s * (k // len(s) + 2)
16 | if k <= len(s):
17 | return long_string[k:k + len(s)]
18 | else:
19 | return long_string[k-len(s):k]
20 |
21 | def rotate_alt(string, k):
22 | k = k % len(string)
23 | return string[k:] + string[:k]
24 |
--------------------------------------------------------------------------------
/algorithms/tree/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/cad4754bc71742c2d6fcbd3b92ae74834d359844/algorithms/tree/__init__.py
--------------------------------------------------------------------------------
/algorithms/tree/avl/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/cad4754bc71742c2d6fcbd3b92ae74834d359844/algorithms/tree/avl/__init__.py
--------------------------------------------------------------------------------
/algorithms/tree/bin_tree_to_list.py:
--------------------------------------------------------------------------------
1 | from tree.tree import TreeNode
2 |
3 |
4 | def bin_tree_to_list(root):
5 | """
6 | type root: root class
7 | """
8 | if not root:
9 | return root
10 | root = bin_tree_to_list_util(root)
11 | while root.left:
12 | root = root.left
13 | return root
14 |
15 |
16 | def bin_tree_to_list_util(root):
17 | if not root:
18 | return root
19 | if root.left:
20 | left = bin_tree_to_list_util(root.left)
21 | while left.right:
22 | left = left.right
23 | left.right = root
24 | root.left = left
25 | if root.right:
26 | right = bin_tree_to_list_util(root.right)
27 | while right.left:
28 | right = right.left
29 | right.left = root
30 | root.right = right
31 | return root
32 |
33 |
34 | def print_tree(root):
35 | while root:
36 | print(root.val)
37 | root = root.right
38 |
--------------------------------------------------------------------------------
/algorithms/tree/binary_tree_paths.py:
--------------------------------------------------------------------------------
1 | def binary_tree_paths(root):
2 | res = []
3 | if root is None:
4 | return res
5 | dfs(res, root, str(root.val))
6 | return res
7 |
8 |
9 | def dfs(res, root, cur):
10 | if root.left is None and root.right is None:
11 | res.append(cur)
12 | if root.left:
13 | dfs(res, root.left, cur+'->'+str(root.left.val))
14 | if root.right:
15 | dfs(res, root.right, cur+'->'+str(root.right.val))
16 |
--------------------------------------------------------------------------------
/algorithms/tree/bst/BSTIterator.py:
--------------------------------------------------------------------------------
1 |
2 | class BSTIterator:
3 | def __init__(self, root):
4 | self.stack = []
5 | while root:
6 | self.stack.append(root)
7 | root = root.left
8 |
9 | def has_next(self):
10 | return bool(self.stack)
11 |
12 | def next(self):
13 | node = self.stack.pop()
14 | tmp = node
15 | if tmp.right:
16 | tmp = tmp.right
17 | while tmp:
18 | self.stack.append(tmp)
19 | tmp = tmp.left
20 | return node.val
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/algorithms/tree/bst/array_to_bst.py:
--------------------------------------------------------------------------------
1 | """
2 | Given an array where elements are sorted in ascending order,
3 | convert it to a height balanced BST.
4 | """
5 |
6 |
7 | class TreeNode(object):
8 | def __init__(self, x):
9 | self.val = x
10 | self.left = None
11 | self.right = None
12 |
13 |
14 | def array_to_bst(nums):
15 | if not nums:
16 | return None
17 | mid = len(nums)//2
18 | node = TreeNode(nums[mid])
19 | node.left = array_to_bst(nums[:mid])
20 | node.right = array_to_bst(nums[mid+1:])
21 | return node
22 |
--------------------------------------------------------------------------------
/algorithms/tree/bst/bst_closest_value.py:
--------------------------------------------------------------------------------
1 | # Given a non-empty binary search tree and a target value,
2 | # find the value in the BST that is closest to the target.
3 |
4 | # Note:
5 | # Given target value is a floating point.
6 | # You are guaranteed to have only one unique value in the BST
7 | # that is closest to the target.
8 |
9 |
10 | # Definition for a binary tree node.
11 | # class TreeNode(object):
12 | # def __init__(self, x):
13 | # self.val = x
14 | # self.left = None
15 | # self.right = None
16 |
17 | def closest_value(root, target):
18 | """
19 | :type root: TreeNode
20 | :type target: float
21 | :rtype: int
22 | """
23 | a = root.val
24 | kid = root.left if target < a else root.right
25 | if not kid:
26 | return a
27 | b = closest_value(kid, target)
28 | return min((a,b), key=lambda x: abs(target-x))
29 |
--------------------------------------------------------------------------------
/algorithms/tree/bst/is_bst.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a binary tree, determine if it is a valid binary search tree (BST).
3 |
4 | Assume a BST is defined as follows:
5 |
6 | The left subtree of a node contains only nodes
7 | with keys less than the node's key.
8 | The right subtree of a node contains only nodes
9 | with keys greater than the node's key.
10 | Both the left and right subtrees must also be binary search trees.
11 | Example 1:
12 | 2
13 | / \
14 | 1 3
15 | Binary tree [2,1,3], return true.
16 | Example 2:
17 | 1
18 | / \
19 | 2 3
20 | Binary tree [1,2,3], return false.
21 | """
22 |
23 | def is_bst(root):
24 | """
25 | :type root: TreeNode
26 | :rtype: bool
27 | """
28 |
29 | stack = []
30 | pre = None
31 |
32 | while root or stack:
33 | while root:
34 | stack.append(root)
35 | root = root.left
36 | root = stack.pop()
37 | if pre and root.val <= pre.val:
38 | return False
39 | pre = root
40 | root = root.right
41 |
42 | return True
43 |
--------------------------------------------------------------------------------
/algorithms/tree/bst/lowest_common_ancestor.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a binary search tree (BST),
3 | find the lowest common ancestor (LCA) of two given nodes in the BST.
4 |
5 | According to the definition of LCA on Wikipedia:
6 | “The lowest common ancestor is defined between two
7 | nodes v and w as the lowest node in T that has both v and w
8 | as descendants (where we allow a node to be a descendant of itself).”
9 |
10 | _______6______
11 | / \
12 | ___2__ ___8__
13 | / \ / \
14 | 0 _4 7 9
15 | / \
16 | 3 5
17 |
18 | For example, the lowest common ancestor (LCA) of nodes 2 and 8 is 6.
19 | Another example is LCA of nodes 2 and 4 is 2,
20 | since a node can be a descendant of itself according to the LCA definition.
21 | """
22 |
23 |
24 | def lowest_common_ancestor(root, p, q):
25 | """
26 | :type root: Node
27 | :type p: Node
28 | :type q: Node
29 | :rtype: Node
30 | """
31 | while root:
32 | if p.val > root.val < q.val:
33 | root = root.right
34 | elif p.val < root.val > q.val:
35 | root = root.left
36 | else:
37 | return root
38 |
--------------------------------------------------------------------------------
/algorithms/tree/bst/predecessor.py:
--------------------------------------------------------------------------------
1 | def predecessor(root, node):
2 | pred = None
3 | while root:
4 | if node.val > root.val:
5 | pred = root
6 | root = root.right
7 | else:
8 | root = root.left
9 | return pred
10 |
--------------------------------------------------------------------------------
/algorithms/tree/bst/serialize_deserialize.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | class TreeNode(object):
4 | def __init__(self, x):
5 | self.val = x
6 | self.left = None
7 | self.right = None
8 |
9 |
10 | def serialize(root):
11 | def build_string(node):
12 | if node:
13 | vals.append(str(node.val))
14 | build_string(node.left)
15 | build_string(node.right)
16 | else:
17 | vals.append("#")
18 | vals = []
19 | build_string(root)
20 | return " ".join(vals)
21 |
22 |
23 | def deserialize(data):
24 | def build_tree():
25 | val = next(vals)
26 | if val == "#":
27 | return None
28 | node = TreeNode(int(val))
29 | node.left = build_tree()
30 | node.right = build_tree()
31 | return node
32 | vals = iter(data.split())
33 | return build_tree()
34 |
--------------------------------------------------------------------------------
/algorithms/tree/bst/successor.py:
--------------------------------------------------------------------------------
1 | def successor(root, node):
2 | succ = None
3 | while root:
4 | if node.val < root.val:
5 | succ = root
6 | root = root.left
7 | else:
8 | root = root.right
9 | return succ
10 |
--------------------------------------------------------------------------------
/algorithms/tree/bst/unique_bst.py:
--------------------------------------------------------------------------------
1 | """
2 | Given n, how many structurally unique BST's
3 | (binary search trees) that store values 1...n?
4 |
5 | For example,
6 | Given n = 3, there are a total of 5 unique BST's.
7 |
8 | 1 3 3 2 1
9 | \ / / / \ \
10 | 3 2 1 1 3 2
11 | / / \ \
12 | 2 1 2 3
13 | """
14 |
15 |
16 | """
17 | Taking 1~n as root respectively:
18 | 1 as root: # of trees = F(0) * F(n-1) // F(0) == 1
19 | 2 as root: # of trees = F(1) * F(n-2)
20 | 3 as root: # of trees = F(2) * F(n-3)
21 | ...
22 | n-1 as root: # of trees = F(n-2) * F(1)
23 | n as root: # of trees = F(n-1) * F(0)
24 |
25 | So, the formulation is:
26 | F(n) = F(0) * F(n-1) + F(1) * F(n-2) + F(2) * F(n-3) + ... + F(n-2) * F(1) + F(n-1) * F(0)
27 | """
28 |
29 | def num_trees(n):
30 | """
31 | :type n: int
32 | :rtype: int
33 | """
34 | dp = [0] * (n+1)
35 | dp[0] = 1
36 | dp[1] = 1
37 | for i in range(2, n+1):
38 | for j in range(i+1):
39 | dp[i] += dp[i-j] * dp[j-1]
40 | return dp[-1]
41 |
--------------------------------------------------------------------------------
/algorithms/tree/deepest_left.py:
--------------------------------------------------------------------------------
1 | # Given a binary tree, find the deepest node
2 | # that is the left child of its parent node.
3 |
4 | # Example:
5 |
6 | # 1
7 | # / \
8 | # 2 3
9 | # / \ \
10 | # 4 5 6
11 | # \
12 | # 7
13 | # should return 4.
14 |
15 | from tree.tree import TreeNode
16 |
17 |
18 | class DeepestLeft:
19 | def __init__(self):
20 | self.depth = 0
21 | self.Node = None
22 |
23 |
24 | def find_deepest_left(root, is_left, depth, res):
25 | if not root:
26 | return
27 | if is_left and depth > res.depth:
28 | res.depth = depth
29 | res.Node = root
30 | find_deepest_left(root.left, True, depth + 1, res)
31 | find_deepest_left(root.right, False, depth + 1, res)
32 |
33 |
34 | if __name__ == '__main__':
35 | root = TreeNode(1)
36 | root.left = TreeNode(2)
37 | root.right = TreeNode(3)
38 | root.left.left = TreeNode(4)
39 | root.left.right = TreeNode(5)
40 | root.right.right = TreeNode(6)
41 | root.right.right.right = TreeNode(7)
42 |
43 | res = DeepestLeft()
44 | find_deepest_left(root, True, 1, res)
45 | if res.Node:
46 | print(res.Node.val)
47 |
--------------------------------------------------------------------------------
/algorithms/tree/invert_tree.py:
--------------------------------------------------------------------------------
1 | # invert a binary tree
2 |
3 | def reverse(root):
4 | if root is None:
5 | return
6 | root.left, root.right = root.right, root.left
7 | if root.left:
8 | reverse(root.left)
9 | if root.right:
10 | reverse(root.right)
11 |
--------------------------------------------------------------------------------
/algorithms/tree/is_balanced.py:
--------------------------------------------------------------------------------
1 | def is_balanced(root):
2 | return __is_balanced_recursive(root)
3 |
4 |
5 | def __is_balanced_recursive(root):
6 | """
7 | O(N) solution
8 | """
9 | return -1 != __get_depth(root)
10 |
11 |
12 | def __get_depth(root):
13 | """
14 | return 0 if unbalanced else depth + 1
15 | """
16 | if root is None:
17 | return 0
18 | left = __get_depth(root.left)
19 | right = __get_depth(root.right)
20 | if abs(left-right) > 1 or -1 in [left, right]:
21 | return -1
22 | return 1 + max(left, right)
23 |
24 |
25 | # def is_balanced(root):
26 | # """
27 | # O(N^2) solution
28 | # """
29 | # left = max_height(root.left)
30 | # right = max_height(root.right)
31 | # return abs(left-right) <= 1 and is_balanced(root.left) and
32 | # is_balanced(root.right)
33 |
34 | # def max_height(root):
35 | # if root is None:
36 | # return 0
37 | # return max(max_height(root.left), max_height(root.right)) + 1
38 |
--------------------------------------------------------------------------------
/algorithms/tree/longest_consecutive.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a binary tree, find the length of the longest consecutive sequence path.
3 |
4 | The path refers to any sequence of nodes from some starting node to any node
5 | in the tree along the parent-child connections.
6 | The longest consecutive path need to be from parent to child
7 | (cannot be the reverse).
8 |
9 | For example,
10 | 1
11 | \
12 | 3
13 | / \
14 | 2 4
15 | \
16 | 5
17 | Longest consecutive sequence path is 3-4-5, so return 3.
18 | 2
19 | \
20 | 3
21 | /
22 | 2
23 | /
24 | 1
25 | """
26 |
27 |
28 | def longest_consecutive(root):
29 | """
30 | :type root: TreeNode
31 | :rtype: int
32 | """
33 | if root is None:
34 | return 0
35 | max_len = 0
36 | dfs(root, 0, root.val, max_len)
37 | return max_len
38 |
39 |
40 | def dfs(root, cur, target, max_len):
41 | if root is None:
42 | return
43 | if root.val == target:
44 | cur += 1
45 | else:
46 | cur = 1
47 | max_len = max(cur, max_len)
48 | dfs(root.left, cur, root.val+1, max_len)
49 | dfs(root.right, cur, root.val+1, max_len)
50 |
--------------------------------------------------------------------------------
/algorithms/tree/lowest_common_ancestor.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a binary tree, find the lowest common ancestor
3 | (LCA) of two given nodes in the tree.
4 |
5 | According to the definition of LCA on Wikipedia:
6 | “The lowest common ancestor is defined between two nodes
7 | v and w as the lowest node in T that has both v and w as
8 | descendants
9 | (where we allow a node to be a descendant of itself).”
10 |
11 | _______3______
12 | / \
13 | ___5__ ___1__
14 | / \ / \
15 | 6 _2 0 8
16 | / \
17 | 7 4
18 | For example, the lowest common ancestor (LCA) of nodes 5 and 1 is 3.
19 | Another example is LCA of nodes 5 and 4 is 5,
20 | since a node can be a descendant of itself according to the LCA definition.
21 | """
22 |
23 |
24 | def lca(root, p, q):
25 | """
26 | :type root: TreeNode
27 | :type p: TreeNode
28 | :type q: TreeNode
29 | :rtype: TreeNode
30 | """
31 | if root is None or root is p or root is q:
32 | return root
33 | left = lca(root.left, p, q)
34 | right = lca(root.right, p, q)
35 | if left is not None and right is not None:
36 | return root
37 | return left if left else right
38 |
--------------------------------------------------------------------------------
/algorithms/tree/max_path_sum.py:
--------------------------------------------------------------------------------
1 | def max_path_sum(root):
2 | maximum = float("-inf")
3 | helper(root, maximum)
4 | return maximum
5 |
6 |
7 | def helper(root, maximum):
8 | if root is None:
9 | return 0
10 | left = helper(root.left, maximum)
11 | right = helper(root.right, maximum)
12 | maximum = max(maximum, left+right+root.val)
13 | return root.val + maximum
14 |
--------------------------------------------------------------------------------
/algorithms/tree/pretty_print.py:
--------------------------------------------------------------------------------
1 | # a -> Adam -> Book -> 4
2 | # b -> Bill -> Computer -> 5
3 | # -> TV -> 6
4 | # Jill -> Sports -> 1
5 | # c -> Bill -> Sports -> 3
6 | # d -> Adam -> Computer -> 3
7 | # Quin -> Computer -> 3
8 | # e -> Quin -> Book -> 5
9 | # -> TV -> 2
10 | # f -> Adam -> Computer -> 7
11 |
12 | from __future__ import print_function
13 |
14 |
15 | def tree_print(tree):
16 | for key in tree:
17 | print(key, end=' ') # end=' ' prevents a newline character
18 | tree_element = tree[key] # multiple lookups is expensive, even amortized O(1)!
19 | for subElem in tree_element:
20 | print(" -> ", subElem, end=' ')
21 | if type(subElem) != str: # OP wants indenting after digits
22 | print("\n ") # newline and a space to match indenting
23 | print() # forces a newline
24 |
--------------------------------------------------------------------------------
/algorithms/tree/same_tree.py:
--------------------------------------------------------------------------------
1 | """
2 | Given two binary trees, write a function to check
3 | if they are equal or not.
4 |
5 | Two binary trees are considered equal if they are
6 | structurally identical and the nodes have the same value.
7 | """
8 |
9 |
10 | def is_same_tree(tree_p, tree_q):
11 | if tree_p is None and tree_q is None:
12 | return True
13 | if tree_p is not None and tree_q is not None and tree_p.val == tree_q.val:
14 | return is_same_tree(tree_p.left, tree_q.left) and is_same_tree(tree_p.right, tree_q.right)
15 | return False
16 |
17 | # Time Complexity O(min(N,M))
18 | # where N and M are the number of nodes for the trees.
19 |
20 | # Space Complexity O(min(height1, height2))
21 | # levels of recursion is the mininum height between the two trees.
22 |
--------------------------------------------------------------------------------
/algorithms/tree/traversal/__init__.py:
--------------------------------------------------------------------------------
1 | from .preorder import *
2 | from .postorder import *
3 | from .inorder import *
4 |
--------------------------------------------------------------------------------
/algorithms/tree/traversal/level_order.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a binary tree, return the level order traversal of
3 | its nodes' values. (ie, from left to right, level by level).
4 |
5 | For example:
6 | Given binary tree [3,9,20,null,null,15,7],
7 | 3
8 | / \
9 | 9 20
10 | / \
11 | 15 7
12 | return its level order traversal as:
13 | [
14 | [3],
15 | [9,20],
16 | [15,7]
17 | ]
18 | """
19 |
20 |
21 | def level_order(root):
22 | ans = []
23 | if not root:
24 | return ans
25 | level = [root]
26 | while level:
27 | current = []
28 | new_level = []
29 | for node in level:
30 | current.append(node.val)
31 | if node.left:
32 | new_level.append(node.left)
33 | if node.right:
34 | new_level.append(node.right)
35 | level = new_level
36 | ans.append(current)
37 | return ans
38 |
--------------------------------------------------------------------------------
/algorithms/tree/traversal/postorder.py:
--------------------------------------------------------------------------------
1 | '''
2 | Time complexity : O(n)
3 | '''
4 |
5 | class Node:
6 |
7 | def __init__(self, val, left=None, right=None):
8 | self.val = val
9 | self.left = left
10 | self.right = right
11 |
12 |
13 | def postorder(root):
14 | res_temp = []
15 | res = []
16 | if not root:
17 | return res
18 | stack = []
19 | stack.append(root)
20 | while stack:
21 | root = stack.pop()
22 | res_temp.append(root.val)
23 | if root.left:
24 | stack.append(root.left)
25 | if root.right:
26 | stack.append(root.right)
27 | while res_temp:
28 | res.append(res_temp.pop())
29 | return res
30 |
31 | # Recursive Implementation
32 | def postorder_rec(root, res=None):
33 | if root is None:
34 | return []
35 | if res is None:
36 | res = []
37 | postorder_rec(root.left, res)
38 | postorder_rec(root.right, res)
39 | res.append(root.val)
40 | return res
41 |
42 |
--------------------------------------------------------------------------------
/algorithms/tree/traversal/preorder.py:
--------------------------------------------------------------------------------
1 | '''
2 | Time complexity : O(n)
3 | '''
4 |
5 |
6 | class Node:
7 | """ This is a class of Node """
8 |
9 | def __init__(self, val, left=None, right=None):
10 | self.val = val
11 | self.left = left
12 | self.right = right
13 |
14 |
15 | def preorder(root):
16 | """ Function to Preorder """
17 | res = []
18 | if not root:
19 | return res
20 | stack = []
21 | stack.append(root)
22 | while stack:
23 | root = stack.pop()
24 | res.append(root.val)
25 | if root.right:
26 | stack.append(root.right)
27 | if root.left:
28 | stack.append(root.left)
29 | return res
30 |
31 | def preorder_rec(root, res=None):
32 | """ Recursive Implementation """
33 | if root is None:
34 | return []
35 | if res is None:
36 | res = []
37 | res.append(root.val)
38 | preorder_rec(root.left, res)
39 | preorder_rec(root.right, res)
40 | return res
41 |
--------------------------------------------------------------------------------
/algorithms/tree/traversal/zigzag.py:
--------------------------------------------------------------------------------
1 | """
2 | Given a binary tree, return the zigzag level order traversal
3 | of its nodes' values.
4 | (ie, from left to right, then right to left
5 | for the next level and alternate between).
6 |
7 | For example:
8 | Given binary tree [3,9,20,null,null,15,7],
9 | 3
10 | / \
11 | 9 20
12 | / \
13 | 15 7
14 | return its zigzag level order traversal as:
15 | [
16 | [3],
17 | [20,9],
18 | [15,7]
19 | ]
20 | """
21 |
22 |
23 | def zigzag_level(root):
24 | res = []
25 | if not root:
26 | return res
27 | level = [root]
28 | flag = 1
29 | while level:
30 | current = []
31 | new_level = []
32 | for node in level:
33 | current.append(node.val)
34 | if node.left:
35 | new_level.append(node.left)
36 | if node.right:
37 | new_level.append(node.right)
38 | level = new_level
39 | res.append(current[::flag])
40 | flag *= -1
41 | return res
42 |
--------------------------------------------------------------------------------
/algorithms/tree/tree.py:
--------------------------------------------------------------------------------
1 | class TreeNode:
2 | def __init__(self, val=0):
3 | self.val = val
4 | self.left = None
5 | self.right = None
6 |
--------------------------------------------------------------------------------
/algorithms/tree/trie/trie.py:
--------------------------------------------------------------------------------
1 | """
2 | Implement a trie with insert, search, and startsWith methods.
3 |
4 | Note:
5 | You may assume that all inputs are consist of lowercase letters a-z.
6 | """
7 | import collections
8 |
9 |
10 | class TrieNode:
11 | def __init__(self):
12 | self.children = collections.defaultdict(TrieNode)
13 | self.is_word = False
14 |
15 |
16 | class Trie:
17 | def __init__(self):
18 | self.root = TrieNode()
19 |
20 | def insert(self, word):
21 | current = self.root
22 | for letter in word:
23 | current = current.children[letter]
24 | current.is_word = True
25 |
26 | def search(self, word):
27 | current = self.root
28 | for letter in word:
29 | current = current.children.get(letter)
30 | if current is None:
31 | return False
32 | return current.is_word
33 |
34 | def starts_with(self, prefix):
35 | current = self.root
36 | for letter in prefix:
37 | current = current.children.get(letter)
38 | if current is None:
39 | return False
40 | return True
41 |
42 |
--------------------------------------------------------------------------------
/algorithms/unix/__init__.py:
--------------------------------------------------------------------------------
1 | from .path.join_with_slash import *
2 | from .path.full_path import *
3 | from .path.split import *
4 | from .path.simplify_path import *
5 |
--------------------------------------------------------------------------------
/algorithms/unix/path/full_path.py:
--------------------------------------------------------------------------------
1 | """
2 | Get a full absolute path a file
3 | """
4 | import os
5 | def full_path(file):
6 | return os.path.abspath(os.path.expanduser(file))
7 |
--------------------------------------------------------------------------------
/algorithms/unix/path/join_with_slash.py:
--------------------------------------------------------------------------------
1 | """
2 | Both URL and file path joins use slashes as dividers between their parts.
3 | For example:
4 |
5 | path/to/dir + file --> path/to/dir/file
6 | path/to/dir/ + file --> path/to/dir/file
7 | http://algorithms.com/ + part --> http://algorithms.com/part
8 | http://algorithms.com + part --> http://algorithms/part
9 | """
10 | import os
11 |
12 | def join_with_slash(base, suffix):
13 | # Remove / trailing
14 | base = base.rstrip('/')
15 | # Remove / leading
16 | suffix = suffix.lstrip('/').rstrip()
17 | full_path = "{}/{}".format(base, suffix)
18 | return full_path
19 |
--------------------------------------------------------------------------------
/algorithms/unix/path/simplify_path.py:
--------------------------------------------------------------------------------
1 | """
2 | Given an absolute path for a file (Unix-style), simplify it.
3 |
4 | For example,
5 | path = "/home/", => "/home"
6 | path = "/a/./b/../../c/", => "/c"
7 |
8 | Corner Cases:
9 |
10 | Did you consider the case where path = "/../"?
11 | In this case, you should return "/".
12 | Another corner case is the path might contain multiple slashes '/' together, such as "/home//foo/".
13 | In this case, you should ignore redundant slashes and return "/home/foo".
14 |
15 | Reference: https://leetcode.com/problems/simplify-path/description/
16 | """
17 |
18 | import os
19 | def simplify_path_v1(path):
20 | return os.path.abspath(path)
21 |
22 | def simplify_path_v2(path):
23 | stack, tokens = [], path.split("/")
24 | for token in tokens:
25 | if token == ".." and stack:
26 | stack.pop()
27 | elif token != ".." and token != "." and token:
28 | stack.append(token)
29 | return "/" + "/".join(stack)
30 |
--------------------------------------------------------------------------------
/algorithms/unix/path/split.py:
--------------------------------------------------------------------------------
1 | """
2 | Splitting a path into 2 parts
3 | Example:
4 | Input: https://algorithms/unix/test.py (for url)
5 | Output:
6 | part[0]: https://algorithms/unix
7 | part[1]: test.py
8 |
9 | Input: algorithms/unix/test.py (for file path)
10 | Output:
11 | part[0]: algorithms/unix
12 | part[1]: test.py
13 | """
14 | import os
15 |
16 | def split(path):
17 | parts = []
18 | split_part = path.rpartition('/')
19 | # Takt the origin path without the last part
20 | parts.append(split_part[0])
21 | # Take the last element of list
22 | parts.append(split_part[2])
23 | return parts
24 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | SPHINXPROJ = algorithms
8 | SOURCEDIR = source
9 | BUILDDIR = build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=source
11 | set BUILDDIR=build
12 | set SPHINXPROJ=algorithms
13 |
14 | if "%1" == "" goto help
15 |
16 | %SPHINXBUILD% >NUL 2>NUL
17 | if errorlevel 9009 (
18 | echo.
19 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
20 | echo.installed, then set the SPHINXBUILD environment variable to point
21 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
22 | echo.may add the Sphinx directory to PATH.
23 | echo.
24 | echo.If you don't have Sphinx installed, grab it from
25 | echo.http://sphinx-doc.org/
26 | exit /b 1
27 | )
28 |
29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
30 | goto end
31 |
32 | :help
33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
34 |
35 | :end
36 | popd
37 |
--------------------------------------------------------------------------------
/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | # Progress bars on iterators
2 | tqdm
3 | sphinx_rtd_theme
4 |
5 | # Downloading data and other files
6 | requests
7 |
8 | # Required for tests only:
9 |
10 | # Style-checking for PEP8
11 | flake8
12 |
13 | # Run unit tests
14 | pytest
15 |
16 | # Lets pytest find our code by automatically modifying PYTHONPATH
17 | pytest-pythonpath
18 |
19 | # Coverage statistics
20 | pytest-cov
21 | codecov
22 |
--------------------------------------------------------------------------------
/docs/source/_static/algorithms_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/cad4754bc71742c2d6fcbd3b92ae74834d359844/docs/source/_static/algorithms_logo.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/128pxblack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/cad4754bc71742c2d6fcbd3b92ae74834d359844/docs/source/_static/logo/128pxblack.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/128pxblack.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
--------------------------------------------------------------------------------
/docs/source/_static/logo/128pxblue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/cad4754bc71742c2d6fcbd3b92ae74834d359844/docs/source/_static/logo/128pxblue.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/128pxblue.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
--------------------------------------------------------------------------------
/docs/source/_static/logo/128pxorange.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/cad4754bc71742c2d6fcbd3b92ae74834d359844/docs/source/_static/logo/128pxorange.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/128pxorange.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
--------------------------------------------------------------------------------
/docs/source/_static/logo/256pxblack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/cad4754bc71742c2d6fcbd3b92ae74834d359844/docs/source/_static/logo/256pxblack.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/256pxblack.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
--------------------------------------------------------------------------------
/docs/source/_static/logo/256pxblue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/cad4754bc71742c2d6fcbd3b92ae74834d359844/docs/source/_static/logo/256pxblue.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/256pxblue.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
--------------------------------------------------------------------------------
/docs/source/_static/logo/256pxorange.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/cad4754bc71742c2d6fcbd3b92ae74834d359844/docs/source/_static/logo/256pxorange.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/256pxorange.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
--------------------------------------------------------------------------------
/docs/source/_static/logo/512pxblack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/cad4754bc71742c2d6fcbd3b92ae74834d359844/docs/source/_static/logo/512pxblack.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/512pxblack.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
--------------------------------------------------------------------------------
/docs/source/_static/logo/512pxblue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/cad4754bc71742c2d6fcbd3b92ae74834d359844/docs/source/_static/logo/512pxblue.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/512pxblue.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
--------------------------------------------------------------------------------
/docs/source/_static/logo/512pxorange.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/cad4754bc71742c2d6fcbd3b92ae74834d359844/docs/source/_static/logo/512pxorange.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/512pxorange.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
--------------------------------------------------------------------------------
/docs/source/_static/logo/add:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/docs/source/_static/logo/logotype1black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/cad4754bc71742c2d6fcbd3b92ae74834d359844/docs/source/_static/logo/logotype1black.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/logotype1blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/cad4754bc71742c2d6fcbd3b92ae74834d359844/docs/source/_static/logo/logotype1blue.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/logotype1orange.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/cad4754bc71742c2d6fcbd3b92ae74834d359844/docs/source/_static/logo/logotype1orange.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/logotype2black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/cad4754bc71742c2d6fcbd3b92ae74834d359844/docs/source/_static/logo/logotype2black.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/logotype2blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/cad4754bc71742c2d6fcbd3b92ae74834d359844/docs/source/_static/logo/logotype2blue.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/logotype2orange.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/cad4754bc71742c2d6fcbd3b92ae74834d359844/docs/source/_static/logo/logotype2orange.png
--------------------------------------------------------------------------------
/docs/source/arrays.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 |
4 | algorithms.arrays
5 | =================
6 |
7 | .. automodule:: algorithms.arrays
8 | .. currentmodule:: algorithms.arrays
9 |
10 | longest_non_repeat
11 | ------------------
12 |
13 | :hidden:`longest_non_repeat_v1`
14 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
15 |
16 | .. autofunction:: longest_non_repeat_v1
17 |
--------------------------------------------------------------------------------
/docs/source/backtrack.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 |
4 | algorithms.backtrack
5 | ====================
6 |
--------------------------------------------------------------------------------
/docs/source/bfs.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 |
4 | algorithms.bfs
5 | =================
6 |
--------------------------------------------------------------------------------
/docs/source/bit.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 |
4 | algorithms.bit
5 | =================
6 |
--------------------------------------------------------------------------------
/docs/source/dfs.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 |
4 | algorithms.dfs
5 | =================
6 |
--------------------------------------------------------------------------------
/docs/source/dp.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 |
4 | algorithms.dp
5 | =================
6 |
--------------------------------------------------------------------------------
/docs/source/examples.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 |
4 | Examples
5 | =================
6 |
--------------------------------------------------------------------------------
/docs/source/graph.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 |
4 | algorithms.graph
5 | =================
6 |
--------------------------------------------------------------------------------
/docs/source/heap.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 |
4 | algorithms.heap
5 | =================
6 |
--------------------------------------------------------------------------------
/docs/source/index.rst:
--------------------------------------------------------------------------------
1 | .. image:: /_static/algorithms_logo.png
2 | :target: https://github.com/keon/algorithms
3 | :scale: 50 %
4 |
5 | The :mod:`algorithms` package consists of
6 | minimal and clean example implementations of data structures and algorithms.
7 |
8 | .. toctree::
9 | :maxdepth: 2
10 | :caption: Package Reference
11 |
12 | self
13 | algorithms.arrays
14 | algorithms.backtrack
15 | algorithms.bfs
16 | algorithms.bit
17 | algorithms.dfs
18 | algorithms.dp
19 | algorithms.graph
20 | algorithms.heap
21 | algorithms.linkedlist
22 | algorithms.map