From 2a513f02c2688b15b1feed64d02c7b2476e4f594 Mon Sep 17 00:00:00 2001 From: "mahbubur.rahman" Date: Fri, 19 Jul 2019 11:59:37 +0900 Subject: [PATCH 1/6] Added matrix exponentiation approach for finding fibonacci number. * Implemented the way of finding nth fibonacci. * Complexity is about O(log(n)*8) --- ..._fibonnacci_using_matrix_exponentiation.py | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 matrix/nth_fibonnacci_using_matrix_exponentiation.py diff --git a/matrix/nth_fibonnacci_using_matrix_exponentiation.py b/matrix/nth_fibonnacci_using_matrix_exponentiation.py new file mode 100644 index 000000000000..5072da8f8333 --- /dev/null +++ b/matrix/nth_fibonnacci_using_matrix_exponentiation.py @@ -0,0 +1,98 @@ +""" +Implementation of finding nth fibonacci number using matrix exponentiation. +Time Complexity is about O(log(n)*8) +As we know + f[n] = f[n-1] + f[n-1] +Converting to matrix, + [f(n),f(n-1)] = [[1,1],[1,0]] * [f(n-1),f(n-2)] +-> [f(n),f(n-1)] = [[1,1],[1,0]]^2 * [f(n-2),f(n-3)] + ... + ... +-> [f(n),f(n-1)] = [[1,1],[1,0]]^(n-1) * [f(1),f(0)] + +So we just need the n times multiplication of the matrix [1,1],[1,0]]. +We can decrease the n times multiplication by following the divide and conquer approach + +""" +from __future__ import print_function + + +def multiply(matrix_a, matrix_b): + matrix_c = [] + n = len(matrix_a) + for i in range(n): + list_1 = [] + for j in range(n): + val = 0 + for k in range(n): + val = val + matrix_a[i][k] * matrix_b[k][j] + list_1.append(val) + matrix_c.append(list_1) + return matrix_c + + +def identity(n): + return [[int(row == column) for column in range(n)] for row in range(n)] + + +def zerro(n): + return [[int(row == column) for column in range(n)] for row in range(n)] + + +def nth_fibonacci(n): + if n <= 1: + return n + res_matrix = identity(2) + fibonacci_matrix = [[1, 1], [1, 0]] + n = n - 1 + while n > 0: + if n % 2 == 1: + res_matrix = multiply(res_matrix, fibonacci_matrix) + fibonacci_matrix = multiply(fibonacci_matrix, fibonacci_matrix) + n = int(n / 2) + return res_matrix[0][0] + + +def nth_fibonnaci_test(n): + if n <= 1: + return n + fib0 = 0 + fib1 = 1 + for i in range(2, n + 1): + fib0, fib1 = fib1, fib0 + fib1 + return fib1 + + +def main(): + print( + "0th fibonnacsi number using matrix exponentiation is %s and using bruteforce is %s \n" + % (nth_fibonacci(0), nth_fibonnaci_test(0)) + ) + print( + "1st fibonnacsi number using matrix exponentiation is %s and using bruteforce is %s \n" + % (nth_fibonacci(1), nth_fibonnaci_test(1)) + ) + print( + "2nd fibonnacsi number using matrix exponentiation is %s and using bruteforce is %s \n" + % (nth_fibonacci(2), nth_fibonnaci_test(2)) + ) + print( + "3rd fibonnacsi number using matrix exponentiation is %s and using bruteforce is %s \n" + % (nth_fibonacci(3), nth_fibonnaci_test(3)) + ) + print( + "10th fibonnacsi number using matrix exponentiation is %s and using bruteforce is %s \n" + % (nth_fibonacci(10), nth_fibonnaci_test(10)) + ) + print( + "100th fibonnacsi number using matrix exponentiation is %s and using bruteforce is %s \n" + % (nth_fibonacci(100), nth_fibonnaci_test(100)) + ) + print( + "1000th fibonnacsi number using matrix exponentiation is %s and using bruteforce is %s \n" + % (nth_fibonacci(1000), nth_fibonnaci_test(1000)) + ) + + +if __name__ == "__main__": + main() From b159705b6d7b33063bb09af8a6b1397766e8b050 Mon Sep 17 00:00:00 2001 From: "Md. Mahbubur Rahman" Date: Fri, 19 Jul 2019 14:56:39 +0900 Subject: [PATCH 2/6] Updated the matrix exponentiation approach of finding nth fibonacci. - Removed some extra spaces - Added the complexity of bruteforce algorithm - Removed unused function called zerro() - Added some docktest based on request --- ..._fibonacci_using_matrix_exponentiation.py} | 46 ++++++++++--------- 1 file changed, 24 insertions(+), 22 deletions(-) rename matrix/{nth_fibonnacci_using_matrix_exponentiation.py => nth_fibonacci_using_matrix_exponentiation.py} (57%) diff --git a/matrix/nth_fibonnacci_using_matrix_exponentiation.py b/matrix/nth_fibonacci_using_matrix_exponentiation.py similarity index 57% rename from matrix/nth_fibonnacci_using_matrix_exponentiation.py rename to matrix/nth_fibonacci_using_matrix_exponentiation.py index 5072da8f8333..fd9e0cba38a4 100644 --- a/matrix/nth_fibonnacci_using_matrix_exponentiation.py +++ b/matrix/nth_fibonacci_using_matrix_exponentiation.py @@ -1,6 +1,7 @@ """ Implementation of finding nth fibonacci number using matrix exponentiation. -Time Complexity is about O(log(n)*8) +Time Complexity is about O(log(n)*8), where 8 is the complexity of matrix multiplication of size 2 by 2. +And on the other hand complexity of bruteforce solution is O(n). As we know f[n] = f[n-1] + f[n-1] Converting to matrix, @@ -9,9 +10,8 @@ ... ... -> [f(n),f(n-1)] = [[1,1],[1,0]]^(n-1) * [f(1),f(0)] - So we just need the n times multiplication of the matrix [1,1],[1,0]]. -We can decrease the n times multiplication by following the divide and conquer approach +We can decrease the n times multiplication by following the divide and conquer approach. """ from __future__ import print_function @@ -35,11 +35,13 @@ def identity(n): return [[int(row == column) for column in range(n)] for row in range(n)] -def zerro(n): - return [[int(row == column) for column in range(n)] for row in range(n)] - - def nth_fibonacci(n): + """ + >>> nth_fibonacci(100) + 354224848179261915075L + >>> nth_fibonacci(-100) + -100 + """ if n <= 1: return n res_matrix = identity(2) @@ -53,7 +55,7 @@ def nth_fibonacci(n): return res_matrix[0][0] -def nth_fibonnaci_test(n): +def nth_fibonacci_test(n): if n <= 1: return n fib0 = 0 @@ -65,32 +67,32 @@ def nth_fibonnaci_test(n): def main(): print( - "0th fibonnacsi number using matrix exponentiation is %s and using bruteforce is %s \n" - % (nth_fibonacci(0), nth_fibonnaci_test(0)) + "0th fibonacci number using matrix exponentiation is %s and using bruteforce is %s \n" + % (nth_fibonacci(0), nth_fibonacci_test(0)) ) print( - "1st fibonnacsi number using matrix exponentiation is %s and using bruteforce is %s \n" - % (nth_fibonacci(1), nth_fibonnaci_test(1)) + "1st fibonacci number using matrix exponentiation is %s and using bruteforce is %s \n" + % (nth_fibonacci(1), nth_fibonacci_test(1)) ) print( - "2nd fibonnacsi number using matrix exponentiation is %s and using bruteforce is %s \n" - % (nth_fibonacci(2), nth_fibonnaci_test(2)) + "2nd fibonacci number using matrix exponentiation is %s and using bruteforce is %s \n" + % (nth_fibonacci(2), nth_fibonacci_test(2)) ) print( - "3rd fibonnacsi number using matrix exponentiation is %s and using bruteforce is %s \n" - % (nth_fibonacci(3), nth_fibonnaci_test(3)) + "3rd fibonacci number using matrix exponentiation is %s and using bruteforce is %s \n" + % (nth_fibonacci(3), nth_fibonacci_test(3)) ) print( - "10th fibonnacsi number using matrix exponentiation is %s and using bruteforce is %s \n" - % (nth_fibonacci(10), nth_fibonnaci_test(10)) + "10th fibonacci number using matrix exponentiation is %s and using bruteforce is %s \n" + % (nth_fibonacci(10), nth_fibonacci_test(10)) ) print( - "100th fibonnacsi number using matrix exponentiation is %s and using bruteforce is %s \n" - % (nth_fibonacci(100), nth_fibonnaci_test(100)) + "100th fibonacci number using matrix exponentiation is %s and using bruteforce is %s \n" + % (nth_fibonacci(100), nth_fibonacci_test(100)) ) print( - "1000th fibonnacsi number using matrix exponentiation is %s and using bruteforce is %s \n" - % (nth_fibonacci(1000), nth_fibonnaci_test(1000)) + "1000th fibonacci number using matrix exponentiation is %s and using bruteforce is %s \n" + % (nth_fibonacci(1000), nth_fibonacci_test(1000)) ) From 044cca8253a71b958fbbf6601c27fdbfe15d73c2 Mon Sep 17 00:00:00 2001 From: "Md. Mahbubur Rahman" Date: Fri, 19 Jul 2019 15:05:27 +0900 Subject: [PATCH 3/6] Updated the matrix exponentiation approach of finding nth fibonacci. - Removed some extra spaces - Added the complexity of bruteforce algorithm - Removed unused function called zerro() - Added some docktest based on request --- ...h_fibonacci_using_matrix_exponentiation.py | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/matrix/nth_fibonacci_using_matrix_exponentiation.py b/matrix/nth_fibonacci_using_matrix_exponentiation.py index fd9e0cba38a4..2904379ca7d5 100644 --- a/matrix/nth_fibonacci_using_matrix_exponentiation.py +++ b/matrix/nth_fibonacci_using_matrix_exponentiation.py @@ -10,9 +10,8 @@ ... ... -> [f(n),f(n-1)] = [[1,1],[1,0]]^(n-1) * [f(1),f(0)] -So we just need the n times multiplication of the matrix [1,1],[1,0]]. -We can decrease the n times multiplication by following the divide and conquer approach. - +So we just need the n times multiplication of the matrix [1,1],[1,0]]. +We can decrease the n times multiplication by following the divide and conquer approach. """ from __future__ import print_function @@ -35,11 +34,11 @@ def identity(n): return [[int(row == column) for column in range(n)] for row in range(n)] -def nth_fibonacci(n): +def nth_fibonacci_matrix(n): """ - >>> nth_fibonacci(100) - 354224848179261915075L - >>> nth_fibonacci(-100) + >>> nth_fibonacci_matrix(100) + 354224848179261915075 + >>> nth_fibonacci_matrix(-100) -100 """ if n <= 1: @@ -55,7 +54,13 @@ def nth_fibonacci(n): return res_matrix[0][0] -def nth_fibonacci_test(n): +def nth_fibonacci_bruteforce(n): + """ + >>> nth_fibonacci_bruteforce(100) + 354224848179261915075 + >>> nth_fibonacci_bruteforce(-100) + -100 + """ if n <= 1: return n fib0 = 0 @@ -68,31 +73,31 @@ def nth_fibonacci_test(n): def main(): print( "0th fibonacci number using matrix exponentiation is %s and using bruteforce is %s \n" - % (nth_fibonacci(0), nth_fibonacci_test(0)) + % (nth_fibonacci_matrix(0), nth_fibonacci_bruteforce(0)) ) print( "1st fibonacci number using matrix exponentiation is %s and using bruteforce is %s \n" - % (nth_fibonacci(1), nth_fibonacci_test(1)) + % (nth_fibonacci_matrix(1), nth_fibonacci_bruteforce(1)) ) print( "2nd fibonacci number using matrix exponentiation is %s and using bruteforce is %s \n" - % (nth_fibonacci(2), nth_fibonacci_test(2)) + % (nth_fibonacci_matrix(2), nth_fibonacci_bruteforce(2)) ) print( "3rd fibonacci number using matrix exponentiation is %s and using bruteforce is %s \n" - % (nth_fibonacci(3), nth_fibonacci_test(3)) + % (nth_fibonacci_matrix(3), nth_fibonacci_bruteforce(3)) ) print( "10th fibonacci number using matrix exponentiation is %s and using bruteforce is %s \n" - % (nth_fibonacci(10), nth_fibonacci_test(10)) + % (nth_fibonacci_matrix(10), nth_fibonacci_bruteforce(10)) ) print( "100th fibonacci number using matrix exponentiation is %s and using bruteforce is %s \n" - % (nth_fibonacci(100), nth_fibonacci_test(100)) + % (nth_fibonacci_matrix(100), nth_fibonacci_bruteforce(100)) ) print( "1000th fibonacci number using matrix exponentiation is %s and using bruteforce is %s \n" - % (nth_fibonacci(1000), nth_fibonacci_test(1000)) + % (nth_fibonacci_matrix(1000), nth_fibonacci_bruteforce(1000)) ) From 3cb55d57d59da43f536822fabc671ba89d5e2ac1 Mon Sep 17 00:00:00 2001 From: "mahbubur.rahman" Date: Wed, 24 Jul 2019 16:07:39 +0900 Subject: [PATCH 4/6] Updated Rabin Karp algorithm. - Previous solution is based on the hash function of python. - Implemented ruling hash to get the appropriate complexity of rabin karp. --- strings/rabin_karp.py | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/strings/rabin_karp.py b/strings/rabin_karp.py index 04a849266ead..9fae48abd6fd 100644 --- a/strings/rabin_karp.py +++ b/strings/rabin_karp.py @@ -1,6 +1,11 @@ +# Numbers of alphabet which we call base +alphabet_size = 256 +# Modulus to hash a string +modulus = 1000003 + + def rabin_karp(pattern, text): """ - The Rabin-Karp Algorithm for finding a pattern within a piece of text with complexity O(nm), most efficient when it is used with multiple patterns as it is able to check if any of a set of patterns match a section of text in o(1) given the precomputed hashes. @@ -12,22 +17,38 @@ def rabin_karp(pattern, text): 2) Step through the text one character at a time passing a window with the same length as the pattern calculating the hash of the text within the window compare it with the hash of the pattern. Only testing equality if the hashes match - """ p_len = len(pattern) - p_hash = hash(pattern) + t_len = len(text) + if p_len > t_len: + return False + + p_hash = 0 + text_hash = 0 + modulus_power = 1 - for i in range(0, len(text) - (p_len - 1)): + # Calculating the hash of pattern and substring of text + for i in range(p_len): + p_hash = (ord(pattern[i]) + p_hash * alphabet_size) % modulus + text_hash = (ord(text[i]) + text_hash * alphabet_size) % modulus + if i == p_len - 1: + continue + modulus_power = (modulus_power * alphabet_size) % modulus - # written like this t - text_hash = hash(text[i:i + p_len]) - if text_hash == p_hash and \ - text[i:i + p_len] == pattern: + for i in range(0, t_len - p_len + 1): + if text_hash == p_hash and text[i : i + p_len] == pattern: return True + if i == t_len - p_len: + continue + # Calculating the ruling hash + text_hash = ( + (text_hash - ord(text[i]) * modulus_power) * alphabet_size + + ord(text[i + p_len]) + ) % modulus return False -if __name__ == '__main__': +if __name__ == "__main__": # Test 1) pattern = "abc1abc12" text1 = "alskfjaldsabc1abc1abc12k23adsfabcabc" From 73b52b85786fe0a6bff34cc4922f32b7761b25f0 Mon Sep 17 00:00:00 2001 From: "Md. Mahbubur Rahman" Date: Wed, 24 Jul 2019 17:06:10 +0900 Subject: [PATCH 5/6] Updated Rabin Karp algorithm. - Previous solution is based on the hash function of python. - Implemented ruling hash to get the appropriate complexity of rabin karp. --- strings/rabin_karp.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/strings/rabin_karp.py b/strings/rabin_karp.py index 9fae48abd6fd..b97e72292f1a 100644 --- a/strings/rabin_karp.py +++ b/strings/rabin_karp.py @@ -48,7 +48,7 @@ def rabin_karp(pattern, text): return False -if __name__ == "__main__": +def test_rabin_karp(): # Test 1) pattern = "abc1abc12" text1 = "alskfjaldsabc1abc1abc12k23adsfabcabc" @@ -69,3 +69,7 @@ def rabin_karp(pattern, text): pattern = "abcdabcy" text = "abcxabcdabxabcdabcdabcy" assert rabin_karp(pattern, text) + + +if __name__ == "__main__": + test_rabin_karp() From eb8f6e2962fc7974b3d7399652c30175ea61d422 Mon Sep 17 00:00:00 2001 From: "Md. Mahbubur Rahman" Date: Wed, 24 Jul 2019 17:36:20 +0900 Subject: [PATCH 6/6] Implemented ruling hash to appropriate complexity of Rabin Karp Added unit pattern testing --- strings/rabin_karp.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/strings/rabin_karp.py b/strings/rabin_karp.py index b97e72292f1a..7c36f7659e24 100644 --- a/strings/rabin_karp.py +++ b/strings/rabin_karp.py @@ -49,6 +49,10 @@ def rabin_karp(pattern, text): def test_rabin_karp(): + """ + >>> test_rabin_karp() + Success. + """ # Test 1) pattern = "abc1abc12" text1 = "alskfjaldsabc1abc1abc12k23adsfabcabc" @@ -69,6 +73,7 @@ def test_rabin_karp(): pattern = "abcdabcy" text = "abcxabcdabxabcdabcdabcy" assert rabin_karp(pattern, text) + print("Success.") if __name__ == "__main__":