From 06dbef04a0700095b156c26b113bf08466a46c90 Mon Sep 17 00:00:00 2001 From: Gattlin Walker Date: Tue, 30 Apr 2019 08:16:42 -0500 Subject: [PATCH 01/11] Adding quick sort where random pivot point is chosen (#774) --- sorts/random_pivot_quick_sort.py | 33 ++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 sorts/random_pivot_quick_sort.py diff --git a/sorts/random_pivot_quick_sort.py b/sorts/random_pivot_quick_sort.py new file mode 100644 index 000000000000..fc8f90486ee6 --- /dev/null +++ b/sorts/random_pivot_quick_sort.py @@ -0,0 +1,33 @@ +""" +Picks the random index as the pivot +""" +import random + +def partition(A, left_index, right_index): + pivot = A[left_index] + i = left_index + 1 + for j in range(left_index + 1, right_index): + if A[j] < pivot: + A[j], A[i] = A[i], A[j] + i += 1 + A[left_index], A[i - 1] = A[i - 1], A[left_index] + return i - 1 + +def quick_sort_random(A, left, right): + if left < right: + pivot = random.randint(left, right - 1) + A[pivot], A[left] = A[left], A[pivot] #switches the pivot with the left most bound + pivot_index = partition(A, left, right) + quick_sort_random(A, left, pivot_index) #recursive quicksort to the left of the pivot point + quick_sort_random(A, pivot_index + 1, right) #recursive quicksort to the right of the pivot point + +def main(): + user_input = input('Enter numbers separated by a comma:\n').strip() + arr = [int(item) for item in user_input.split(',')] + + quick_sort_random(arr, 0, len(arr)) + + print(arr) + +if __name__ == "__main__": + main() \ No newline at end of file From 7b89d03dd7d80087fa95bcf7a1983fe3d8b424ca Mon Sep 17 00:00:00 2001 From: yolstatrisch Date: Thu, 2 May 2019 00:44:21 +0800 Subject: [PATCH 02/11] Added an O(1) solution to problem 002 (#776) * Added an O(1) solution to problem 002 * Removed comments from sol3.py that were accidentally added to sol4.py --- project_euler/problem_02/sol4.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 project_euler/problem_02/sol4.py diff --git a/project_euler/problem_02/sol4.py b/project_euler/problem_02/sol4.py new file mode 100644 index 000000000000..64bae65f49b4 --- /dev/null +++ b/project_euler/problem_02/sol4.py @@ -0,0 +1,13 @@ +import math +from decimal import * + +getcontext().prec = 100 +phi = (Decimal(5) ** Decimal(0.5) + 1) / Decimal(2) + +n = Decimal(int(input()) - 1) + +index = (math.floor(math.log(n * (phi + 2), phi) - 1) // 3) * 3 + 2 +num = round(phi ** Decimal(index + 1)) / (phi + 2) +sum = num // 2 + +print(int(sum)) From c5c3a74f8fbeed522288a63099a2121f9fe6bddb Mon Sep 17 00:00:00 2001 From: Anup Kumar Panwar <1anuppanwar@gmail.com> Date: Sat, 4 May 2019 15:43:37 +0530 Subject: [PATCH 03/11] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index faebd313507a..1e43deb6bdef 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ # The Algorithms - Python +[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=JP3BLXA6KMDGW) + ### All algorithms implemented in Python (for education) From e22ea7e380d75012990c8bb1648081b229cdd6fa Mon Sep 17 00:00:00 2001 From: Anup Kumar Panwar <1anuppanwar@gmail.com> Date: Sat, 4 May 2019 21:53:06 +0530 Subject: [PATCH 04/11] Update Directed and Undirected (Weighted) Graph.py --- graphs/Directed and Undirected (Weighted) Graph.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/graphs/Directed and Undirected (Weighted) Graph.py b/graphs/Directed and Undirected (Weighted) Graph.py index 68977de8d311..a31a4a96d6d0 100644 --- a/graphs/Directed and Undirected (Weighted) Graph.py +++ b/graphs/Directed and Undirected (Weighted) Graph.py @@ -152,6 +152,7 @@ def cycle_nodes(self): parent = -2 indirect_parents = [] ss = s + on_the_way_back = False anticipating_nodes = set() while True: @@ -199,6 +200,7 @@ def has_cycle(self): parent = -2 indirect_parents = [] ss = s + on_the_way_back = False anticipating_nodes = set() while True: @@ -367,6 +369,7 @@ def cycle_nodes(self): parent = -2 indirect_parents = [] ss = s + on_the_way_back = False anticipating_nodes = set() while True: @@ -414,6 +417,7 @@ def has_cycle(self): parent = -2 indirect_parents = [] ss = s + on_the_way_back = False anticipating_nodes = set() while True: From 7677c370115faa49759b72f5d7c9debfe1081e35 Mon Sep 17 00:00:00 2001 From: weixuanhu <44716380+weixuanhu@users.noreply.github.com> Date: Mon, 6 May 2019 17:54:31 +0800 Subject: [PATCH 05/11] update 'sorted' to 'ascending sorted' in comments (#789) To avoid confusion all 'sorted' to 'ascending sorted' in comments --- searches/binary_search.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/searches/binary_search.py b/searches/binary_search.py index 7df45883c09a..1d5da96586cd 100644 --- a/searches/binary_search.py +++ b/searches/binary_search.py @@ -21,10 +21,10 @@ def binary_search(sorted_collection, item): """Pure implementation of binary search algorithm in Python - Be careful collection must be sorted, otherwise result will be + Be careful collection must be ascending sorted, otherwise result will be unpredictable - :param sorted_collection: some sorted collection with comparable items + :param sorted_collection: some ascending sorted collection with comparable items :param item: item value to search :return: index of found item or None if item is not found @@ -60,10 +60,10 @@ def binary_search(sorted_collection, item): def binary_search_std_lib(sorted_collection, item): """Pure implementation of binary search algorithm in Python using stdlib - Be careful collection must be sorted, otherwise result will be + Be careful collection must be ascending sorted, otherwise result will be unpredictable - :param sorted_collection: some sorted collection with comparable items + :param sorted_collection: some ascending sorted collection with comparable items :param item: item value to search :return: index of found item or None if item is not found @@ -89,11 +89,11 @@ def binary_search_by_recursion(sorted_collection, item, left, right): """Pure implementation of binary search algorithm in Python by recursion - Be careful collection must be sorted, otherwise result will be + Be careful collection must be ascending sorted, otherwise result will be unpredictable First recursion should be started with left=0 and right=(len(sorted_collection)-1) - :param sorted_collection: some sorted collection with comparable items + :param sorted_collection: some ascending sorted collection with comparable items :param item: item value to search :return: index of found item or None if item is not found @@ -123,11 +123,11 @@ def binary_search_by_recursion(sorted_collection, item, left, right): return binary_search_by_recursion(sorted_collection, item, midpoint+1, right) def __assert_sorted(collection): - """Check if collection is sorted, if not - raises :py:class:`ValueError` + """Check if collection is ascending sorted, if not - raises :py:class:`ValueError` :param collection: collection - :return: True if collection is sorted - :raise: :py:class:`ValueError` if collection is not sorted + :return: True if collection is ascending sorted + :raise: :py:class:`ValueError` if collection is not ascending sorted Examples: >>> __assert_sorted([0, 1, 2, 4]) @@ -136,10 +136,10 @@ def __assert_sorted(collection): >>> __assert_sorted([10, -1, 5]) Traceback (most recent call last): ... - ValueError: Collection must be sorted + ValueError: Collection must be ascending sorted """ if collection != sorted(collection): - raise ValueError('Collection must be sorted') + raise ValueError('Collection must be ascending sorted') return True @@ -150,7 +150,7 @@ def __assert_sorted(collection): try: __assert_sorted(collection) except ValueError: - sys.exit('Sequence must be sorted to apply binary search') + sys.exit('Sequence must be ascending sorted to apply binary search') target_input = raw_input('Enter a single number to be found in the list:\n') target = int(target_input) From 30a358298385e0e29b70a841d0b4019dc235f3a3 Mon Sep 17 00:00:00 2001 From: Lorenz Nickel Date: Wed, 8 May 2019 21:48:30 +0200 Subject: [PATCH 06/11] fix: replaced outdated url (#791) http://www.lpb-riannetrujillo.com/blog/python-fractal/ moved to http://www.riannetrujillo.com/blog/python-fractal/ --- other/sierpinski_triangle.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/other/sierpinski_triangle.py b/other/sierpinski_triangle.py index 6a06058fe03e..329a8ce5c43f 100644 --- a/other/sierpinski_triangle.py +++ b/other/sierpinski_triangle.py @@ -21,7 +21,7 @@ Usage: - $python sierpinski_triangle.py -Credits: This code was written by editing the code from http://www.lpb-riannetrujillo.com/blog/python-fractal/ +Credits: This code was written by editing the code from http://www.riannetrujillo.com/blog/python-fractal/ ''' import turtle @@ -64,4 +64,4 @@ def triangle(points,depth): depth-1) -triangle(points,int(sys.argv[1])) \ No newline at end of file +triangle(points,int(sys.argv[1])) From 56513cb21f759ac26b31ac1edcb45d886a97f715 Mon Sep 17 00:00:00 2001 From: Junth Basnet <25685098+Junth19@users.noreply.github.com> Date: Fri, 10 May 2019 16:48:05 +0545 Subject: [PATCH 07/11] add-binary-exponentiation (#790) --- maths/BinaryExponentiation.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 maths/BinaryExponentiation.py diff --git a/maths/BinaryExponentiation.py b/maths/BinaryExponentiation.py new file mode 100644 index 000000000000..2411cd58a76b --- /dev/null +++ b/maths/BinaryExponentiation.py @@ -0,0 +1,25 @@ +#Author : Junth Basnet +#Time Complexity : O(logn) + +def binary_exponentiation(a, n): + + if (n == 0): + return 1 + + elif (n % 2 == 1): + return binary_exponentiation(a, n - 1) * a + + else: + b = binary_exponentiation(a, n / 2) + return b * b + + +try: + base = int(input('Enter Base : ')) + power = int(input("Enter Power : ")) +except ValueError: + print ("Invalid literal for integer") + +result = binary_exponentiation(base, power) +print("{}^({}) : {}".format(base, power, result)) + From 36828b106f7905ecc0c0776e40c99929728a91a9 Mon Sep 17 00:00:00 2001 From: Julien Castiaux Date: Sat, 11 May 2019 13:20:25 +0200 Subject: [PATCH 08/11] [FIX] maths/PrimeCheck (#796) Current implementation is buggy and hard to read. * Negative values were raising a TypeError due to `math.sqrt` * 1 was considered prime, it is not. * 2 was considered not prime, it is. The implementation has been corrected to fix the bugs and to enhance readability. A docstring has been added with the definition of a prime number. A complete test suite has been written, it tests the 10 first primes, a negative value, 0, 1 and some not prime numbers. closes #795 --- maths/PrimeCheck.py | 55 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/maths/PrimeCheck.py b/maths/PrimeCheck.py index e0c51d77a038..8c5c181689dd 100644 --- a/maths/PrimeCheck.py +++ b/maths/PrimeCheck.py @@ -1,13 +1,54 @@ import math +import unittest + + def primeCheck(number): - if number % 2 == 0 and number > 2: + """ + A number is prime if it has exactly two dividers: 1 and itself. + """ + if number < 2: + # Negatives, 0 and 1 are not primes return False - return all(number % i for i in range(3, int(math.sqrt(number)) + 1, 2)) + if number < 4: + # 2 and 3 are primes + return True + if number % 2 == 0: + # Even values are not primes + return False + + # Except 2, all primes are odd. If any odd value divide + # the number, then that number is not prime. + odd_numbers = range(3, int(math.sqrt(number)) + 1, 2) + return not any(number % i == 0 for i in odd_numbers) + + +class Test(unittest.TestCase): + def test_primes(self): + self.assertTrue(primeCheck(2)) + self.assertTrue(primeCheck(3)) + self.assertTrue(primeCheck(5)) + self.assertTrue(primeCheck(7)) + self.assertTrue(primeCheck(11)) + self.assertTrue(primeCheck(13)) + self.assertTrue(primeCheck(17)) + self.assertTrue(primeCheck(19)) + self.assertTrue(primeCheck(23)) + self.assertTrue(primeCheck(29)) + + def test_not_primes(self): + self.assertFalse(primeCheck(-19), + "Negative numbers are not prime.") + self.assertFalse(primeCheck(0), + "Zero doesn't have any divider, primes must have two") + self.assertFalse(primeCheck(1), + "One just have 1 divider, primes must have two.") + self.assertFalse(primeCheck(2 * 2)) + self.assertFalse(primeCheck(2 * 3)) + self.assertFalse(primeCheck(3 * 3)) + self.assertFalse(primeCheck(3 * 5)) + self.assertFalse(primeCheck(3 * 5 * 7)) -def main(): - print(primeCheck(37)) - print(primeCheck(100)) - print(primeCheck(77)) if __name__ == '__main__': - main() + unittest.main() + From d8badcc6d5568e3ed8b060305f6d02e74019f1a4 Mon Sep 17 00:00:00 2001 From: Anup Kumar Panwar <1anuppanwar@gmail.com> Date: Sun, 12 May 2019 09:10:56 +0530 Subject: [PATCH 09/11] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1e43deb6bdef..9b61f1b63287 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # The Algorithms - Python -[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=JP3BLXA6KMDGW) +[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/TheAlgorithms/100) ### All algorithms implemented in Python (for education) From 3f7bec6c00c089490c8b5d38686373ca6e1ea97b Mon Sep 17 00:00:00 2001 From: Bhushan Borole <37565807+bhushan-borole@users.noreply.github.com> Date: Sun, 12 May 2019 17:16:47 +0530 Subject: [PATCH 10/11] Added page-rank algorithm implementation (#780) * Added page-rank algorithm implementation * changed init variables --- Graphs/pagerank.py | 72 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 Graphs/pagerank.py diff --git a/Graphs/pagerank.py b/Graphs/pagerank.py new file mode 100644 index 000000000000..59f15a99e6b2 --- /dev/null +++ b/Graphs/pagerank.py @@ -0,0 +1,72 @@ +''' +Author: https://github.com/bhushan-borole +''' +''' +The input graph for the algorithm is: + + A B C +A 0 1 1 +B 0 0 1 +C 1 0 0 + +''' + +graph = [[0, 1, 1], + [0, 0, 1], + [1, 0, 0]] + + +class Node: + def __init__(self, name): + self.name = name + self.inbound = [] + self.outbound = [] + + def add_inbound(self, node): + self.inbound.append(node) + + def add_outbound(self, node): + self.outbound.append(node) + + def __repr__(self): + return 'Node {}: Inbound: {} ; Outbound: {}'.format(self.name, + self.inbound, + self.outbound) + + +def page_rank(nodes, limit=3, d=0.85): + ranks = {} + for node in nodes: + ranks[node.name] = 1 + + outbounds = {} + for node in nodes: + outbounds[node.name] = len(node.outbound) + + for i in range(limit): + print("======= Iteration {} =======".format(i+1)) + for j, node in enumerate(nodes): + ranks[node.name] = (1 - d) + d * sum([ ranks[ib]/outbounds[ib] for ib in node.inbound ]) + print(ranks) + + +def main(): + names = list(input('Enter Names of the Nodes: ').split()) + + nodes = [Node(name) for name in names] + + for ri, row in enumerate(graph): + for ci, col in enumerate(row): + if col == 1: + nodes[ci].add_inbound(names[ri]) + nodes[ri].add_outbound(names[ci]) + + print("======= Nodes =======") + for node in nodes: + print(node) + + page_rank(nodes) + + +if __name__ == '__main__': + main() \ No newline at end of file From 70bb6b2f18bec6cadca052d96e526d014d18ff32 Mon Sep 17 00:00:00 2001 From: Ravi Patel Date: Mon, 13 May 2019 01:15:27 -0400 Subject: [PATCH 11/11] Added Huffman Coding Algorithm (#798) --- compression/huffman.py | 87 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 compression/huffman.py diff --git a/compression/huffman.py b/compression/huffman.py new file mode 100644 index 000000000000..b6238b66e9fd --- /dev/null +++ b/compression/huffman.py @@ -0,0 +1,87 @@ +import sys + +class Letter: + def __init__(self, letter, freq): + self.letter = letter + self.freq = freq + self.bitstring = "" + + def __repr__(self): + return f'{self.letter}:{self.freq}' + + +class TreeNode: + def __init__(self, freq, left, right): + self.freq = freq + self.left = left + self.right = right + + +def parse_file(file_path): + """ + Read the file and build a dict of all letters and their + frequences, then convert the dict into a list of Letters. + """ + chars = {} + with open(file_path) as f: + while True: + c = f.read(1) + if not c: + break + chars[c] = chars[c] + 1 if c in chars.keys() else 1 + letters = [] + for char, freq in chars.items(): + letter = Letter(char, freq) + letters.append(letter) + letters.sort(key=lambda l: l.freq) + return letters + +def build_tree(letters): + """ + Run through the list of Letters and build the min heap + for the Huffman Tree. + """ + while len(letters) > 1: + left = letters.pop(0) + right = letters.pop(0) + total_freq = left.freq + right.freq + node = TreeNode(total_freq, left, right) + letters.append(node) + letters.sort(key=lambda l: l.freq) + return letters[0] + +def traverse_tree(root, bitstring): + """ + Recursively traverse the Huffman Tree to set each + Letter's bitstring, and return the list of Letters + """ + if type(root) is Letter: + root.bitstring = bitstring + return [root] + letters = [] + letters += traverse_tree(root.left, bitstring + "0") + letters += traverse_tree(root.right, bitstring + "1") + return letters + +def huffman(file_path): + """ + Parse the file, build the tree, then run through the file + again, using the list of Letters to find and print out the + bitstring for each letter. + """ + letters_list = parse_file(file_path) + root = build_tree(letters_list) + letters = traverse_tree(root, "") + print(f'Huffman Coding of {file_path}: ') + with open(file_path) as f: + while True: + c = f.read(1) + if not c: + break + le = list(filter(lambda l: l.letter == c, letters))[0] + print(le.bitstring, end=" ") + print() + +if __name__ == "__main__": + # pass the file path to the huffman function + huffman(sys.argv[1])