├── requirements.txt
├── algorithms
├── __init__.py
├── tree
│ ├── __init__.py
│ ├── avl
│ │ └── __init__.py
│ ├── traversal
│ │ ├── __init__.py
│ │ ├── level_order.py
│ │ ├── preorder.py
│ │ ├── postorder.py
│ │ └── zigzag.py
│ ├── tree.py
│ ├── bst
│ │ ├── successor.py
│ │ ├── predecessor.py
│ │ ├── array_to_bst.py
│ │ ├── BSTIterator.py
│ │ ├── bst_closest_value.py
│ │ ├── serialize_deserialize.py
│ │ ├── is_bst.py
│ │ ├── unique_bst.py
│ │ └── lowest_common_ancestor.py
│ ├── invert_tree.py
│ ├── max_path_sum.py
│ ├── binary_tree_paths.py
│ ├── same_tree.py
│ ├── pretty_print.py
│ ├── bin_tree_to_list.py
│ ├── is_balanced.py
│ ├── longest_consecutive.py
│ ├── trie
│ │ └── trie.py
│ ├── deepest_left.py
│ └── lowest_common_ancestor.py
├── matrix
│ ├── __init__.py
│ ├── sum_sub_squares.py
│ ├── rotate_image.py
│ ├── search_in_sorted_matrix.py
│ ├── multiply.py
│ └── matrix_exponentiation.py
├── compression
│ └── __init__.py
├── distribution
│ ├── __init__.py
│ └── histogram.py
├── automata
│ ├── __init__.py
│ └── dfa.py
├── set
│ ├── __init__.py
│ └── find_keyboard_row.py
├── streaming
│ └── __init__.py
├── greedy
│ └── __init__.py
├── queues
│ ├── __init__.py
│ ├── zigzagiterator.py
│ ├── reconstruct_queue.py
│ ├── moving_average.py
│ └── max_sliding_window.py
├── unix
│ ├── __init__.py
│ └── path
│ │ ├── full_path.py
│ │ ├── join_with_slash.py
│ │ ├── split.py
│ │ └── simplify_path.py
├── bfs
│ └── __init__.py
├── heap
│ ├── __init__.py
│ └── sliding_window_max.py
├── dfs
│ ├── __init__.py
│ └── count_islands.py
├── map
│ ├── __init__.py
│ ├── valid_sudoku.py
│ ├── is_anagram.py
│ ├── longest_common_subsequence.py
│ ├── is_isomorphic.py
│ └── longest_palindromic_subsequence.py
├── bit
│ ├── power_of_two.py
│ ├── add_bitwise_operator.py
│ ├── remove_bit.py
│ ├── reverse_bits.py
│ ├── count_flips_to_convert.py
│ ├── __init__.py
│ ├── single_number.py
│ ├── find_missing_number.py
│ ├── bytes_int_conversion.py
│ ├── swap_pair.py
│ ├── flip_bit_longest_sequence.py
│ ├── find_difference.py
│ ├── single_number2.py
│ ├── count_ones.py
│ ├── bit_operation.py
│ └── has_alternative_bit.py
├── maths
│ ├── num_digits.py
│ ├── prime_check.py
│ ├── nth_digit.py
│ ├── hailstone.py
│ ├── sqrt_precision_factor.py
│ ├── euler_totient.py
│ ├── combination.py
│ ├── modular_exponential.py
│ ├── next_perfect_square.py
│ ├── extended_gcd.py
│ ├── is_strobogrammatic.py
│ ├── pythagoras.py
│ ├── find_order_simple.py
│ ├── __init__.py
│ ├── fft.py
│ ├── modular_inverse.py
│ ├── decimal_to_binary_ip.py
│ ├── recursive_binomial_coefficient.py
│ ├── cosine_similarity.py
│ ├── summing_digits.py
│ ├── magic_number.py
│ ├── power.py
│ ├── base_conversion.py
│ └── factorial.py
├── linkedlist
│ ├── __init__.py
│ ├── is_sorted.py
│ ├── is_cyclic.py
│ ├── swap_in_pairs.py
│ ├── linkedlist.py
│ ├── reverse.py
│ ├── rotate_list.py
│ ├── merge_two_list.py
│ ├── remove_range.py
│ └── copy_random_pointer.py
├── strings
│ ├── check_pangram.py
│ ├── license_number.py
│ ├── reverse_vowel.py
│ ├── reverse_string.py
│ ├── reverse_words.py
│ ├── int_to_roman.py
│ ├── delete_reoccurring.py
│ ├── add_binary.py
│ ├── roman_to_int.py
│ ├── group_anagrams.py
│ ├── rotate.py
│ ├── repeat_substring.py
│ ├── first_unique_char.py
│ ├── atbash_cipher.py
│ ├── contain_string.py
│ ├── caesar_cipher.py
│ ├── make_sentence.py
│ ├── is_rotated.py
│ ├── repeat_string.py
│ ├── judge_circle.py
│ ├── encode_decode.py
│ ├── one_edit_distance.py
│ ├── multiply_strings.py
│ ├── domain_extractor.py
│ ├── longest_palindromic_substring.py
│ ├── panagram.py
│ └── count_binary_substring.py
├── stack
│ ├── __init__.py
│ ├── valid_parenthesis.py
│ ├── remove_min.py
│ ├── simplify_path.py
│ ├── is_sorted.py
│ └── ordered_stack.py
├── dp
│ ├── max_subarray.py
│ ├── house_robber.py
│ ├── __init__.py
│ ├── rod_cut.py
│ ├── climbing_stairs.py
│ ├── knapsack.py
│ ├── word_break.py
│ ├── int_divide.py
│ └── coin_change.py
├── graph
│ ├── __init__.py
│ ├── markov_chain.py
│ ├── prims_minimum_spanning.py
│ ├── check_bipartite.py
│ └── all_pairs_shortest_path.py
├── sort
│ ├── exchange_sort.py
│ ├── wiggle_sort.py
│ ├── gnome_sort.py
│ ├── meeting_rooms.py
│ ├── shell_sort.py
│ ├── __init__.py
│ ├── pigeonhole_sort.py
│ ├── selection_sort.py
│ ├── comb_sort.py
│ ├── insertion_sort.py
│ ├── pancake_sort.py
│ ├── sort_colors.py
│ ├── cocktail_shaker_sort.py
│ ├── bogo_sort.py
│ ├── bucket_sort.py
│ ├── radix_sort.py
│ ├── bubble_sort.py
│ ├── stooge_sort.py
│ ├── quick_sort.py
│ └── bead_sort.py
├── search
│ ├── linear_search.py
│ ├── __init__.py
│ ├── search_insert.py
│ ├── last_occurrence.py
│ ├── first_occurrence.py
│ ├── search_range.py
│ ├── find_min_rotate.py
│ └── jump_search.py
├── backtrack
│ ├── anagram.py
│ ├── __init__.py
│ ├── permute_unique.py
│ ├── subsets_unique.py
│ ├── generate_abbreviations.py
│ ├── letter_combination.py
│ ├── combination_sum.py
│ ├── generate_parenthesis.py
│ └── subsets.py
├── arrays
│ ├── __init__.py
│ ├── missing_ranges.py
│ ├── two_sum.py
│ ├── josephus.py
│ ├── summarize_ranges.py
│ ├── move_zeros.py
│ ├── limit.py
│ ├── remove_duplicates.py
│ ├── trimmean.py
│ ├── delete_nth.py
│ ├── flatten.py
│ ├── top_1.py
│ ├── max_ones_index.py
│ └── plus_one.py
└── ml
│ └── nearest_neighbor.py
├── docs
├── source
│ ├── _static
│ │ ├── logo
│ │ │ ├── add
│ │ │ ├── 128pxblue.png
│ │ │ ├── 256pxblue.png
│ │ │ ├── 512pxblue.png
│ │ │ ├── 128pxblack.png
│ │ │ ├── 128pxorange.png
│ │ │ ├── 256pxblack.png
│ │ │ ├── 256pxorange.png
│ │ │ ├── 512pxblack.png
│ │ │ ├── 512pxorange.png
│ │ │ ├── logotype1black.png
│ │ │ ├── logotype1blue.png
│ │ │ ├── logotype2black.png
│ │ │ ├── logotype2blue.png
│ │ │ ├── logotype1orange.png
│ │ │ ├── logotype2orange.png
│ │ │ ├── 128pxblack.svg
│ │ │ ├── 256pxblack.svg
│ │ │ ├── 512pxblack.svg
│ │ │ ├── 128pxblue.svg
│ │ │ ├── 128pxorange.svg
│ │ │ ├── 256pxblue.svg
│ │ │ ├── 256pxorange.svg
│ │ │ ├── 512pxblue.svg
│ │ │ └── 512pxorange.svg
│ │ └── algorithms_logo.png
│ ├── bfs.rst
│ ├── bit.rst
│ ├── dfs.rst
│ ├── dp.rst
│ ├── examples.rst
│ ├── map.rst
│ ├── set.rst
│ ├── graph.rst
│ ├── heap.rst
│ ├── maths.rst
│ ├── matrix.rst
│ ├── queues.rst
│ ├── search.rst
│ ├── sort.rst
│ ├── stack.rst
│ ├── tree.rst
│ ├── strings.rst
│ ├── backtrack.rst
│ ├── linkedlist.rst
│ ├── arrays.rst
│ └── index.rst
├── requirements.txt
├── Makefile
└── make.bat
├── MANIFEST.in
├── .coveragerc
├── test_requirements.txt
├── tests
├── test_set.py
├── test_histogram.py
└── test_greedy.py
├── .gitignore
├── setup.py
├── .travis.yml
├── LICENSE
├── .github
└── workflows
│ └── python-app.yml
└── tox.ini
/requirements.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/algorithms/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/algorithms/tree/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/algorithms/matrix/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/algorithms/tree/avl/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/source/_static/logo/add:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/algorithms/compression/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/algorithms/distribution/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/algorithms/automata/__init__.py:
--------------------------------------------------------------------------------
1 | from .dfa import *
2 |
--------------------------------------------------------------------------------
/algorithms/set/__init__.py:
--------------------------------------------------------------------------------
1 | from .find_keyboard_row import *
2 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include README.md
2 | include LICENSE
3 | include algorithms/*
4 |
--------------------------------------------------------------------------------
/algorithms/streaming/__init__.py:
--------------------------------------------------------------------------------
1 | from .one_sparse_recovery import *
2 | from .misra_gries import *
3 |
--------------------------------------------------------------------------------
/.coveragerc:
--------------------------------------------------------------------------------
1 | [report]
2 | omit =
3 | */python?.?/*
4 | */site-packages/nose/*
5 | *__init__*
6 |
--------------------------------------------------------------------------------
/algorithms/greedy/__init__.py:
--------------------------------------------------------------------------------
1 | from .max_contiguous_subsequence_sum import *
2 | from .gale_shapley import *
--------------------------------------------------------------------------------
/test_requirements.txt:
--------------------------------------------------------------------------------
1 | flake8
2 | python-coveralls
3 | coverage
4 | nose
5 | pytest
6 | tox
7 | black
8 |
--------------------------------------------------------------------------------
/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/map.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 |
4 | algorithms.map
5 | =================
6 |
--------------------------------------------------------------------------------
/docs/source/set.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 |
4 | algorithms.set
5 | =================
6 |
--------------------------------------------------------------------------------
/algorithms/tree/traversal/__init__.py:
--------------------------------------------------------------------------------
1 | from .preorder import *
2 | from .postorder import *
3 | from .inorder import *
4 |
--------------------------------------------------------------------------------
/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/maths.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 |
4 | algorithms.maths
5 | =================
6 |
--------------------------------------------------------------------------------
/docs/source/matrix.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 |
4 | algorithms.matrix
5 | =================
6 |
--------------------------------------------------------------------------------
/docs/source/queues.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 |
4 | algorithms.queue
5 | =================
6 |
--------------------------------------------------------------------------------
/docs/source/search.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 |
4 | algorithms.search
5 | =================
6 |
--------------------------------------------------------------------------------
/docs/source/sort.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 |
4 | algorithms.sort
5 | =================
6 |
--------------------------------------------------------------------------------
/docs/source/stack.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 |
4 | algorithms.stack
5 | =================
6 |
--------------------------------------------------------------------------------
/docs/source/tree.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 |
4 | algorithms.tree
5 | =================
6 |
--------------------------------------------------------------------------------
/docs/source/_static/logo/128pxblue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/HEAD/docs/source/_static/logo/128pxblue.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/256pxblue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/HEAD/docs/source/_static/logo/256pxblue.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/512pxblue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/HEAD/docs/source/_static/logo/512pxblue.png
--------------------------------------------------------------------------------
/docs/source/strings.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 |
4 | algorithms.string
5 | =================
6 |
--------------------------------------------------------------------------------
/docs/source/_static/algorithms_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/HEAD/docs/source/_static/algorithms_logo.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/128pxblack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/HEAD/docs/source/_static/logo/128pxblack.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/128pxorange.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/HEAD/docs/source/_static/logo/128pxorange.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/256pxblack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/HEAD/docs/source/_static/logo/256pxblack.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/256pxorange.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/HEAD/docs/source/_static/logo/256pxorange.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/512pxblack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/HEAD/docs/source/_static/logo/512pxblack.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/512pxorange.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/HEAD/docs/source/_static/logo/512pxorange.png
--------------------------------------------------------------------------------
/docs/source/backtrack.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 |
4 | algorithms.backtrack
5 | ====================
6 |
--------------------------------------------------------------------------------
/docs/source/_static/logo/logotype1black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/HEAD/docs/source/_static/logo/logotype1black.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/logotype1blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/HEAD/docs/source/_static/logo/logotype1blue.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/logotype2black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/HEAD/docs/source/_static/logo/logotype2black.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/logotype2blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/HEAD/docs/source/_static/logo/logotype2blue.png
--------------------------------------------------------------------------------
/docs/source/linkedlist.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 |
4 | algorithms.linkedlist
5 | =====================
6 |
--------------------------------------------------------------------------------
/docs/source/_static/logo/logotype1orange.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/HEAD/docs/source/_static/logo/logotype1orange.png
--------------------------------------------------------------------------------
/docs/source/_static/logo/logotype2orange.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/keon/algorithms/HEAD/docs/source/_static/logo/logotype2orange.png
--------------------------------------------------------------------------------
/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/tests/test_set.py:
--------------------------------------------------------------------------------
1 | from algorithms.set import (
2 | find_keyboard_row
3 | )
4 |
5 | import unittest
6 |
7 |
8 | class TestFindKeyboardRow(unittest.TestCase):
9 | def test_find_keyboard_row(self):
10 | self.assertEqual(["Alaska", "Dad"],
11 | find_keyboard_row(["Hello", "Alaska",
12 | "Dad", "Peace"]))
13 |
--------------------------------------------------------------------------------
/.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/
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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/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/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/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/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/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/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/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/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_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/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 |
--------------------------------------------------------------------------------
/tests/test_histogram.py:
--------------------------------------------------------------------------------
1 | from algorithms.distribution.histogram import get_histogram
2 |
3 | import unittest
4 |
5 |
6 | class TestListsInHistogram(unittest.TestCase):
7 | def test_histogram(self):
8 | list_1 = [3, 3, 2, 1]
9 | list_2 = [2, 3, 5, 5, 5, 6, 4, 3, 7]
10 |
11 | self.assertEqual(get_histogram(list_1), {1: 1, 2: 1, 3: 2})
12 | self.assertEqual(get_histogram(list_2),
13 | {2: 1, 3: 2, 4: 1, 5: 3, 6: 1, 7: 1})
14 |
15 |
16 | if __name__ == '__main__':
17 | unittest.main()
18 |
--------------------------------------------------------------------------------
/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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 |
--------------------------------------------------------------------------------
/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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/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/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 |
--------------------------------------------------------------------------------
/tests/test_greedy.py:
--------------------------------------------------------------------------------
1 | from algorithms.greedy import (
2 | max_contiguous_subsequence_sum,
3 | )
4 |
5 | import unittest
6 |
7 | class TestMaxContiguousSubsequenceSum(unittest.TestCase):
8 | def test_max_contiguous_subsequence_sum(self):
9 | arr1 = [-2, 3, 8, -1, 4]
10 | arr2 = [-1, 1, 0]
11 | arr3 = [-1, -3, -4]
12 | arr4 = [-2, 3, 8, -12, 8, 4]
13 |
14 | self.assertEqual(max_contiguous_subsequence_sum(arr1), 14)
15 | self.assertEqual(max_contiguous_subsequence_sum(arr2), 1)
16 | self.assertEqual(max_contiguous_subsequence_sum(arr3), -1)
17 | self.assertEqual(max_contiguous_subsequence_sum(arr4), 12)
18 |
19 | if __name__ == '__main__':
20 |
21 | unittest.main()
--------------------------------------------------------------------------------
/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/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/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/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/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/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/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 | from typing import List, Tuple
9 |
10 |
11 | def summarize_ranges(array: List[int]) -> List[Tuple[int, ...]]:
12 | res = []
13 | if len(array) == 0:
14 | return []
15 | if len(array) == 1:
16 | return [(array[0], array[0])]
17 | it = iter(array)
18 | start = end = next(it)
19 | for num in it:
20 | if num - end == 1:
21 | end = num
22 | else:
23 | res.append((start, end))
24 | start = end = num
25 | res.append((start, end))
26 | return res
27 |
--------------------------------------------------------------------------------
/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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 | Time Complexity: O(n) for hashable items, O(n²) worst case for unhashable items
11 | Space Complexity: O(n) for the seen set and result array
12 | """
13 |
14 | from collections.abc import Hashable
15 |
16 |
17 | def remove_duplicates(array):
18 | seen = set()
19 | new_array = []
20 |
21 | for item in array:
22 | if isinstance(item, Hashable):
23 | if item not in seen:
24 | seen.add(item)
25 | new_array.append(item)
26 | else:
27 | if item not in new_array:
28 | new_array.append(item)
29 |
30 | return new_array
31 |
--------------------------------------------------------------------------------
/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/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/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/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/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/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/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/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/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/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/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/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 |
--------------------------------------------------------------------------------
/docs/source/_static/logo/128pxblack.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
--------------------------------------------------------------------------------
/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/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/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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/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/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 |
--------------------------------------------------------------------------------
/docs/source/_static/logo/256pxblack.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
--------------------------------------------------------------------------------
/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/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/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/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/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 |
--------------------------------------------------------------------------------
/docs/source/_static/logo/512pxblack.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import io
2 | from setuptools import find_packages, setup
3 |
4 |
5 | def long_description():
6 | with io.open('README.md', 'r', encoding='utf-8') as f:
7 | readme = f.read()
8 | return readme
9 |
10 |
11 | setup(name='algorithms',
12 | version='0.1.4',
13 | description='Pythonic Data Structures and Algorithms',
14 | long_description=long_description(),
15 | long_description_content_type="text/markdown",
16 | url='https://github.com/keon/algorithms',
17 | author='Algorithms Team & Contributors',
18 | author_email="kwk236@gmail.com",
19 | license='MIT',
20 | packages=find_packages(exclude=('tests', 'tests.*')),
21 | classifiers=[
22 | 'Programming Language :: Python :: 3',
23 | 'Programming Language :: Python :: 3.4',
24 | 'Programming Language :: Python :: 3.5',
25 | 'Programming Language :: Python :: 3.6',
26 | 'Programming Language :: Python :: 3.7',
27 | ],
28 | zip_safe=False)
29 |
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/docs/source/_static/logo/128pxblue.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
--------------------------------------------------------------------------------
/docs/source/_static/logo/128pxorange.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
--------------------------------------------------------------------------------
/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/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/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/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 |
--------------------------------------------------------------------------------
/docs/source/_static/logo/256pxblue.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
--------------------------------------------------------------------------------
/docs/source/_static/logo/256pxorange.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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