From b3d52d753a851d8ffee4c557bb2918eb018463f9 Mon Sep 17 00:00:00 2001 From: Aaditya Chapagain Date: Tue, 22 Oct 2019 09:22:08 +0545 Subject: [PATCH 001/302] add program to assign unique caps to every person in limited pools of unique caps --- .../dynamic_programming/bit_masking1.py | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 algorithms/dynamic_programming/bit_masking1.py diff --git a/algorithms/dynamic_programming/bit_masking1.py b/algorithms/dynamic_programming/bit_masking1.py new file mode 100644 index 00000000..21c65630 --- /dev/null +++ b/algorithms/dynamic_programming/bit_masking1.py @@ -0,0 +1,98 @@ +""" +Consider the below problems statement. + +There are 100 different types of caps each having a unique id from 1 to 100. Also, +there are ā€˜n’ persons each having a collection of a variable number of caps. +One day all of these persons decide to go in a party wearing a cap but to look unique +they decided that none of them will wear the same type of cap. So, count the total number +of arrangements or ways such that none of them is wearing the same type of cap. + +""" + +#Python program to find number of ways to wear hats +from collections import defaultdict + +class AssignCap: + + # Initialize variables + def __init__(self): + + self.allmask = 0 + + self.total_caps = 100 + + self.caps = defaultdict(list) + + + # Mask is the set of persons, i is the current cap number. + def countWaysUtil(self,dp, mask, cap_no): + + # If all persons are wearing a cap so we + # are done and this is one way so return 1 + if mask == self.allmask: + return 1 + + # If not everyone is wearing a cap and also there are no more + # caps left to process, so there is no way, thus return 0; + if cap_no > self.total_caps: + return 0 + + # If we have already solved this subproblem, return the answer. + if dp[mask][cap_no]!= -1 : + return dp[mask][cap_no] + + # Ways, when we don't include this cap in our arrangement + # or solution set + ways = self.countWaysUtil(dp, mask, cap_no + 1) + + # assign ith cap one by one to all the possible persons + # and recur for remaining caps. + if cap_no in self.caps: + + for ppl in self.caps[cap_no]: + + # if person 'ppl' is already wearing a cap then continue + if mask & (1 << ppl) : continue + + # Else assign him this cap and recur for remaining caps with + # new updated mask vector + ways += self.countWaysUtil(dp, mask | (1 << ppl), cap_no + 1) + + ways = ways % (10**9 + 7) + + # Save the result and return it + dp[mask][cap_no] = ways + + return dp[mask][cap_no] + + + + def countWays(self,N): + + # Reads n lines from standard input for current test case + # create dictionary for cap. cap[i] = list of person having + # cap no i + for ppl in range(N): + + cap_possessed_by_person = map(int, input().strip().split()) + + for i in cap_possessed_by_person: + + self.caps[i].append(ppl) + + # allmask is used to check if all persons + # are included or not, set all n bits as 1 + self.allmask = (1 << N) -1 + + # Initialize all entries in dp as -1 + dp = [[-1 for j in range(self.total_caps + 1)] for i in range(2 ** N)] + + # Call recursive function countWaysUtil + # result will be in dp[0][1] + print (self.countWaysUtil(dp, 0, 1,)) + +#Driver Program +def main(): + No_of_people = int(input()) # number of persons in every test case + + AssignCap().countWays(No_of_people) From 97bb0e5bbc50e8a1a3a566efc32f1600b88f8a84 Mon Sep 17 00:00:00 2001 From: Aaditya Chapagain Date: Tue, 22 Oct 2019 10:34:25 +0545 Subject: [PATCH 002/302] add program to find k palindrome in a string --- .../dynamic_programming/k_palindrome1.py | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 algorithms/dynamic_programming/k_palindrome1.py diff --git a/algorithms/dynamic_programming/k_palindrome1.py b/algorithms/dynamic_programming/k_palindrome1.py new file mode 100644 index 00000000..4c78da79 --- /dev/null +++ b/algorithms/dynamic_programming/k_palindrome1.py @@ -0,0 +1,59 @@ +# code to find if given string +# is K-Palindrome or not + +""" +Explanation + +Process all characters one by one staring from either from left or right sides of both strings. +Let us traverse from the right corner, there are two possibilities for every pair of character being traversed. + +If last characters of two strings are same, we ignore last characters and get count for remaining strings. +So we recur for lengths m-1 and n-1 where m is length of str1 and n is length of str2. +If last characters are not same, we consider remove operation on last character of first string and +last character of second string, recursively compute minimum cost for the operations and take minimum of two values. +Remove last char from str1: Recur for m-1 and n. +Remove last char from str2: Recur for m and n-1. +""" + +# Find if given string +# is K-Palindrome or not +def isKPalRec(str1, str2, m, n): + + # If first string is empty, + # the only option is to remove + # all characters of second string + if not m: return n + + # If second string is empty, + # the only option is to remove + # all characters of first string + if not n: return m + + # If last characters of two strings + # are same, ignore last characters + # and get count for remaining strings. + if str1[m-1] == str2[n-1]: + return isKPalRec(str1, str2, m-1, n-1) + + # If last characters are not same, + # 1. Remove last char from str1 and recur for m-1 and n + # 2. Remove last char from str2 and recur for m and n-1 + # Take minimum of above two operations + res = 1 + min(isKPalRec(str1, str2, m-1, n), # Remove from str1 + (isKPalRec(str1, str2, m, n-1))) # Remove from str2 + + return res + +# Returns true if str is k palindrome. +def isKPal(string, k): + revStr = string[::-1] + l = len(string) + + return (isKPalRec(string, revStr, l, l) <= k * 2) + + +# Driver program +string = "acdcb" +k = 2 + +print("Yes" if isKPal(string, k) else "No") \ No newline at end of file From 8c0b662bc378a0f56aa22bff2542504a6cba5c26 Mon Sep 17 00:00:00 2001 From: Ed Howard Date: Fri, 25 Oct 2019 18:50:50 -0400 Subject: [PATCH 003/302] removed unused self parameter --- algorithms/dynamic_programming/max_subarray.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/algorithms/dynamic_programming/max_subarray.py b/algorithms/dynamic_programming/max_subarray.py index 5a1caa43..422c29c9 100644 --- a/algorithms/dynamic_programming/max_subarray.py +++ b/algorithms/dynamic_programming/max_subarray.py @@ -8,8 +8,8 @@ """ -# Iterative Solution -def max_sub_array(self, arr): +# Iterative Solution - Kadane's algorithm +def max_sub_array(arr): if not arr: return 0 @@ -19,3 +19,8 @@ def max_sub_array(self, arr): max_sum = max(max_sum, cur_sum) return max_sum + + + +print max_sub_array([1,2,-100,3,4]) + From dd2827e79ba184ffa39e8bc25528acc56f5e448d Mon Sep 17 00:00:00 2001 From: Mehar Madnani <41502248+imehar@users.noreply.github.com> Date: Sun, 27 Oct 2019 01:10:00 +0530 Subject: [PATCH 004/302] Solved 'n' number of m-faced dice --- algorithms/dynamic_programming/dice.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 algorithms/dynamic_programming/dice.py diff --git a/algorithms/dynamic_programming/dice.py b/algorithms/dynamic_programming/dice.py new file mode 100644 index 00000000..501e2fa1 --- /dev/null +++ b/algorithms/dynamic_programming/dice.py @@ -0,0 +1,23 @@ +''' +Given n dices each with m faces, numbered from 1 to m, +find the number of ways to get a given sum X. +X is the summation of values on each face when all the dice are thrown. + +''' + +dp = [[-1 for i in range(x+1)] for j in range(n+1)] + +def NumOfWays(m, n, x): + if x == 0 and n == 0: + return 1 + if x < 0 or n == 0: + return 0 + if dp[n][x] != -1: + return dp[n][x] + + ans = 0 + for i in range(1, m + 1): + ans += NumOfWays(m, n - 1, x - i) + + dp[n][x] = ans + return ans From 29e0fb6f12dc261cc4435e9ff30c15c3c6e659de Mon Sep 17 00:00:00 2001 From: northtree Date: Sun, 27 Oct 2019 11:38:51 +1100 Subject: [PATCH 005/302] Find odd number in array --- data_structures/array/find_odd_number.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 data_structures/array/find_odd_number.py diff --git a/data_structures/array/find_odd_number.py b/data_structures/array/find_odd_number.py new file mode 100644 index 00000000..ea97a2a4 --- /dev/null +++ b/data_structures/array/find_odd_number.py @@ -0,0 +1,12 @@ +def find_odd_number(nums): + """ Find one number in array which is not duplicated, + or exsits odd times. + """ + s = 0 + for n in nums: + s ^= n + return s + + +a = [0, 0, 1, 1, 2, 2, 6, 6, 9, 10, 10] +print(find_odd_number(a)) From 2f2373d2cad8724a50021c42e65965ee9fd966ba Mon Sep 17 00:00:00 2001 From: northtree Date: Sun, 27 Oct 2019 12:11:29 +1100 Subject: [PATCH 006/302] Generate random matrix --- data_structures/array/random_matrix.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 data_structures/array/random_matrix.py diff --git a/data_structures/array/random_matrix.py b/data_structures/array/random_matrix.py new file mode 100644 index 00000000..1d2aef59 --- /dev/null +++ b/data_structures/array/random_matrix.py @@ -0,0 +1,24 @@ +def random_matrix(n): + """ Generate random n x n matix without repreated entries in rows or columns. + The entries are integers between 1 and n. + """ + from random import shuffle + + a = list(range(n + 1)) + shuffle(a) + + # Use slicing to left rotate + m = [a[i:] + a[:i] for i in range(n + 1)] + + # Shuffle rows in matrix + shuffle(m) + + # Shuffle cols in matrix (optional) + m = list(map(list, zip(*m))) # Transpose the matrix + shuffle(m) + + return m + + +m = random_matrix(9) +print('\n'.join(map(str, m))) From 405a0eba2f2ac3f598388afb0446d3621afa1f36 Mon Sep 17 00:00:00 2001 From: northtree Date: Sun, 27 Oct 2019 12:12:49 +1100 Subject: [PATCH 007/302] Fix typo in desc --- data_structures/array/random_matrix.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/array/random_matrix.py b/data_structures/array/random_matrix.py index 1d2aef59..33017c51 100644 --- a/data_structures/array/random_matrix.py +++ b/data_structures/array/random_matrix.py @@ -1,5 +1,5 @@ def random_matrix(n): - """ Generate random n x n matix without repreated entries in rows or columns. + """ Generate random n x n matrix without repeated entries in rows or columns. The entries are integers between 1 and n. """ from random import shuffle From 19ffc10a6185f03f7f2689270a0c7fd49b7a9e26 Mon Sep 17 00:00:00 2001 From: shreyas1599 Date: Sun, 27 Oct 2019 08:47:04 +0530 Subject: [PATCH 008/302] Update sumofdigits.py fixed pep8 issues and wrapped code in a function --- algorithms/math/sumofdigits.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/algorithms/math/sumofdigits.py b/algorithms/math/sumofdigits.py index 62ba2177..8dd9040c 100644 --- a/algorithms/math/sumofdigits.py +++ b/algorithms/math/sumofdigits.py @@ -1,8 +1,11 @@ -#This is to find the sum of digits of a number untill it is a single digit -n=int(input()) #here n is the number -if n%9!=0: - print(n%9) -else: - print("9") -#this method reduces time complexity by a factor of n and also without using any loop +# This is to find the sum of digits of a number until it is a single digit + +def sum_of_digits(n): + n = int(input()) # here n is the number + if n % 9 != 0: + print(n % 9) + else: + print("9") + +# This method reduces time complexity by a factor of n and also without using any loop From fc5548595ce344c53209af908b3350862b587e09 Mon Sep 17 00:00:00 2001 From: northtree Date: Sun, 27 Oct 2019 14:51:15 +1100 Subject: [PATCH 009/302] Is rotate string --- data_structures/strings/rotate_string.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 data_structures/strings/rotate_string.py diff --git a/data_structures/strings/rotate_string.py b/data_structures/strings/rotate_string.py new file mode 100644 index 00000000..c4493d40 --- /dev/null +++ b/data_structures/strings/rotate_string.py @@ -0,0 +1,21 @@ +def is_rotate_string(A, B): + """ + Given two strings, A and B. + + A shift on A consists of taking string A and moving the leftmost character to the rightmost position. For example, if A = 'abcde', then it will be 'bcdea' after one shift on A. Return True if and only if A can become B after some number of shifts on A. + + :type A: str + :type B: str + :rtype: bool + """ + len_a = len(A) + len_b = len(B) + if len_a != len_b: + return False + if len_a == 0: + return True + for i in range(len_a): + A = A[-1:] + A[:-1] + if A == B: + return True + return False From 1838fee189227207a91719793a57f234ff2ffb6f Mon Sep 17 00:00:00 2001 From: northtree Date: Sun, 27 Oct 2019 14:51:27 +1100 Subject: [PATCH 010/302] Add entry for rotate_string.py --- data_structures/strings/index.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data_structures/strings/index.md b/data_structures/strings/index.md index 3f7bf484..df56b743 100644 --- a/data_structures/strings/index.md +++ b/data_structures/strings/index.md @@ -3,4 +3,5 @@ * [Check Permutations](check_permutations.py) * [Are Anagrams](are_anagrams.py) * [Adjacent Vowel Pairs](adjacent_vowel_pairs.py) -* [Toggle String](toggle_string.py) \ No newline at end of file +* [Toggle String](toggle_string.py) +* [Is Rotate String](rotate_string.py) From 5484dc7742c7c6aa5d7da4e37676008ef933284f Mon Sep 17 00:00:00 2001 From: northtree Date: Sun, 27 Oct 2019 14:53:18 +1100 Subject: [PATCH 011/302] Add tests for rotate string --- data_structures/strings/rotate_string.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/data_structures/strings/rotate_string.py b/data_structures/strings/rotate_string.py index c4493d40..48edb9d9 100644 --- a/data_structures/strings/rotate_string.py +++ b/data_structures/strings/rotate_string.py @@ -19,3 +19,8 @@ def is_rotate_string(A, B): if A == B: return True return False + + +# Test +print(is_rotate_string('abcde', 'cdeab')) +print(is_rotate_string('abcde', 'abced')) From 523dec5b50eb238031fd71d4bbce7de359381f61 Mon Sep 17 00:00:00 2001 From: northtree Date: Sun, 27 Oct 2019 15:14:43 +1100 Subject: [PATCH 012/302] Check if it is perfect square number --- algorithms/math/perfect_square.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 algorithms/math/perfect_square.py diff --git a/algorithms/math/perfect_square.py b/algorithms/math/perfect_square.py new file mode 100644 index 00000000..40e817bb --- /dev/null +++ b/algorithms/math/perfect_square.py @@ -0,0 +1,21 @@ +def is_perfect_square(num): + """ + Given a positive integer num, write a function which returns True if num is a perfect square else False. + + Note: Do not use any built-in library function such as `sqrt`. + + :type num: int + :rtype: bool + """ + i = 0 + while i * i < num: + i += 1 + if i * i == num: + return True + else: + return False + + +# Test +print(is_perfect_square(16)) +print(is_perfect_square(14)) From 330659ddd40fc2e8c9604fa1d205ab0109d326bf Mon Sep 17 00:00:00 2001 From: northtree Date: Sun, 27 Oct 2019 15:15:00 +1100 Subject: [PATCH 013/302] Add entry for perfect_square.py --- algorithms/math/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/algorithms/math/index.md b/algorithms/math/index.md index a02f7ae0..e84f7095 100644 --- a/algorithms/math/index.md +++ b/algorithms/math/index.md @@ -4,4 +4,5 @@ * [Fibonacci Number](fibonacci_number.py) * [Nth Prime Number](prime.py) * [Sieve of Erastothenes](sieve_of_eratosthenes.py) +* [Perfect Square](perfect_square.py) From 5cec2152fb0fed0d583c878bfe18c530907322da Mon Sep 17 00:00:00 2001 From: Mehar Madnani <41502248+imehar@users.noreply.github.com> Date: Sun, 27 Oct 2019 18:58:28 +0530 Subject: [PATCH 014/302] Changed to follow pep8 --- algorithms/dynamic_programming/dice.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/algorithms/dynamic_programming/dice.py b/algorithms/dynamic_programming/dice.py index 501e2fa1..00129fd3 100644 --- a/algorithms/dynamic_programming/dice.py +++ b/algorithms/dynamic_programming/dice.py @@ -7,17 +7,18 @@ dp = [[-1 for i in range(x+1)] for j in range(n+1)] + def NumOfWays(m, n, x): - if x == 0 and n == 0: - return 1 - if x < 0 or n == 0: - return 0 - if dp[n][x] != -1: - return dp[n][x] + if x == 0 and n == 0: + return 1 + if x < 0 or n == 0: + return 0 + if dp[n][x] != -1: + return dp[n][x] - ans = 0 - for i in range(1, m + 1): - ans += NumOfWays(m, n - 1, x - i) + ans = 0 + for i in range(1, m + 1): + ans += NumOfWays(m, n - 1, x - i) - dp[n][x] = ans - return ans + dp[n][x] = ans + return ans From 6fa80554fa987a09cc6993bc14afa3a3cfb58136 Mon Sep 17 00:00:00 2001 From: quizzicaltrains <56100477+quizzicaltrains@users.noreply.github.com> Date: Sun, 27 Oct 2019 15:36:06 -0700 Subject: [PATCH 015/302] Create topological_sort.py Implementation of topological sort --- algorithms/graph/topological_sort.py | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 algorithms/graph/topological_sort.py diff --git a/algorithms/graph/topological_sort.py b/algorithms/graph/topological_sort.py new file mode 100644 index 00000000..ea214d0d --- /dev/null +++ b/algorithms/graph/topological_sort.py @@ -0,0 +1,33 @@ +from collections import defaultdict + + +def topological_sort(graph: dict) -> list: + """Provides the topologically sorted nodes of a graph in a list. Takes input as a dictionary, + where the key is a node and the value is a list of the nodes that the key is a source node for.""" + + # Keeps track of the "degree" of a node; once this reaches 0, we push it onto the output. + leading_in = defaultdict(lambda: 0) + + for key, values in graph.items(): + if key not in leading_in.keys(): + leading_in[key] = 0 + for node in values: + leading_in[node] += 1 + + queue = [] + output = [] + + for node, degree in leading_in.items(): + if degree == 0: + queue.append(node) + output.append(node) + + while queue: + node = queue.pop(0) + for destination in graph.get(node, []): + leading_in[destination] -= 1 + if leading_in[destination] == 0: + queue.append(destination) + output.append(destination) + + return output From 82a04b689efcf6202b8c32a3f93320ec7a4859c8 Mon Sep 17 00:00:00 2001 From: Mehar Madnani <41502248+imehar@users.noreply.github.com> Date: Mon, 28 Oct 2019 14:56:16 +0530 Subject: [PATCH 016/302] Changed to snake_case --- algorithms/dynamic_programming/dice.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/algorithms/dynamic_programming/dice.py b/algorithms/dynamic_programming/dice.py index 00129fd3..4c4ec68f 100644 --- a/algorithms/dynamic_programming/dice.py +++ b/algorithms/dynamic_programming/dice.py @@ -8,7 +8,7 @@ dp = [[-1 for i in range(x+1)] for j in range(n+1)] -def NumOfWays(m, n, x): +def num_of_ways(m, n, x): if x == 0 and n == 0: return 1 if x < 0 or n == 0: @@ -18,7 +18,7 @@ def NumOfWays(m, n, x): ans = 0 for i in range(1, m + 1): - ans += NumOfWays(m, n - 1, x - i) + ans += num_of_ways(m, n - 1, x - i) dp[n][x] = ans return ans From 0487d8e17ba12df027b402567fd1344539211a27 Mon Sep 17 00:00:00 2001 From: Nick Date: Tue, 29 Oct 2019 07:33:49 +0200 Subject: [PATCH 017/302] Fixed problematic fibonacci series --- algorithms/math/fibonacci_number.py | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/algorithms/math/fibonacci_number.py b/algorithms/math/fibonacci_number.py index ad58a349..a355f32f 100644 --- a/algorithms/math/fibonacci_number.py +++ b/algorithms/math/fibonacci_number.py @@ -1,26 +1,15 @@ # Program that prints out the fibonacci sequence until a given number -def calc_fib(num): - while len(fib) <= num: - n = len(fib) - fib.append((fib[n-1] + fib[n-2])) - + def main(): - print("Enter the Position of the Number in the Sequence or \'0\' to Quit: ") - num = 0 - fib = list() - fib.append(0) - fib.append(1) + n = int(input("insert number")) + fib = [1, 1] + for i in range(2,n,1): + print(i) + fib.append(fib[i-1]+fib[i-2]) - while True: - num = int(input()) - if(num <= 0): - break + print(fib) - if len(fib) <= num: - calc_fib(num) - print('Fibonacci Number at Position ' + str(num) + ' is: ' + str(fib[num])) - if __name__ == '__main__': main() From fc0946cabc4ecf4bf2bd0ef7f45054d87086bbfd Mon Sep 17 00:00:00 2001 From: shreyas1599 Date: Tue, 29 Oct 2019 15:37:00 +0530 Subject: [PATCH 018/302] fixed pep8 issues --- algorithms/sorting/select_sort.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/algorithms/sorting/select_sort.py b/algorithms/sorting/select_sort.py index 51322430..8ba2cad7 100644 --- a/algorithms/sorting/select_sort.py +++ b/algorithms/sorting/select_sort.py @@ -1,5 +1,5 @@ -def findSmallest(arr): +def find_smallest(arr): smallest = arr[0] smallest_index = 0 @@ -12,15 +12,15 @@ def findSmallest(arr): -def selectionSort(arr): - newArr = [] +def selection_sort(arr): + new_arr = [] for i in range(len(arr)): - smallest = findSmallest(arr) - newArr.append(arr.pop(smallest)) + smallest = find_smallest(arr) + new_arr.append(arr.pop(smallest)) - return newArr + return new_arr array = [100, 5, 72, 41, 80, 1, 99, 36, 27, 78] -print(selectionSort(array)) # [1, 5, 27, 36, 41, 72, 78, 80, 99, 100] \ No newline at end of file +print(selection_sort(array)) # [1, 5, 27, 36, 41, 72, 78, 80, 99, 100] From 103a592e7f42d66238a6b48d688dee8ddd36ae06 Mon Sep 17 00:00:00 2001 From: shreyas1599 Date: Tue, 29 Oct 2019 11:36:44 +0000 Subject: [PATCH 019/302] fix: pep8 issues --- .theia/settings.json | 3 ++ algorithms/sorting/bubble_sort.py | 2 +- algorithms/sorting/merge_sort.py | 52 +++++++++++++++---------------- 3 files changed, 30 insertions(+), 27 deletions(-) create mode 100644 .theia/settings.json diff --git a/.theia/settings.json b/.theia/settings.json new file mode 100644 index 00000000..651011e0 --- /dev/null +++ b/.theia/settings.json @@ -0,0 +1,3 @@ +{ + "editor.autoSave": "on" +} \ No newline at end of file diff --git a/algorithms/sorting/bubble_sort.py b/algorithms/sorting/bubble_sort.py index 781b1f5a..85668cac 100644 --- a/algorithms/sorting/bubble_sort.py +++ b/algorithms/sorting/bubble_sort.py @@ -3,7 +3,7 @@ Best time scenario is when array is already sorted - O(n) ''' -def bubbleSort(array): +def bubble_sort(array): n = len(array) for i in range(n): diff --git a/algorithms/sorting/merge_sort.py b/algorithms/sorting/merge_sort.py index f9eb554c..8dbf1d37 100644 --- a/algorithms/sorting/merge_sort.py +++ b/algorithms/sorting/merge_sort.py @@ -1,49 +1,49 @@ """ High level explanation: -mergeSort is a Divide and conquer algorithm that splits in halves the array and +merge_sort is a Divide and conquer algorithm that splits in halves the array and then builds it back up by merging and sorting at the same time its elements. Time complexity: -mergeSort has a time complexity of O(n log n). +merge_sort has a time complexity of O(n log n). """ -def mergeSort(arr): - if len(arr) >1: - mid = len(arr)//2 #Finding the mid of the array - L = arr[:mid] # Dividing the array elements - R = arr[mid:] # into 2 halves - - mergeSort(L) # Sorting the first half - mergeSort(R) # Sorting the second half - +def merge_sort(arr): + if len(arr) >1: + mid = len(arr)//2 #Finding the mid of the array + L = arr[:mid] # Dividing the array elements + R = arr[mid:] # into 2 halves + + merge_sort(L) # Sorting the first half + merge_sort(R) # Sorting the second half + i = j = k = 0 - - # Copy data to temp arrays L[] and R[] - while i < len(L) and j < len(R): - if L[i] < R[j]: - arr[k] = L[i] + + # Copy data to temp arrays L[] and R[] + while i < len(L) and j < len(R): + if L[i] < R[j]: + arr[k] = L[i] i+=1 - else: - arr[k] = R[j] + else: + arr[k] = R[j] j+=1 k+=1 - - # Checking if any element was left - while i < len(L): - arr[k] = L[i] + + # Checking if any element was left + while i < len(L): + arr[k] = L[i] i+=1 k+=1 - - while j < len(R): - arr[k] = R[j] + + while j < len(R): + arr[k] = R[j] j+=1 k+=1 test_array = [10,30,20,100,40,80,90,210,34] -mergeSort(test_array) +merge_sort(test_array) print(test_array) From 65e88cdacc1f1e10a1938c732d4ec741235251ed Mon Sep 17 00:00:00 2001 From: shreyas1599 Date: Tue, 29 Oct 2019 17:56:20 +0530 Subject: [PATCH 020/302] delete .theia/settings.json --- .theia/settings.json | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 .theia/settings.json diff --git a/.theia/settings.json b/.theia/settings.json deleted file mode 100644 index 651011e0..00000000 --- a/.theia/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "editor.autoSave": "on" -} \ No newline at end of file From 3b52c094cfdf96a548e4e46cd579511877e25b7c Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 30 Oct 2019 16:30:22 +0530 Subject: [PATCH 021/302] Update articles.md --- bookmarks/articles.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bookmarks/articles.md b/bookmarks/articles.md index 16fc7323..8553d9c4 100644 --- a/bookmarks/articles.md +++ b/bookmarks/articles.md @@ -51,3 +51,5 @@ This is a list of articles that may be useful for algorithms and data structures - https://martinfowler.com/articles/serverless.html - https://samnewman.io/patterns/architectural/bff/ + +- https://www.ultravioletsoftware.com/single-post/2017/03/23/An-introduction-into-the-WSGI-ecosystem From 84641d9615890739156ec4e3378d49f5755daf45 Mon Sep 17 00:00:00 2001 From: Tyrone Damasceno Date: Wed, 30 Oct 2019 08:44:40 -0300 Subject: [PATCH 022/302] Add missing files and lexicographically sorting --- algorithms/dynamic_programming/index.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/algorithms/dynamic_programming/index.md b/algorithms/dynamic_programming/index.md index 7bfbcd4c..d411b44b 100644 --- a/algorithms/dynamic_programming/index.md +++ b/algorithms/dynamic_programming/index.md @@ -1,8 +1,11 @@ # Index of dynamic_programming +* [Climbing Stairs](climbing_stairs.py) +* [Coin Change](Coin_Change.py) +* [Dice](dice.py) +* [Edit Distance](edit_distance.py) * [Longest Common Subsequence](longest_common_subsequence.py) -* [Rod Cutting](rod_cutting.py) +* [Longest Palindromic Subsequence](longest_palindromic_subsequence.py) * [Max Subarray](max_subarray.py) +* [Rod Cutting](rod_cutting.py) * [Unique Grid Paths](unique_grid_paths.py) -* [Edit Distance](edit_distance.py) - From 77539cceedfd0199b895a54b5fc82c4366432a5b Mon Sep 17 00:00:00 2001 From: Tyrone Damasceno Date: Wed, 30 Oct 2019 08:47:12 -0300 Subject: [PATCH 023/302] Rename file with snake_case --- .../dynamic_programming/{Coin_Change.py => coin_change.py} | 0 algorithms/dynamic_programming/index.md | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename algorithms/dynamic_programming/{Coin_Change.py => coin_change.py} (100%) diff --git a/algorithms/dynamic_programming/Coin_Change.py b/algorithms/dynamic_programming/coin_change.py similarity index 100% rename from algorithms/dynamic_programming/Coin_Change.py rename to algorithms/dynamic_programming/coin_change.py diff --git a/algorithms/dynamic_programming/index.md b/algorithms/dynamic_programming/index.md index d411b44b..0a50f2c6 100644 --- a/algorithms/dynamic_programming/index.md +++ b/algorithms/dynamic_programming/index.md @@ -1,7 +1,7 @@ # Index of dynamic_programming * [Climbing Stairs](climbing_stairs.py) -* [Coin Change](Coin_Change.py) +* [Coin Change](coin_change.py) * [Dice](dice.py) * [Edit Distance](edit_distance.py) * [Longest Common Subsequence](longest_common_subsequence.py) From 18cb65bbb028139d26842d69b0f248784daea2b5 Mon Sep 17 00:00:00 2001 From: harman Date: Wed, 30 Oct 2019 20:44:03 +0530 Subject: [PATCH 024/302] Added daysofweek.py --- data_structures/array/daysofweek.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 data_structures/array/daysofweek.py diff --git a/data_structures/array/daysofweek.py b/data_structures/array/daysofweek.py new file mode 100644 index 00000000..2b279f23 --- /dev/null +++ b/data_structures/array/daysofweek.py @@ -0,0 +1,18 @@ +''' +Given a date, return the corresponding day of the week for that date. +The input is given as three integers representing the day, month and year respectively. +Return the answer as one of the following values {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}. +The given dates are valid dates between the years 1971 and 2100. + +Example 1: +Input: day = 31, month = 8, year = 2019 +Output: "Saturday" +''' + # :type day: int , :type month: int , :type year: int , :rtype: str + +class Solution(object): + def dayOfTheWeek(self, day, month, year): + day_of_week_map = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"] + t = [ 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 ] + year -= month < 3 + return day_of_week_map[((year + int(year / 4) - int(year / 100) + int(year / 400) + t[month - 1] + day) % 7)] \ No newline at end of file From 4f60f87caec16c7dda1da35cd33aa286167dea71 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 5 Nov 2019 12:08:30 +0530 Subject: [PATCH 025/302] Update misc.md --- bookmarks/misc.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bookmarks/misc.md b/bookmarks/misc.md index de317d49..4bb89d2f 100644 --- a/bookmarks/misc.md +++ b/bookmarks/misc.md @@ -13,3 +13,5 @@ This is a list of misc links that may be useful when learning or researching dat - https://wsvincent.com/ - https://machinelearningmastery.com + +- https://stackoverflow.com/questions/10631326/difference-between-select-into-and-insert-into-from-old-table From 0e726f4822512a55fe58986da5fe1a7e0b238e2a Mon Sep 17 00:00:00 2001 From: aaditya Date: Tue, 5 Nov 2019 22:20:46 +0545 Subject: [PATCH 026/302] update - follow the pep8 coding style --- .../dynamic_programming/bit_masking1.py | 171 +++++++++--------- .../dynamic_programming/k_palindrome1.py | 92 +++++----- 2 files changed, 135 insertions(+), 128 deletions(-) diff --git a/algorithms/dynamic_programming/bit_masking1.py b/algorithms/dynamic_programming/bit_masking1.py index 21c65630..e33c47f1 100644 --- a/algorithms/dynamic_programming/bit_masking1.py +++ b/algorithms/dynamic_programming/bit_masking1.py @@ -9,90 +9,91 @@ """ -#Python program to find number of ways to wear hats -from collections import defaultdict - -class AssignCap: - - # Initialize variables - def __init__(self): - - self.allmask = 0 - - self.total_caps = 100 - - self.caps = defaultdict(list) - - - # Mask is the set of persons, i is the current cap number. - def countWaysUtil(self,dp, mask, cap_no): - - # If all persons are wearing a cap so we - # are done and this is one way so return 1 - if mask == self.allmask: +# Python program to find number of ways to wear hats +from collections import defaultdict + + +class AssignCap: + + # Initialize variables + def __init__(self): + + self.allmask = 0 + + self.total_caps = 100 + + self.caps = defaultdict(list) + + # Mask is the set of persons, i is the current cap number. + def countWaysUtil(self, dp, mask, cap_no): + + # If all persons are wearing a cap so we + # are done and this is one way so return 1 + if mask == self.allmask: return 1 - - # If not everyone is wearing a cap and also there are no more - # caps left to process, so there is no way, thus return 0; - if cap_no > self.total_caps: + + # If not everyone is wearing a cap and also there are no more + # caps left to process, so there is no way, thus return 0; + if cap_no > self.total_caps: return 0 - - # If we have already solved this subproblem, return the answer. - if dp[mask][cap_no]!= -1 : - return dp[mask][cap_no] - - # Ways, when we don't include this cap in our arrangement - # or solution set - ways = self.countWaysUtil(dp, mask, cap_no + 1) - - # assign ith cap one by one to all the possible persons - # and recur for remaining caps. - if cap_no in self.caps: - - for ppl in self.caps[cap_no]: - - # if person 'ppl' is already wearing a cap then continue - if mask & (1 << ppl) : continue - - # Else assign him this cap and recur for remaining caps with - # new updated mask vector - ways += self.countWaysUtil(dp, mask | (1 << ppl), cap_no + 1) - - ways = ways % (10**9 + 7) - - # Save the result and return it - dp[mask][cap_no] = ways - - return dp[mask][cap_no] - - - - def countWays(self,N): - - # Reads n lines from standard input for current test case - # create dictionary for cap. cap[i] = list of person having - # cap no i - for ppl in range(N): - - cap_possessed_by_person = map(int, input().strip().split()) - - for i in cap_possessed_by_person: - - self.caps[i].append(ppl) - - # allmask is used to check if all persons - # are included or not, set all n bits as 1 - self.allmask = (1 << N) -1 - - # Initialize all entries in dp as -1 - dp = [[-1 for j in range(self.total_caps + 1)] for i in range(2 ** N)] - - # Call recursive function countWaysUtil - # result will be in dp[0][1] - print (self.countWaysUtil(dp, 0, 1,)) - -#Driver Program -def main(): - No_of_people = int(input()) # number of persons in every test case - - AssignCap().countWays(No_of_people) + + # If we have already solved this subproblem, return the answer. + if dp[mask][cap_no] != -1: + return dp[mask][cap_no] + + # Ways, when we don't include this cap in our arrangement + # or solution set + ways = self.countWaysUtil(dp, mask, cap_no + 1) + + # assign ith cap one by one to all the possible persons + # and recur for remaining caps. + if cap_no in self.caps: + + for ppl in self.caps[cap_no]: + + # if person 'ppl' is already wearing a cap then continue + if mask & (1 << ppl): + continue + + # Else assign him this cap and recur for remaining caps with + # new updated mask vector + ways += self.countWaysUtil(dp, mask | (1 << ppl), cap_no + 1) + + ways = ways % (10**9 + 7) + + # Save the result and return it + dp[mask][cap_no] = ways + + return dp[mask][cap_no] + + def countWays(self, N): + + # Reads n lines from standard input for current test case + # create dictionary for cap. cap[i] = list of person having + # cap no i + for ppl in range(N): + + cap_possessed_by_person = map(int, input().strip().split()) + + for i in cap_possessed_by_person: + + self.caps[i].append(ppl) + + # allmask is used to check if all persons + # are included or not, set all n bits as 1 + self.allmask = (1 << N) - 1 + + # Initialize all entries in dp as -1 + dp = [[-1 for j in range(self.total_caps + 1)] for i in range(2 ** N)] + + # Call recursive function countWaysUtil + # result will be in dp[0][1] + print(self.countWaysUtil(dp, 0, 1,)) + +# Driver Program + + +def main(): + No_of_people = int(input()) # number of persons in every test case + + AssignCap().countWays(No_of_people) diff --git a/algorithms/dynamic_programming/k_palindrome1.py b/algorithms/dynamic_programming/k_palindrome1.py index 4c78da79..2903f9e8 100644 --- a/algorithms/dynamic_programming/k_palindrome1.py +++ b/algorithms/dynamic_programming/k_palindrome1.py @@ -1,10 +1,10 @@ -# code to find if given string +# code to find if given string # is K-Palindrome or not """ Explanation -Process all characters one by one staring from either from left or right sides of both strings. +Process all characters one by one staring from either from left or right sides of both strings. Let us traverse from the right corner, there are two possibilities for every pair of character being traversed. If last characters of two strings are same, we ignore last characters and get count for remaining strings. @@ -14,46 +14,52 @@ Remove last char from str1: Recur for m-1 and n. Remove last char from str2: Recur for m and n-1. """ - -# Find if given string -# is K-Palindrome or not -def isKPalRec(str1, str2, m, n): - - # If first string is empty, - # the only option is to remove - # all characters of second string - if not m: return n - - # If second string is empty, - # the only option is to remove - # all characters of first string - if not n: return m - - # If last characters of two strings - # are same, ignore last characters - # and get count for remaining strings. - if str1[m-1] == str2[n-1]: - return isKPalRec(str1, str2, m-1, n-1) - - # If last characters are not same, - # 1. Remove last char from str1 and recur for m-1 and n - # 2. Remove last char from str2 and recur for m and n-1 - # Take minimum of above two operations - res = 1 + min(isKPalRec(str1, str2, m-1, n), # Remove from str1 - (isKPalRec(str1, str2, m, n-1))) # Remove from str2 - - return res - -# Returns true if str is k palindrome. -def isKPal(string, k): - revStr = string[::-1] - l = len(string) - - return (isKPalRec(string, revStr, l, l) <= k * 2) - - -# Driver program + +# Find if given string +# is K-Palindrome or not + + +def isKPalRec(str1, str2, m, n): + + # If first string is empty, + # the only option is to remove + # all characters of second string + if not m: + return n + + # If second string is empty, + # the only option is to remove + # all characters of first string + if not n: + return m + + # If last characters of two strings + # are same, ignore last characters + # and get count for remaining strings. + if str1[m - 1] == str2[n - 1]: + return isKPalRec(str1, str2, m - 1, n - 1) + + # If last characters are not same, + # 1. Remove last char from str1 and recur for m-1 and n + # 2. Remove last char from str2 and recur for m and n-1 + # Take minimum of above two operations + res = 1 + min(isKPalRec(str1, str2, m - 1, n), # Remove from str1 + (isKPalRec(str1, str2, m, n - 1))) # Remove from str2 + + return res + +# Returns true if str is k palindrome. + + +def isKPal(string, k): + revStr = string[::-1] + l = len(string) + + return (isKPalRec(string, revStr, l, l) <= k * 2) + + +# Driver program string = "acdcb" k = 2 - -print("Yes" if isKPal(string, k) else "No") \ No newline at end of file + +print("Yes" if isKPal(string, k) else "No") From b05adc1c5cd5c78cc836e647f1137946d6443f5a Mon Sep 17 00:00:00 2001 From: Sameer Khan Date: Sun, 10 Nov 2019 13:26:58 +0530 Subject: [PATCH 027/302] Updated index.md to remove typo Removed an extra square bracket. --- data_structures/bst/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/bst/index.md b/data_structures/bst/index.md index 7e286a69..97a6320f 100644 --- a/data_structures/bst/index.md +++ b/data_structures/bst/index.md @@ -1,6 +1,6 @@ # Index of BST -* [[Deletion](deletion.py) +* [Deletion](deletion.py) * [Sorted Array To BST](sorted_array_to_bst.py) * [Print Left Node](print_left_node.py) * [Diameter](diameter.py) From d7b52a01af17e0a592b54bb906c210bc3acad53b Mon Sep 17 00:00:00 2001 From: aaditya Date: Wed, 13 Nov 2019 13:50:34 +0545 Subject: [PATCH 028/302] convert camelCase fucntion defination into function defination seperated by underscore --- algorithms/dynamic_programming/bit_masking1.py | 12 ++++++------ algorithms/dynamic_programming/k_palindrome1.py | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/algorithms/dynamic_programming/bit_masking1.py b/algorithms/dynamic_programming/bit_masking1.py index e33c47f1..b5e3de9b 100644 --- a/algorithms/dynamic_programming/bit_masking1.py +++ b/algorithms/dynamic_programming/bit_masking1.py @@ -25,7 +25,7 @@ def __init__(self): self.caps = defaultdict(list) # Mask is the set of persons, i is the current cap number. - def countWaysUtil(self, dp, mask, cap_no): + def count_ways_util(self, dp, mask, cap_no): # If all persons are wearing a cap so we # are done and this is one way so return 1 @@ -43,7 +43,7 @@ def countWaysUtil(self, dp, mask, cap_no): # Ways, when we don't include this cap in our arrangement # or solution set - ways = self.countWaysUtil(dp, mask, cap_no + 1) + ways = self.count_ways_util(dp, mask, cap_no + 1) # assign ith cap one by one to all the possible persons # and recur for remaining caps. @@ -57,7 +57,7 @@ def countWaysUtil(self, dp, mask, cap_no): # Else assign him this cap and recur for remaining caps with # new updated mask vector - ways += self.countWaysUtil(dp, mask | (1 << ppl), cap_no + 1) + ways += self.count_ways_util(dp, mask | (1 << ppl), cap_no + 1) ways = ways % (10**9 + 7) @@ -66,7 +66,7 @@ def countWaysUtil(self, dp, mask, cap_no): return dp[mask][cap_no] - def countWays(self, N): + def count_ways(self, N): # Reads n lines from standard input for current test case # create dictionary for cap. cap[i] = list of person having @@ -88,7 +88,7 @@ def countWays(self, N): # Call recursive function countWaysUtil # result will be in dp[0][1] - print(self.countWaysUtil(dp, 0, 1,)) + print(self.count_ways_util(dp, 0, 1,)) # Driver Program @@ -96,4 +96,4 @@ def countWays(self, N): def main(): No_of_people = int(input()) # number of persons in every test case - AssignCap().countWays(No_of_people) + AssignCap().count_ways(No_of_people) diff --git a/algorithms/dynamic_programming/k_palindrome1.py b/algorithms/dynamic_programming/k_palindrome1.py index 2903f9e8..8c69e5af 100644 --- a/algorithms/dynamic_programming/k_palindrome1.py +++ b/algorithms/dynamic_programming/k_palindrome1.py @@ -19,7 +19,7 @@ # is K-Palindrome or not -def isKPalRec(str1, str2, m, n): +def is_kpalrec(str1, str2, m, n): # If first string is empty, # the only option is to remove @@ -43,23 +43,23 @@ def isKPalRec(str1, str2, m, n): # 1. Remove last char from str1 and recur for m-1 and n # 2. Remove last char from str2 and recur for m and n-1 # Take minimum of above two operations - res = 1 + min(isKPalRec(str1, str2, m - 1, n), # Remove from str1 - (isKPalRec(str1, str2, m, n - 1))) # Remove from str2 + res = 1 + min(is_kpalrec(str1, str2, m - 1, n), # Remove from str1 + (is_kpalrec(str1, str2, m, n - 1))) # Remove from str2 return res # Returns true if str is k palindrome. -def isKPal(string, k): +def is_kPal(string, k): revStr = string[::-1] l = len(string) - return (isKPalRec(string, revStr, l, l) <= k * 2) + return (is_kpalrec(string, revStr, l, l) <= k * 2) # Driver program string = "acdcb" k = 2 -print("Yes" if isKPal(string, k) else "No") +print("Yes" if is_kPal(string, k) else "No") From 4ae222ff38eb3ec113b54b90db0f5ea84b539dcf Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 19 Nov 2019 10:09:08 +0530 Subject: [PATCH 029/302] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6b18100c..060e92c7 100644 --- a/README.md +++ b/README.md @@ -71,4 +71,4 @@ To follow the guidelines, refer to [Contributing.md](CONTRIBUTING.md) ## :page_facing_up: License -MIT @ Prabhu Pant +[MIT @ Prabhu Pant](LICENSE) From 281080a65bf206cdfcee18dbbf8efe3bcd31570d Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 20 Nov 2019 11:24:07 +0530 Subject: [PATCH 030/302] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 060e92c7..c76377a1 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # Python Data Structures and Algorithms -This repository contains data structures and algorithms concepts and questions in Python. +This repository contains data structures and algorithms concepts and questions userful for interviews in Python. ## :dart: Objective From ae23e275e4054cf925d52ecd1cec1f2bbfb15d9a Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Fri, 22 Nov 2019 12:16:02 +0530 Subject: [PATCH 031/302] Fix count_zeros.py --- data_structures/array/moves_zeros_to_end.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/array/moves_zeros_to_end.py b/data_structures/array/moves_zeros_to_end.py index 5c9509bb..036c5cd8 100644 --- a/data_structures/array/moves_zeros_to_end.py +++ b/data_structures/array/moves_zeros_to_end.py @@ -5,5 +5,5 @@ def move(arr): arr[count] = a count += 1 while count < len(nums): - nums[count] = 0 + arr[count] = 0 count += 1 From 52486d8f985b5c00b80434f4f16a2f5492bcaf17 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Fri, 22 Nov 2019 22:01:07 +0530 Subject: [PATCH 032/302] Added new questions --- data_structures/graphs/DFS.py | 46 ------------ data_structures/graphs/PrimsMST.py | 58 --------------- data_structures/graphs/TopoSort.py | 44 ------------ data_structures/graphs/bfs.py | 28 ++++++++ data_structures/graphs/dfs.py | 24 +++++++ data_structures/graphs/mother_vertex.py | 5 ++ .../linked_list/sum_of_two_numbers.py | 71 +++++++++++++++++++ 7 files changed, 128 insertions(+), 148 deletions(-) delete mode 100644 data_structures/graphs/DFS.py delete mode 100644 data_structures/graphs/PrimsMST.py delete mode 100644 data_structures/graphs/TopoSort.py create mode 100644 data_structures/graphs/bfs.py create mode 100644 data_structures/graphs/dfs.py create mode 100644 data_structures/graphs/mother_vertex.py create mode 100644 data_structures/linked_list/sum_of_two_numbers.py diff --git a/data_structures/graphs/DFS.py b/data_structures/graphs/DFS.py deleted file mode 100644 index cc133a1f..00000000 --- a/data_structures/graphs/DFS.py +++ /dev/null @@ -1,46 +0,0 @@ -# An Iterative DFS solution. -class Graph: - def __init__(self, V): - self.V = V - self.adj = [[] for i in range(V)] - - def add_edge(self, v, w): - self.adj[v].append(w) - - def DFS_util(self, s, visited): - - stack = [] - - stack.append(s) - - while (len(stack) != 0): - - s = stack.pop() - - if (not visited[s]): - print(s, end=" ") - visited[s] = True - - i = 0 - while i < len(self.adj[s]): - if (not visited[self.adj[s][i]]): - stack.append(self.adj[s][i]) - i += 1 - - def DFS(self): - visited = [False] * self.V - for i in range(self.V): - if (not visited[i]): - self.DFS_util(i, visited) - - -if __name__ == '__main__': - - g = Graph(5) - g.add_edge(1, 0) - g.add_edge(2, 1) - g.add_edge(3, 4) - g.add_edge(4, 0) - - print("Following is Depth First Traversal") - g.DFS() diff --git a/data_structures/graphs/PrimsMST.py b/data_structures/graphs/PrimsMST.py deleted file mode 100644 index b0156210..00000000 --- a/data_structures/graphs/PrimsMST.py +++ /dev/null @@ -1,58 +0,0 @@ -# Uses adjacency matrix representation of graph to calculate Minimum -# Spanning Tree - -import sys - - -class Graph(): - - def __init__(self, vertices): - self.V = vertices - self.graph = [[0 for column in range(vertices)] - for row in range(vertices)] - - # Function to print generated MST - def print_MST(self, parent): - print("Edge \t Weight") - for i in range(1, self.V): - print(parent[i], "-", i, "\t", self.graph[i][parent[i]]) - - # Function to find vertex with min. distance from set of vertices - #not included in MST - def min_value(self, key, MSTSet): - minval = sys.maxsize - - for v in range(self.V): - if (key[v] < minval) and (MSTSet[v] == False): - minval = key[v] - min_index = v - return min_index - - # Function to construct Prim's MST - def MST(self): - key = [sys.maxsize] * self.V - parent = [None] * self.V - key[0] = 0 - MSTSet = [False] * self.V - parent[0] = -1 - - for j in range(self.V): - u = self.min_value(key, MSTSet) - MSTSet[u] = True - - for v in range(self.V): - if (self.graph[u][v] > 0) and (MSTSet[v] == - False) and (key[v] > self.graph[u][v]): - key[v] = self.graph[u][v] - parent[v] = u - - self.print_MST(parent) - - -g = Graph(4) -g.graph = [[0, 2, 0, 6], - [2, 0, 3, 8], - [0, 3, 0, 0], - [6, 8, 0, 0]] - -g.MST() diff --git a/data_structures/graphs/TopoSort.py b/data_structures/graphs/TopoSort.py deleted file mode 100644 index 4cb5dccb..00000000 --- a/data_structures/graphs/TopoSort.py +++ /dev/null @@ -1,44 +0,0 @@ -# Topological sorting of Directed Acyclic Graph -from collections import defaultdict - - -class Graph: - def __init__(self, vertices): - self.graph = defaultdict(list) - self.V = vertices - - def add_edge(self, u, v): - self.graph[u].append(v) - - def topological_sort_util(self, v, visited, stack): - - visited[v] = True - - for i in self.graph[v]: - if not visited[i]: - self.topological_sort_util(i, visited, stack) - - stack.insert(0, v) - - # Topological sort function - def topological_sort(self): - visited = [False] * self.V - stack = [] - - for i in range(self.V): - if (visited[i] == False): - self.topological_sort_util(i, visited, stack) - - print(stack) - - -g = Graph(6) -g.add_edge(5, 2) -g.add_edge(5, 0) -g.add_edge(4, 0) -g.add_edge(4, 1) -g.add_edge(2, 3) -g.add_edge(3, 1) - -print("One possible Topological Sort of the graph is:") -g.topological_sort() diff --git a/data_structures/graphs/bfs.py b/data_structures/graphs/bfs.py new file mode 100644 index 00000000..72a0fff6 --- /dev/null +++ b/data_structures/graphs/bfs.py @@ -0,0 +1,28 @@ +from collections import defaultdict + +class Graph: + + def __init__(self): + self.graph = defaultdict(list) + + + def add_edge(self, u, v): + self.graph[u].append(v) + + + def bfs(self, s): + visited = [False] * len(self.graph) + + queue = [] + + queue.append(s) + visited[s] = True + + while queue: + s = queue.pop(0) + print(s, end=' ') + + for i in self.graph[s]: + if visited[i] == False: + queue.append(i) + visited[i] = True diff --git a/data_structures/graphs/dfs.py b/data_structures/graphs/dfs.py new file mode 100644 index 00000000..b6608f2b --- /dev/null +++ b/data_structures/graphs/dfs.py @@ -0,0 +1,24 @@ +from collections import defaultdict + +class Graph: + + def __init__(self): + self.graph = defaultdict(list) + + + def add_edge(self, u, v): + self.graph[u].append[v] + + + def dfs_util(self, v, visited): + visited[v] = True + print(v, end=' ') + + for i in self.graph[v]: + if visited[i] == False: + self.dfs_util(i, visited) + + + def dfs(self, v): + visited = [False] * (len(self.graph)) + self.dfs_util(v, visited) diff --git a/data_structures/graphs/mother_vertex.py b/data_structures/graphs/mother_vertex.py new file mode 100644 index 00000000..bc996c78 --- /dev/null +++ b/data_structures/graphs/mother_vertex.py @@ -0,0 +1,5 @@ +# A mother vertex is a vertex such that all other vertices +# can be reached by a path from this vertex + + + diff --git a/data_structures/linked_list/sum_of_two_numbers.py b/data_structures/linked_list/sum_of_two_numbers.py new file mode 100644 index 00000000..2f0ea65a --- /dev/null +++ b/data_structures/linked_list/sum_of_two_numbers.py @@ -0,0 +1,71 @@ +class Node(): + + def __init__(self, val): + self.val = val + self.next = None + + +def push(head, data): + node = Node(data) + curr = head + while curr.next: + curr = curr.next + curr.next = node + + +def print_list(head): + curr = head + while curr: + print(curr.val, end=' ') + curr = curr.next + + +def sum_numbers(head1, head2): + carry = 0 + prev = None + res = None + while head1 is not None or head2 is not None: + data1 = 0 if head1 is None else head1.val + data2 = 0 if head2 is None else head2.val + s = carry + data1 + data2 + carry = 1 if s >= 10 else 0 + s = s if s < 10 else s % 10 + + temp = Node(s) + + # if this is the first node, make it head + if res is None: + res = temp + else: + prev.next = temp + + prev = temp + + # move pointers ahead + if head1 is not None: + head1 = head1.next + if head2 is not None: + head2 = head2.next + + if carry > 0: + temp.next = Node(carry) + + return res + + + + +head1 = Node(1) +push(head1, 2) +push(head1, 3) +push(head1, 4) +print_list(head1) +print() +head2 = Node(5) +push(head2, 2) +push(head2, 1) +push(head2, 3) +print_list(head2) +print() +summmed_list = sum_numbers(head1, head2) +print_list(summmed_list) From 216e3dc078b0291d0f11ab4b18400fdb6c90245b Mon Sep 17 00:00:00 2001 From: vernalhav Date: Sat, 23 Nov 2019 12:15:33 -0300 Subject: [PATCH 033/302] Added LIS to DP --- .../longest_increasing_subsequence.py | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 algorithms/dynamic_programming/longest_increasing_subsequence.py diff --git a/algorithms/dynamic_programming/longest_increasing_subsequence.py b/algorithms/dynamic_programming/longest_increasing_subsequence.py new file mode 100644 index 00000000..30978c2f --- /dev/null +++ b/algorithms/dynamic_programming/longest_increasing_subsequence.py @@ -0,0 +1,84 @@ +''' +Problem statement: +given an array of N elements, +return the length of the +longest increasing subsequence +of that array +''' + +def memoize(f): + """ + Generic decorator for + Dynamic Programming + problems + """ + cache = dict() + def memoized_f(*args): + if args in cache: + global hits + hits += 1 + return cache[args] + + cache[args] = f(*args) + return cache[args] + + return memoized_f + + +def lis(s): + """ Return length of LIS in array s """ + + ''' + NOTE: array s will be declared in the superscope + of lis_routine, so it doesn't need to be passed + as argument and subsequently not hashed by @memoize + ''' + + @memoize + def lis_routine(cur_index=0, last_index=-1, cur_length=0): + """ + Return length of the longest increasing + subsequence from array s. + + To use, simply call lis(s). The other + parameters will be used in the + recursion + """ + + if cur_index == len(s): + return cur_length + + ''' + Length of the LIS if we include cur_index + is initialized as -1 because we might not + be able to include it if it is less than + the number at last_index. If last_index is + -1, we can take cur_index, as it will be + the first integer in the possible LIS. + ''' + take = -1 + if last_index == -1 or s[last_index] < s[cur_index]: + take = lis_routine(cur_index + 1, cur_index, cur_length + 1) + + # Length of the LIS if we don't include cur_index + not_take = lis_routine(cur_index + 1, last_index, cur_length) + + # Return the greatest LIS (include cur_index or not) + return max(take, not_take) + + return lis_routine() + + +def main(): + """ Simple test cases """ + t1 = [1, 6, 2, 3, 7, 9, 4, 8, 5] + t2 = [9, 8, 7, 6, 5, 4, 3, 2, 1] + t3 = [-1, -1, -1, -1, -1, -1] + + print('LIS of {}: {}'.format(t1, lis(t1))) # Should be 5 + print('LIS of {}: {}'.format(t2, lis(t2))) # Should be 1 + print('LIS of {}: {}'.format(t3, lis(t3))) # Should be 1 + + +if __name__ == '__main__': + main() \ No newline at end of file From 228a6655572e6da9b7bb3ba10567b68728e1c5bb Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 26 Nov 2019 10:16:10 +0530 Subject: [PATCH 034/302] Delete binary-tree-level-order-traversal.py --- .../binary-tree-level-order-traversal.py | 52 ------------------- 1 file changed, 52 deletions(-) delete mode 100644 data_structures/binary_trees/binary-tree-level-order-traversal.py diff --git a/data_structures/binary_trees/binary-tree-level-order-traversal.py b/data_structures/binary_trees/binary-tree-level-order-traversal.py deleted file mode 100644 index 36d2f319..00000000 --- a/data_structures/binary_trees/binary-tree-level-order-traversal.py +++ /dev/null @@ -1,52 +0,0 @@ -''' -Author : MiKueen -Level : Medium -Problem Statement : Binary Tree Level Order Traversal - -Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level). - -For example: -Given binary tree [3,9,20,null,null,15,7], - 3 - / \ - 9 20 - / \ - 15 7 -return its level order traversal as: -[ - [3], - [9,20], - [15,7] -] -''' - -from collections import deque - -# Definition for a binary tree node. -# class TreeNode(object): -# def __init__(self, x): -# self.val = x -# self.left = None -# self.right = None - -class Solution(object): - def levelOrder(self, root): - """ - :type root: TreeNode - :rtype: List[List[int]] - """ - if not root: - return [] - level, res = deque([root]), [] - while level: - next_level = [] - for i in range(len(level)): - node = level.popleft() - if node.left: - level.append(node.left) - if node.right: - level.append(node.right) - next_level.append(node.val) - res.append(next_level) - return res - \ No newline at end of file From b28593b3ff1f57f1a85787b1b08726e996d3041c Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 26 Nov 2019 10:16:16 +0530 Subject: [PATCH 035/302] Delete flatten-binary-tree-to-linked-list.py --- .../flatten-binary-tree-to-linked-list.py | 59 ------------------- 1 file changed, 59 deletions(-) delete mode 100644 data_structures/binary_trees/flatten-binary-tree-to-linked-list.py diff --git a/data_structures/binary_trees/flatten-binary-tree-to-linked-list.py b/data_structures/binary_trees/flatten-binary-tree-to-linked-list.py deleted file mode 100644 index 1c0362a1..00000000 --- a/data_structures/binary_trees/flatten-binary-tree-to-linked-list.py +++ /dev/null @@ -1,59 +0,0 @@ -''' -Author : MiKueen -Level : Medium -Problem Statement : Flatten Binary Tree to Linked List - -Given a binary tree, flatten it to a linked list in-place. -For example, given the following tree: - 1 - / \ - 2 5 - / \ \ -3 4 6 - -The flattened tree should look like: -1 - \ - 2 - \ - 3 - \ - 4 - \ - 5 - \ - 6 - -Approach : Recursive solution -1. Flatten left subtree -2. Find tail of left subtree -3. Attach tail of left subtree to starting node of right subtree -4. Flatten right subtree -''' - -# Definition for a binary tree node. -# class TreeNode(object): -# def __init__(self, x): -# self.val = x -# self.left = None -# self.right = None - -class Solution(object): - def flatten(self, root): - """ - :type root: TreeNode - :rtype: None Do not return anything, modify root in-place instead. - """ - - if not root: - return - - right = root.right - if root.left: - self.flatten(root.left) - tail = root.left - while tail.right: - tail = tail.right - root.left, root.right, tail.right = None, root.left, right - self.flatten(right) - \ No newline at end of file From fe17999ad719f35a51f9a9270789781a34cd8a8f Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 26 Nov 2019 10:16:22 +0530 Subject: [PATCH 036/302] Delete maximum-depth-of-binary-tree.py --- .../maximum-depth-of-binary-tree.py | 53 ------------------- 1 file changed, 53 deletions(-) delete mode 100644 data_structures/binary_trees/maximum-depth-of-binary-tree.py diff --git a/data_structures/binary_trees/maximum-depth-of-binary-tree.py b/data_structures/binary_trees/maximum-depth-of-binary-tree.py deleted file mode 100644 index cb65fb92..00000000 --- a/data_structures/binary_trees/maximum-depth-of-binary-tree.py +++ /dev/null @@ -1,53 +0,0 @@ -''' -Author : MiKueen -Level : Easy -Problem Statement : Maximum Depth of Binary Tree - -Given a binary tree, find its maximum depth. -The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node. -Note: A leaf is a node with no children. - -Example: -Given binary tree [3,9,20,null,null,15,7], - - 3 - / \ - 9 20 - / \ - 15 7 -return its depth = 3. -''' - -from collections import deque - -# Definition for a binary tree node. -# class TreeNode(object): -# def __init__(self, x): -# self.val = x -# self.left = None -# self.right = None - -class Solution(object): - def maxDepth(self, root): - """ - :type root: TreeNode - :rtype: int - """ - - # BFS solution - if not root: - return 0 - if root.left is None and root.right is None: - return 1 - - depth, level = 0, deque([root]) - while level: - depth += 1 - for i in range(len(level)): - node = level.popleft() - if node.left: - level.append(node.left) - if node.right: - level.append(node.right) - return depth - \ No newline at end of file From fed832176672948fbf6e8319909ceebf69666c22 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 26 Nov 2019 10:16:30 +0530 Subject: [PATCH 037/302] Delete minimum-depth-of-binary-tree.py --- .../minimum-depth-of-binary-tree.py | 55 ------------------- 1 file changed, 55 deletions(-) delete mode 100644 data_structures/binary_trees/minimum-depth-of-binary-tree.py diff --git a/data_structures/binary_trees/minimum-depth-of-binary-tree.py b/data_structures/binary_trees/minimum-depth-of-binary-tree.py deleted file mode 100644 index 2dbbf5df..00000000 --- a/data_structures/binary_trees/minimum-depth-of-binary-tree.py +++ /dev/null @@ -1,55 +0,0 @@ -''' -Author : MiKueen -Level : Easy -Problem Statement : Minimum Depth of Binary Tree - -Given a binary tree, find its minimum depth. -The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node. -Note: A leaf is a node with no children. - -Example: -Given binary tree [3,9,20,null,null,15,7], - - 3 - / \ - 9 20 - / \ - 15 7 -return its minimum depth = 2. -''' - -from collections import deque - -# Definition for a binary tree node. -# class TreeNode(object): -# def __init__(self, x): -# self.val = x -# self.left = None -# self.right = None - -class Solution(object): - def minDepth(self, root): - """ - :type root: TreeNode - :rtype: int - """ - - # BFS solution - if not root: - return 0 - if root.left is None and root.right is None: - return 1 - - depth, level = 1, deque([root]) - while level: - for i in range(len(level)): - node = level.popleft() - if node.left is None and node.right is None: - return depth - if node.left: - level.append(node.left) - if node.right: - level.append(node.right) - depth += 1 - return depth - \ No newline at end of file From 36f3bc9d6de272f948d7d969c62ff7addfa7a600 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 26 Nov 2019 10:16:35 +0530 Subject: [PATCH 038/302] Delete path-sum.py --- data_structures/binary_trees/path-sum.py | 64 ------------------------ 1 file changed, 64 deletions(-) delete mode 100644 data_structures/binary_trees/path-sum.py diff --git a/data_structures/binary_trees/path-sum.py b/data_structures/binary_trees/path-sum.py deleted file mode 100644 index 69bc80be..00000000 --- a/data_structures/binary_trees/path-sum.py +++ /dev/null @@ -1,64 +0,0 @@ -''' -Author : MiKueen -Level : Medium -Problem Statement : Path Sum II - -Given a binary tree and a sum, find all root-to-leaf paths where each path's sum equals the given sum. -Note: A leaf is a node with no children. - -Example: -Given the below binary tree and sum = 22, - 5 - / \ - 4 8 - / / \ - 11 13 4 - / \ / \ -7 2 5 1 -Return: -[ - [5,4,11,2], - [5,8,4,5] -] -''' - -# Definition for a binary tree node. -# class TreeNode(object): -# def __init__(self, x): -# self.val = x -# self.left = None -# self.right = None - -class Solution(object): - def pathSum(self, root, sum): - """ - :type root: TreeNode - :type sum: int - :rtype: List[List[int]] - """ - - # DFS solution - if not root: - return [] - if root.left is None and root.right is None: - if sum == root.val: - return [[root.val]] - else: - return [] - - res = [] - left, right = [], [] - sum -= root.val - - if root.left: - left = self.pathSum(root.left, sum) - if root.right: - right = self.pathSum(root.right, sum) - - for l in left: - res.append([root.val] + l) - for r in right: - res.append([root.val] + r) - - return res - \ No newline at end of file From c6398bce87f6b0e48241cc487b55a0ffadeac2d4 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 26 Nov 2019 10:17:19 +0530 Subject: [PATCH 039/302] Create print_spiral_tree.py --- .../binary_trees/print_spiral_tree.py | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 data_structures/binary_trees/print_spiral_tree.py diff --git a/data_structures/binary_trees/print_spiral_tree.py b/data_structures/binary_trees/print_spiral_tree.py new file mode 100644 index 00000000..463823ee --- /dev/null +++ b/data_structures/binary_trees/print_spiral_tree.py @@ -0,0 +1,34 @@ +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def print_spiral(root): + + s1 = [] + s2 = [] + + s1.append(root) + + while not len(s1) == 0 or not len(s2) == 0: + + while not len(s1) == 0: + temp = s1.pop() + print(temp.data, end=' ') + + if temp.right: + s2.append(temp.right) + if temp.left: + s2.append(temp.left) + + while not len(s2) == 0: + temp = s2.pop() + print(temp.data, end=' ') + + if temp.left: + s1.append(temp.left) + if temp.right: + s1.append(temp.right) From 1450e5fddcb9f1ffc1c1cc0e248f73d759eea1fe Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 26 Nov 2019 10:17:48 +0530 Subject: [PATCH 040/302] Create boundary_traversal.py --- .../binary_trees/boundary_traversal.py | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 data_structures/binary_trees/boundary_traversal.py diff --git a/data_structures/binary_trees/boundary_traversal.py b/data_structures/binary_trees/boundary_traversal.py new file mode 100644 index 00000000..760a6342 --- /dev/null +++ b/data_structures/binary_trees/boundary_traversal.py @@ -0,0 +1,49 @@ +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def print_leaves(root): + if root: + print_leaves(root.left) + + if not root.left and not root.right: + print(root.val, end=' ') + + print_leaves(root.right) + +# To ensure top down, print before calling for other +# To ensure bottom up, print after calling + +def print_left_boundary(root): + if root: + if root.left: + print(root.val, end=' ') + print_left_boundary(root.left) + + elif root.right: + print(root.val, end=' ') + print_left_boundary(root.right) + + +def print_right_boundary(root): + if root: + if root.right: + print_right_boundary(root.right) + print(root.val, end=' ') + + elif root.left: + print_right_boundary(root.left) + print(root.val, end=' ') + + +def print_boundary(root): + if root: + print(root.val) + print_left_boundary(root.left) + print_leaves(root.left) + print_leaves(root.right) + print_right_boundary(root.right) From 82906a3c3791bca6a57e0a246646cb1f9076ec65 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 26 Nov 2019 10:18:10 +0530 Subject: [PATCH 041/302] Create continuous_tree.py --- .../binary_trees/continuous_tree.py | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 data_structures/binary_trees/continuous_tree.py diff --git a/data_structures/binary_trees/continuous_tree.py b/data_structures/binary_trees/continuous_tree.py new file mode 100644 index 00000000..9522d3bf --- /dev/null +++ b/data_structures/binary_trees/continuous_tree.py @@ -0,0 +1,33 @@ +# A continuous tree is such that the absolute difference between two +# adjacent nodes is 1 + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def continuous(root): + # Can be continuous if + # 1. Root is none + # 2. Both left and right STs are none + # 3. If left ST is none, check for right + # 4. If right ST is none, check for left + # 5. Else check for everything + + if root is None: + return True + + if root.left == None and root.right == None: + return True + + if root.left == None: + return (abs(root.val - root.right.val) == 1) and continuous(root.right) + + if root.right == None: + return (abs(root.val - root.left.val) == 1) and continuous(root.left) + + return (abs(root.val - root.right.val) == 1) and (abs(root.left.val - root.val) == 1) and continuous(root.left) and continuous(root.right) + From 189755d58593eb277d56c0f249eb8d8abcef717b Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 26 Nov 2019 10:18:31 +0530 Subject: [PATCH 042/302] Delete symmetric_binary_tree.py --- .../binary_trees/symmetric_binary_tree.py | 37 ------------------- 1 file changed, 37 deletions(-) delete mode 100644 data_structures/binary_trees/symmetric_binary_tree.py diff --git a/data_structures/binary_trees/symmetric_binary_tree.py b/data_structures/binary_trees/symmetric_binary_tree.py deleted file mode 100644 index 8f742715..00000000 --- a/data_structures/binary_trees/symmetric_binary_tree.py +++ /dev/null @@ -1,37 +0,0 @@ -# Definition for a binary tree node. -# class TreeNode: -# def __init__(self, x): -# self.val = x -# self.left = None -# self.right = None - -def isSymmetric(self, root: TreeNode) -> bool: - """ - function to determine if the provided TreeNode is the root - of a symmetric binary tree - """ - - def isMirror(left: TreeNode, right: TreeNode) -> bool: - """ - Utility function to determine if two trees mirror each other. If the root and - all subtrees searched here are mirrors, then the tree as a whole is symmetric - """ - - # Two null values are mirrors - if left is None and right is None: - return True - - # If only one value is null, these trees do not mirror each other - if left is None or right is None: - return False - - # If the values are not equal, the trees do not mirror each other - if left.val != right.val: - return False - - # If left.left mirrors right.right, and left.right mirrors right.left, - # the subtrees mirror each other - return isMirror(left.left, right.right) and isMirror(left.right, right.left) - - return isMirror(root, root) - From 58a4f1a65cbe2531a569080a80ced6f19be6db2c Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 26 Nov 2019 10:18:45 +0530 Subject: [PATCH 043/302] Create foldable_or_symmetric_tree.py --- .../foldable_or_symmetric_tree.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 data_structures/binary_trees/foldable_or_symmetric_tree.py diff --git a/data_structures/binary_trees/foldable_or_symmetric_tree.py b/data_structures/binary_trees/foldable_or_symmetric_tree.py new file mode 100644 index 00000000..0943d62c --- /dev/null +++ b/data_structures/binary_trees/foldable_or_symmetric_tree.py @@ -0,0 +1,31 @@ +# A foldable tree is one such that the mirror of left subtree is equal +# to the right subtree + +class Node: + + def __init__(self, val): + self.val = val + self.right = None + self.left = None + + +def foldable(left, right): + if left is None and right is None: + return True + + if left is None or right is None: + return False + + return left.val == right.val and foldable(left.left, right.right) and foldable(left.right, right.left) + + +root = Node(4) + +root.left = Node(2) +root.left.left = Node(1) + +root.right = Node(2) +root.right.right = Node(10) + +print(foldable(root.left, root.right)) + From 3979b43cf3c7a9a7550a76620e8c90d29add556c Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 26 Nov 2019 10:19:32 +0530 Subject: [PATCH 044/302] Create evaluate_expresssion_tree.py --- .../binary_trees/evaluate_expresssion_tree.py | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 data_structures/binary_trees/evaluate_expresssion_tree.py diff --git a/data_structures/binary_trees/evaluate_expresssion_tree.py b/data_structures/binary_trees/evaluate_expresssion_tree.py new file mode 100644 index 00000000..02bb3066 --- /dev/null +++ b/data_structures/binary_trees/evaluate_expresssion_tree.py @@ -0,0 +1,37 @@ +# In expression tree, the integer values will be at the leaf nodes +# The operands will be all the other internal nodes + +class Node: + + def __init__(self, val): + self.val = val + self.right = None + self.left = None + + +def evaluate(root): + if root is None: + return 0 + + # Check for leaf node + if root.left is None and root.right is None: + return int(root.data) + + # Evaluate left tree + left_sum = evaluate(root.left) + + # Evaluate right tree + right_sum = evaluate(root.right) + + # Check which operator to apply + if root.data == '+': + return left_sum + right_sum + + elif root.data == '-': + return left_sum - right_sum + + elif root.data == '*': + return left_sum * right_sum + + else: + return left_sum / right_sum From f824a7234cda3dc37ee9bc93145b5cd26c3feb80 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 26 Nov 2019 10:29:42 +0530 Subject: [PATCH 045/302] Create diagonal_tree.py --- data_structures/binary_trees/diagonal_tree.py | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 data_structures/binary_trees/diagonal_tree.py diff --git a/data_structures/binary_trees/diagonal_tree.py b/data_structures/binary_trees/diagonal_tree.py new file mode 100644 index 00000000..b8dc2082 --- /dev/null +++ b/data_structures/binary_trees/diagonal_tree.py @@ -0,0 +1,38 @@ +# Print tree in a diagonal form + +# We use the distance of slope from the rightmost slope as key +# in a dict and then proceed + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def diagonal_print_util(root, d, diagonal_map): + if root is None: + return + + try: + diagonal_map[d].append(root.val) + except: + diagonal_map[d] = [root.val] + + # Increase vertical distance if left child + diagonal_print_util(root.left, d+1, diagonal_map) + + # Vertical distance remains same for the right child + diagonal_print_util(root.right, d, diagonal_map) + + +def diagonal_print(root): + diagonal_map = dict() + + diagonal_print_util(root, 0, diagonal_map) + + for i in diagonal_map: + for j in diagonal_map[i]: + print(j, end=" ") + print('') From d6a6ee853102593b7f4cfc9c792f8afd79968b83 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 27 Nov 2019 11:05:44 +0530 Subject: [PATCH 046/302] Create logical_and_tree.py --- .../binary_trees/logical_and_tree.py | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 data_structures/binary_trees/logical_and_tree.py diff --git a/data_structures/binary_trees/logical_and_tree.py b/data_structures/binary_trees/logical_and_tree.py new file mode 100644 index 00000000..1dddf0b0 --- /dev/null +++ b/data_structures/binary_trees/logical_and_tree.py @@ -0,0 +1,21 @@ +# Given a tree that contains only 0s and 1s, convert it into +# a logical AND tree. A logical AND tree is such that +# left_child AND right_child = AND_VALUE + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def convert(root): + if root is None: + return + + convert(root.left) + convert(root.right) + + if root.left and root.right: + root.val = root.left.val & root.right.val From 067ee786086f721ac59991320e6c9d33a62527cc Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 27 Nov 2019 11:06:39 +0530 Subject: [PATCH 047/302] Create flip_tree.py --- data_structures/binary_trees/flip_tree.py | 33 +++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 data_structures/binary_trees/flip_tree.py diff --git a/data_structures/binary_trees/flip_tree.py b/data_structures/binary_trees/flip_tree.py new file mode 100644 index 00000000..20c8cbf5 --- /dev/null +++ b/data_structures/binary_trees/flip_tree.py @@ -0,0 +1,33 @@ +# Flip a tree such like here +# https://www.geeksforgeeks.org/flip-binary-tree/ + +# Flipping subtree algorithm +# 1. root->left->left = root->right +# 2. root->left->right = root +# 3. root->left = NULL +# 4. root->right = NULL + + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def flip_tree(root): + if root is None: + return root + + if root.left is None and root.right is None: + return root + + flipped_root = flip_tree(root.left) + + root.left.left = root.right + root.left.right = root + root.left = None + root.right = None + + return flipped_root From be24a094012bb3940a4ad85c3af192c236bbd0fd Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 27 Nov 2019 11:07:44 +0530 Subject: [PATCH 048/302] Create left_right_to_down_right.py --- .../binary_trees/left_right_to_down_right.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 data_structures/binary_trees/left_right_to_down_right.py diff --git a/data_structures/binary_trees/left_right_to_down_right.py b/data_structures/binary_trees/left_right_to_down_right.py new file mode 100644 index 00000000..c043bcaa --- /dev/null +++ b/data_structures/binary_trees/left_right_to_down_right.py @@ -0,0 +1,24 @@ +# Convert a tree that is a left right representation to a +# down right representation + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.rigt = None + + +def convert(root): + if root is None: + return + + convert(root.left) + convert(root.right) + + if root.left == None: + root.left = root.right + else: + root.left.right = root.right + + root.right = None From 3f4d8540968686e9e47901dde2524eb169725721 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 27 Nov 2019 11:24:45 +0530 Subject: [PATCH 049/302] Create check_if_graph_is_tree.py --- data_structures/binary_trees/check_if_graph_is_tree.py | 1 + 1 file changed, 1 insertion(+) create mode 100644 data_structures/binary_trees/check_if_graph_is_tree.py diff --git a/data_structures/binary_trees/check_if_graph_is_tree.py b/data_structures/binary_trees/check_if_graph_is_tree.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/data_structures/binary_trees/check_if_graph_is_tree.py @@ -0,0 +1 @@ + From b3f2ad9b8c33fb70a4caa2b93aabcabae5c65b10 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 27 Nov 2019 11:39:43 +0530 Subject: [PATCH 050/302] Create check_cousin.py --- data_structures/binary_trees/check_cousin.py | 36 ++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 data_structures/binary_trees/check_cousin.py diff --git a/data_structures/binary_trees/check_cousin.py b/data_structures/binary_trees/check_cousin.py new file mode 100644 index 00000000..6453eed4 --- /dev/null +++ b/data_structures/binary_trees/check_cousin.py @@ -0,0 +1,36 @@ +# Check if two nodes are cousin or not + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def level(root, node, lev): + if not root: + return 0 + if root == node: + return lev + + l = level(root.left, node, lev + 1) + + if not l == 0: + return l + + l = level(root.right, node, lev + 1) + + +def is_sibling(root, a, b): + if root is None: + return 0 + + return ( (root.left == a and root.right == b) or (root.left == b and root.right == a) or is_sibling(root.left, a, b) or is_sibling(root.right, a, b) ) + + +def is_cousin(root, a, b): + if level(root, a, 1) == level(root, b, 1) and not is_sibling(root, a, b): + return True + else: + return False From e2cd86f7aacbdba80c6db753744fb727662c2fab Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 27 Nov 2019 11:44:09 +0530 Subject: [PATCH 051/302] Create check_all_leaves_at_same_level.py --- .../check_all_leaves_at_same_level.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 data_structures/binary_trees/check_all_leaves_at_same_level.py diff --git a/data_structures/binary_trees/check_all_leaves_at_same_level.py b/data_structures/binary_trees/check_all_leaves_at_same_level.py new file mode 100644 index 00000000..a296fb21 --- /dev/null +++ b/data_structures/binary_trees/check_all_leaves_at_same_level.py @@ -0,0 +1,28 @@ +# check if all the leaves of a tree are at the same level + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def check_util(root, level): + if root is None: + return True + + if root.left is None and root.right is None: + if check.leaf_level == 0: + check.leaf_level = level + return True + + return level == check.leaf_level + + return check_util(root.left, level + 1) and check_util(root.right, level + 1) + + +def check(root): + level = 0 + check.leaf_level = 0 + return check_util(root, level) From d352da37987dd58b7a8d9d532577a630966cc961 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 27 Nov 2019 12:50:13 +0530 Subject: [PATCH 052/302] Update articles.md --- bookmarks/articles.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bookmarks/articles.md b/bookmarks/articles.md index 8553d9c4..a2b8e1ca 100644 --- a/bookmarks/articles.md +++ b/bookmarks/articles.md @@ -53,3 +53,5 @@ This is a list of articles that may be useful for algorithms and data structures - https://samnewman.io/patterns/architectural/bff/ - https://www.ultravioletsoftware.com/single-post/2017/03/23/An-introduction-into-the-WSGI-ecosystem + +- https://jwt.io/introduction/ From 5ecbd06a5edd9c6ed9b8f89e2fdae8441a34885b Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 27 Nov 2019 14:40:48 +0530 Subject: [PATCH 053/302] Create check_divide_in_two_halves.pyt --- .../check_divide_in_two_halves.pyt | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 data_structures/binary_trees/check_divide_in_two_halves.pyt diff --git a/data_structures/binary_trees/check_divide_in_two_halves.pyt b/data_structures/binary_trees/check_divide_in_two_halves.pyt new file mode 100644 index 00000000..a51fa90b --- /dev/null +++ b/data_structures/binary_trees/check_divide_in_two_halves.pyt @@ -0,0 +1,33 @@ +# Check if removing an edge of a binary tree can divide +# the tree in two equal halves + +# Count the number of nodes, say n. Then traverse the tree +# in bottom up manner and check if n - s = s + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def count(root): + if not root: + return 0 + return count(root.left) + count(root.right) + 1 + + +def check_util(root, n): + if root == None: + return False + + if count(root) == n - count(root): + return True + + return check_util(root.left, n) || check_util(root.right, n) + + +def check(root): + n = count(rot) + return check_util(root, n) From 1c10fe9288194aa5318bc514b901b08fd72b2e0b Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 27 Nov 2019 14:42:33 +0530 Subject: [PATCH 054/302] Update check_divide_in_two_halves.pyt --- data_structures/binary_trees/check_divide_in_two_halves.pyt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/data_structures/binary_trees/check_divide_in_two_halves.pyt b/data_structures/binary_trees/check_divide_in_two_halves.pyt index a51fa90b..71603f99 100644 --- a/data_structures/binary_trees/check_divide_in_two_halves.pyt +++ b/data_structures/binary_trees/check_divide_in_two_halves.pyt @@ -21,10 +21,12 @@ def count(root): def check_util(root, n): if root == None: return False - + + # Check for root if count(root) == n - count(root): return True - + + # Check for all the other nodes return check_util(root.left, n) || check_util(root.right, n) From e9f7215aa3ea0892f24a220ac8911d549ee89799 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 27 Nov 2019 15:15:45 +0530 Subject: [PATCH 055/302] Update check_divide_in_two_halves.pyt --- data_structures/binary_trees/check_divide_in_two_halves.pyt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/binary_trees/check_divide_in_two_halves.pyt b/data_structures/binary_trees/check_divide_in_two_halves.pyt index 71603f99..df4f71b3 100644 --- a/data_structures/binary_trees/check_divide_in_two_halves.pyt +++ b/data_structures/binary_trees/check_divide_in_two_halves.pyt @@ -27,7 +27,7 @@ def check_util(root, n): return True # Check for all the other nodes - return check_util(root.left, n) || check_util(root.right, n) + return check_util(root.left, n) or check_util(root.right, n) def check(root): From ac94378fe56fd4e85c3f96a89b09b410b38d51cc Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 27 Nov 2019 15:16:31 +0530 Subject: [PATCH 056/302] Create check_perfect_binary_tree.py --- .../binary_trees/check_perfect_binary_tree.py | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 data_structures/binary_trees/check_perfect_binary_tree.py diff --git a/data_structures/binary_trees/check_perfect_binary_tree.py b/data_structures/binary_trees/check_perfect_binary_tree.py new file mode 100644 index 00000000..c3f76281 --- /dev/null +++ b/data_structures/binary_trees/check_perfect_binary_tree.py @@ -0,0 +1,38 @@ +# A binary tree is perfect if all the internal nodes have 2 children and +# all the leaves are at the same level + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +# Returns depth of leftmost leaf +def find_depth(root): + d = 0 + while root: + d += 1 + root = root.left + return d + + +def check_perfect(root, d, level=0): + if not root: + return True + + # If leaf node, then its depth must be same as that of other nodes + if root.left is None and root.right is None: + return d == (level + 1) + + # An internal node with only one child + if root.left is None or root.right is None: + return False + + return check_perfect(root.left, d, level+1) and check_perfect(root.right, d, level+1) + + +def is_perfect(root): + d = find_depth(root) + return check_perfect(root, d) From 5e7b10540e57c014f686db51829406eb85dabcb4 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 27 Nov 2019 15:16:55 +0530 Subject: [PATCH 057/302] Create check_full_binary_tree.py --- .../binary_trees/check_full_binary_tree.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 data_structures/binary_trees/check_full_binary_tree.py diff --git a/data_structures/binary_trees/check_full_binary_tree.py b/data_structures/binary_trees/check_full_binary_tree.py new file mode 100644 index 00000000..23c03f16 --- /dev/null +++ b/data_structures/binary_trees/check_full_binary_tree.py @@ -0,0 +1,22 @@ +# A full binary tree is one which has 0 or 2 children only + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def check(root): + if root is None: + return True + + if root.left is None and root.right is None: + return True + + if root.left is not None and root.right is not None: + return check(root.left) and check(root.right) + + return False + From 0db2d9a5dc2993a4c9e7347e04933af8eb610b11 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 27 Nov 2019 17:02:07 +0530 Subject: [PATCH 058/302] Create identical_trees.py --- .../binary_trees/identical_trees.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 data_structures/binary_trees/identical_trees.py diff --git a/data_structures/binary_trees/identical_trees.py b/data_structures/binary_trees/identical_trees.py new file mode 100644 index 00000000..1d81cef3 --- /dev/null +++ b/data_structures/binary_trees/identical_trees.py @@ -0,0 +1,18 @@ +# Check if two trees are identical or not + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def identical(root1, root2): + if root1 is None and root2 is None: + return True + + if root1 is not None and root2 is not None: + return root1.val == root2. val and identical(root1.left, root2.left) and identical(root1.right, root2.right) + + return False From a3061aa5c60cdac160db49fc07124bd469321375 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 27 Nov 2019 17:06:13 +0530 Subject: [PATCH 059/302] Create check_if_path_exists.py --- .../binary_trees/check_if_path_exists.py | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 data_structures/binary_trees/check_if_path_exists.py diff --git a/data_structures/binary_trees/check_if_path_exists.py b/data_structures/binary_trees/check_if_path_exists.py new file mode 100644 index 00000000..be05f876 --- /dev/null +++ b/data_structures/binary_trees/check_if_path_exists.py @@ -0,0 +1,21 @@ +# Check if a given path exists in a tree + +# Traverse the tree in preorder fashion and keep matching the node +# value to the index of the given path + +class Node: + + def __init__(self, val): + self.val = val + self.right = None + self.left = None + + +def check_path(root, arr, n, index): + if root is None: + return n == 0 + + if root.left == None and root.right == None and root.val == arr[index] and index == n -1: + return True + + return (index < n) and (root.val == arr[index]) and (check_path(root.left, arr, n, index + 1) or check_path(root.right, arr, n, index + 1)) From ed81d7528853cf78f696e60b470169d562b75b4e Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 27 Nov 2019 17:17:32 +0530 Subject: [PATCH 060/302] Create print_nodes_at_k_distance_from_root.py --- .../print_nodes_at_k_distance_from_root.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 data_structures/binary_trees/print_nodes_at_k_distance_from_root.py diff --git a/data_structures/binary_trees/print_nodes_at_k_distance_from_root.py b/data_structures/binary_trees/print_nodes_at_k_distance_from_root.py new file mode 100644 index 00000000..a07e0211 --- /dev/null +++ b/data_structures/binary_trees/print_nodes_at_k_distance_from_root.py @@ -0,0 +1,16 @@ +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def print_k(root, k): + if root is None: + return + if k == 0: + print(root.val) + else: + print_k(root.left, k-1) + print_k(root.right, k-1) From 40edae390dbfb18904d316a6558a53f5e0bc3e93 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 27 Nov 2019 17:24:58 +0530 Subject: [PATCH 061/302] Create print_path_to_a_node.py --- .../binary_trees/print_path_to_a_node.py | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 data_structures/binary_trees/print_path_to_a_node.py diff --git a/data_structures/binary_trees/print_path_to_a_node.py b/data_structures/binary_trees/print_path_to_a_node.py new file mode 100644 index 00000000..3e1ece97 --- /dev/null +++ b/data_structures/binary_trees/print_path_to_a_node.py @@ -0,0 +1,34 @@ +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def has_path(root, arr, x): + if not root: + return False + + arr.append(root.val) + + if root.val == x: + return True + + if has_path(root.left, arr, x) or has_path(root.right, arr, x): + return True + + # If the required node is not in the left or right subtree, remove + # the parent node from where the fork starts + arr.pop() + return False + + +def print_path(root, x): + arr = [] + + if has_path(root, arr, x): + for i in arr: + print(i, end=' ') + else: + print('Path not present') From 4ce5d5e364098e6923c2f92f9f99621ad7d12499 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 28 Nov 2019 17:17:03 +0530 Subject: [PATCH 062/302] Create maximum_left_node.py --- .../binary_trees/maximum_left_node.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 data_structures/binary_trees/maximum_left_node.py diff --git a/data_structures/binary_trees/maximum_left_node.py b/data_structures/binary_trees/maximum_left_node.py new file mode 100644 index 00000000..8e3f23b2 --- /dev/null +++ b/data_structures/binary_trees/maximum_left_node.py @@ -0,0 +1,22 @@ +# Find the max value in only the left nodes of the tree + +# Do inorder traversal and just keep track of the values + +class Node: + + def __init__(self, val): + self.val = val + self.right = None + self.left = None + + +def find(root): + res = -999999999999 + + if not root: + return res + + if root.left != None: + res = root.left.val + + return max(find(root.left), res, find(root.right)) From ba60b56897436fabc1b6ebf0bf44110bad14fc09 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 28 Nov 2019 17:23:23 +0530 Subject: [PATCH 063/302] Create longest_path_with_same_value.py --- .../longest_path_with_same_value.py | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 data_structures/binary_trees/longest_path_with_same_value.py diff --git a/data_structures/binary_trees/longest_path_with_same_value.py b/data_structures/binary_trees/longest_path_with_same_value.py new file mode 100644 index 00000000..288bbf95 --- /dev/null +++ b/data_structures/binary_trees/longest_path_with_same_value.py @@ -0,0 +1,33 @@ +class Node: + + def __init__(self, val): + self.val = val + self.right = None + self.left = None + + +def length(root, ans): + if not root: + return 0 + + left = length(root.left, ans) + right = length(root.right, ans) + + left_max = 0 + right_max = 0 + + if root.left and root.left.val == root.val: + left_max += 1 + + if root.right and root.right.val == root.val: + right_max += 1 + + ans[0] = max(ans[0], left_max + right_max) + + return max(left_max, right_max) + + +def longest_path(root): + ans = [0] + length(root, ans) + return ans[0] From 281b96c1fa12889be28aa2ef5df63c678a71f0b5 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Fri, 29 Nov 2019 12:50:30 +0530 Subject: [PATCH 064/302] Create print_full_nodes.py --- .../binary_trees/print_full_nodes.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 data_structures/binary_trees/print_full_nodes.py diff --git a/data_structures/binary_trees/print_full_nodes.py b/data_structures/binary_trees/print_full_nodes.py new file mode 100644 index 00000000..e76c63c8 --- /dev/null +++ b/data_structures/binary_trees/print_full_nodes.py @@ -0,0 +1,30 @@ +# Given a tree, print all the full nodes of it +# A full node is such that both its children are present + +class Node: + + def __init__(self, val): + self.val = val + self.right = None + self.left = None + + +def print_full(root): + if not root: + return + if root.left and root.right: + print(root.val, end=' ') + print_full(root.left) + print_full(root.right) + + +root = Node(10) +root.left = Node(8) +root.right = Node(2) + +root.left.left = Node(3) +root.left.right = Node(5) + +root.right.left = Node(7) + +print_full(root) From cc53555698ee81ceb6e6b6547c496b637bbf0210 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Fri, 29 Nov 2019 12:53:02 +0530 Subject: [PATCH 065/302] Create print_odd_level_nodes.py --- .../binary_trees/print_odd_level_nodes.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 data_structures/binary_trees/print_odd_level_nodes.py diff --git a/data_structures/binary_trees/print_odd_level_nodes.py b/data_structures/binary_trees/print_odd_level_nodes.py new file mode 100644 index 00000000..bd83c75c --- /dev/null +++ b/data_structures/binary_trees/print_odd_level_nodes.py @@ -0,0 +1,19 @@ +# Print all the nodes at odd levels of a binary tree + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def print_odd(root, is_odd=True): + if not root: + return + + if is_odd: + print(root.val, end=' ') + + print_odd(root, not is_odd) + print_odd(root, not is_odd) From e32d7da57f66d72e37ce91285975a9ddb46fab06 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Fri, 29 Nov 2019 13:00:31 +0530 Subject: [PATCH 066/302] Create diameter.py --- data_structures/binary_trees/diameter.py | 31 ++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 data_structures/binary_trees/diameter.py diff --git a/data_structures/binary_trees/diameter.py b/data_structures/binary_trees/diameter.py new file mode 100644 index 00000000..da1726b7 --- /dev/null +++ b/data_structures/binary_trees/diameter.py @@ -0,0 +1,31 @@ +# Diameter of a binary tree is the longest path between two leaf nodes of a binary tree +# Diameter of a binary tree is maximum value of (left_height + right_height + 1) for each node + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def height(root, ans): + if not root: + return 0 + + lheight = height(root.left, ans) + rheight = height(root.right, ans) + + ans[0] = max(ans[0], 1 + lheight + rheight) + + return 1 + max(lheight, rheight) + + +def diameter(root): + if not root: + return 0 + + ans = [-9999999999] + + h = height(root, ans) + return ans[0] From 2cf191c21942c11fea7691cc073a97008434fe5b Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Fri, 29 Nov 2019 13:09:02 +0530 Subject: [PATCH 067/302] Create print_all_root_to_leaf_paths.py --- .../print_all_root_to_leaf_paths.py | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 data_structures/binary_trees/print_all_root_to_leaf_paths.py diff --git a/data_structures/binary_trees/print_all_root_to_leaf_paths.py b/data_structures/binary_trees/print_all_root_to_leaf_paths.py new file mode 100644 index 00000000..f3c0d2a6 --- /dev/null +++ b/data_structures/binary_trees/print_all_root_to_leaf_paths.py @@ -0,0 +1,37 @@ +# Traverse the tree in preorder fashion +# append value in stack +# if root.left and root.right is None, then print all stack values +# traverse left +# traverse right +# pop from stack + +class Node: + + def __init__(self, val): + self.val = val + self.right = None + self.left = None + + +def print_route(root, stack): + if root == None: + return + + stack.append(root.val) + if root.left == None and root.right == None: + for i in stack: + print(i, end=' ') + print() + + print_route(root.left, stack) + print_route(root.right, stack) + stack.pop() + + +root = Node(1) +root.left = Node(2) +root.right = Node(3) +root.left.left = Node(4) +root.left.right = Node(5) + +print_route(root, []) From 5124eab392c6956c3ff75185757e7745acc88b9f Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Fri, 29 Nov 2019 15:06:21 +0530 Subject: [PATCH 068/302] Create children_sum_property.py --- .../binary_trees/children_sum_property.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 data_structures/binary_trees/children_sum_property.py diff --git a/data_structures/binary_trees/children_sum_property.py b/data_structures/binary_trees/children_sum_property.py new file mode 100644 index 00000000..8894fabe --- /dev/null +++ b/data_structures/binary_trees/children_sum_property.py @@ -0,0 +1,28 @@ +# Check whether a tree statisfies children sum property +# Children sum property is such that every partent = left + right child + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def sum_prop(root): + l = r = 0 + + if not root or (not root.left and not root.right): + return True + + else: + if root.left: + l = root.left.val + + if root.right: + r = root.right.val + + if (root.val == l + r) and sum_prop(root.left) and sum_prop(root.right): + return True + else: + return False From ee5e2ae44a4a3e725393d92b45577263bb978401 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Fri, 29 Nov 2019 15:13:50 +0530 Subject: [PATCH 069/302] Create print_nodes_with_no_sibling.py --- .../print_nodes_with_no_sibling.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 data_structures/binary_trees/print_nodes_with_no_sibling.py diff --git a/data_structures/binary_trees/print_nodes_with_no_sibling.py b/data_structures/binary_trees/print_nodes_with_no_sibling.py new file mode 100644 index 00000000..5c7ffc2a --- /dev/null +++ b/data_structures/binary_trees/print_nodes_with_no_sibling.py @@ -0,0 +1,24 @@ +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def no_siblings(root): + if root is None: + return + + if root.left is not None and root.right is not None: + no_siblings(root.left) + no_siblings(root.right) + + elif root.right is not None: + print(root.right.val) + no_siblings(root.right) + + elif root.left is not None: + print(root.left.val) + no_siblings(root.left) + From b237acd88a839da0d050e7ced4863ce01a781de4 Mon Sep 17 00:00:00 2001 From: Sri Harsha Date: Sun, 1 Dec 2019 12:16:45 +0530 Subject: [PATCH 070/302] Python script to check if String C is formed by interleaving of String A and String B --- .../strings/check_interleaving_of_strings.py | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 data_structures/strings/check_interleaving_of_strings.py diff --git a/data_structures/strings/check_interleaving_of_strings.py b/data_structures/strings/check_interleaving_of_strings.py new file mode 100644 index 00000000..e232ed51 --- /dev/null +++ b/data_structures/strings/check_interleaving_of_strings.py @@ -0,0 +1,57 @@ +''' +Question: Given three strings A, B and C. Write a function that checks whether C +is an interleaving of A and B. C is said to be interleaving A and B, if +it contains all characters of A and B and order of all characters in +individual strings is preserved. + +Solution: We include one character from String A or String B and check whether the resultant +string formed so far by one particular interleaving of the the current prefix of String A +and String B form a prefix of String C. This can be achieved using dynamic programming. +This approach relies on fact that in order to determine whether a +substring of String C(upto index k), can be formed by interleaving strings String A +and String B upto indices i and j respectively depends on the characters of +String A and String B upto indices i and j only and not on characters coming afterwards. + +Complexity analysis - +Time complexity : O(m x n) . dp array of size n is filled m times where m and n are lengths of +String A and String B respectively. +Space complexity : O(n) + +''' + +#Function to check if String C is formed by interleaving of String A and B +#Returns a boolean value +def isInterleaving(string_A, string_B, string_C): + #Check if the length of String C is equal to sum of lengths of String A and B + #In other words, check if String C contains all characters of String A and B + if(len(string_C) != len(string_A) + len(string_B)): return False + + #Create an empty array of length of String B + dp = [None] * (len(string_B) + 1) + + for i in range(len(string_A) + 1): + for j in range(len(string_B) + 1): + if(i == 0 and j == 0): + #The first value of array dp always holds True + dp[j] = True + elif(i == 0): + dp[j] = dp[j - 1] and string_B[j - 1] == string_C[j - 1] + elif(j == 0): + dp[j] = dp[j] and string_A[i - 1] == string_C[i - 1] + else: + dp[j] = ((dp[j] and string_A[i - 1] == string_C[i + j - 1]) or (dp[j - 1] and string_B[j - 1] == string_C[i + j - 1])) + + + return dp[len(string_B)] + +#Driver Code +string_A = input("Enter string A") +string_B = input("Enter string B") +string_C = input("Enter string C") + +result = isInterleaving(string_A, string_B, string_C) + +if(result): + print("String C is interleaving String A and String B") +else: + print("String C is not interleaving String A and String B") \ No newline at end of file From a7d522a40483af94cb902bba880f90ee116d704f Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Sun, 1 Dec 2019 18:52:53 +0530 Subject: [PATCH 071/302] new question --- .../binary_trees/sum_predecessor_successor.py | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 data_structures/binary_trees/sum_predecessor_successor.py diff --git a/data_structures/binary_trees/sum_predecessor_successor.py b/data_structures/binary_trees/sum_predecessor_successor.py new file mode 100644 index 00000000..be333a01 --- /dev/null +++ b/data_structures/binary_trees/sum_predecessor_successor.py @@ -0,0 +1,73 @@ +# Convert a binary tree such that each node is the sum of +# its inorder predecessor and successor + +# Store the inorder traversal in an array. Now while traversing +# replace each node with the values arr[i-1] + arr[i+1] as these +# are the inorder predecessor and successor + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def inorder(root): + if not root: + return None + + arr = [] + stack = [] + + while True: + if root: + stack.append(root) + root = root.left + else: + if not stack: + break + root = stack.pop() + arr.append(root.val) + root = root.right + + return arr + + +def replace_nodes(root, arr): + if not root: + return + + stack = [] + i = 1 + while True: + if root: + stack.append(root) + root = root.left + else: + if not stack: + break + root = stack.pop() + root.val = arr[i-1] + arr[i+1] + i += 1 + root = root.right + + + return root + + +root = Node(1) +root.left = Node(2) +root.right = Node(3) +root.left.left = Node(4) +root.left.right = Node(5) +root.right.right = Node(7) +root.right.left = Node(6) + +arr = inorder(root) +print('Inorder traversal original - ', arr) + +new_root = replace_nodes(root, arr) +new_arr = inorder(new_root) +print('New traversal - ', new_arr) + From d33de1e418fd49def40c459636482b46a266cfb4 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 2 Dec 2019 11:41:01 +0530 Subject: [PATCH 072/302] Create sum_of_all_nodes.py --- data_structures/binary_trees/sum_of_all_nodes.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 data_structures/binary_trees/sum_of_all_nodes.py diff --git a/data_structures/binary_trees/sum_of_all_nodes.py b/data_structures/binary_trees/sum_of_all_nodes.py new file mode 100644 index 00000000..e5fe0dd1 --- /dev/null +++ b/data_structures/binary_trees/sum_of_all_nodes.py @@ -0,0 +1,15 @@ +# Find the sum of all nodes of a binary tree + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def sum_nodes(root): + if root is None: + return 0 + + return root.val + sum_nodes(root.left) + sum_nodes(root.right) From 83823a6aec5c6f4773261016c65d91d0ad8485bd Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 2 Dec 2019 11:56:31 +0530 Subject: [PATCH 073/302] Create sum_of_all_left_leaves.py --- .../binary_trees/sum_of_all_left_leaves.py | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 data_structures/binary_trees/sum_of_all_left_leaves.py diff --git a/data_structures/binary_trees/sum_of_all_left_leaves.py b/data_structures/binary_trees/sum_of_all_left_leaves.py new file mode 100644 index 00000000..4ef261f8 --- /dev/null +++ b/data_structures/binary_trees/sum_of_all_left_leaves.py @@ -0,0 +1,47 @@ +# Find the sum of all left leaves of a binary tree + + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def is_leaf(root): + if root is None: + return False + if root.left is None and root.right is None: + return True + return False + + +def sum_left(root): + s = 0 + stack = [] + + while True: + if root: + stack.append(root) + root = root.left + else: + if not stack: + break + root = stack.pop() + if is_leaf(root.left): + s += root.left.val + root = root.right + + return s + + +root = Node(9) +root.left = Node(8) +root.right = Node(6) +root.right.left = Node(1) + +root.left.left = Node(5) +root.left.right = Node(2) + +print(sum_left(root)) From a36d2ad983f8a5b31ebb904df18299ae881ffd01 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 2 Dec 2019 12:02:54 +0530 Subject: [PATCH 074/302] Create sum_of_perfect_binary_tree.py --- .../binary_trees/sum_of_perfect_binary_tree.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 data_structures/binary_trees/sum_of_perfect_binary_tree.py diff --git a/data_structures/binary_trees/sum_of_perfect_binary_tree.py b/data_structures/binary_trees/sum_of_perfect_binary_tree.py new file mode 100644 index 00000000..f438015f --- /dev/null +++ b/data_structures/binary_trees/sum_of_perfect_binary_tree.py @@ -0,0 +1,12 @@ +# https://www.geeksforgeeks.org/find-sum-nodes-given-perfect-binary-tree/ + +import math + +def sum_nodes(l): + leaf_nodes = math.pow(2, l-1) + + s = (leaf_nodes + (leaf_nodes + 1)) / 2 + + res = s * l + + return int(res) From b480e9f4a83b0c8eaea5e0502c402aa945b2e0f3 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 2 Dec 2019 12:11:26 +0530 Subject: [PATCH 075/302] Create largest_subtree_sum.py --- .../binary_trees/largest_subtree_sum.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 data_structures/binary_trees/largest_subtree_sum.py diff --git a/data_structures/binary_trees/largest_subtree_sum.py b/data_structures/binary_trees/largest_subtree_sum.py new file mode 100644 index 00000000..d79002f2 --- /dev/null +++ b/data_structures/binary_trees/largest_subtree_sum.py @@ -0,0 +1,31 @@ +# Find the largest subtree sum in a binary tree +# Do a postorder traversal + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def sum_util(root, ans): + if root is None: + return 0 + + s = root.val + sum_util(root.left, ans) + sum_util(root.right, ans) + + ans[0] = max(ans[0], s) + + return s + + +def find_sum(root): + if root is None: + return 0 + + ans = [-99999999] + + sum_util(root, ans) + + return ans[0] From e84921d59f86525e729af26e20fcb29e14e4aee3 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 2 Dec 2019 12:13:58 +0530 Subject: [PATCH 076/302] Create TO_DO --- data_structures/binary_trees/TO_DO | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 data_structures/binary_trees/TO_DO diff --git a/data_structures/binary_trees/TO_DO b/data_structures/binary_trees/TO_DO new file mode 100644 index 00000000..cb734cb7 --- /dev/null +++ b/data_structures/binary_trees/TO_DO @@ -0,0 +1,2 @@ +1. Max width of a binary tree +2. Total width of a binary tree From 2c81da93d04ad46fd1f1f097930ba4c74b0a586d Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 3 Dec 2019 11:02:05 +0530 Subject: [PATCH 077/302] Create kosaraju_algorithm.py --- data_structures/graphs/kosaraju_algorithm.py | 65 ++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 data_structures/graphs/kosaraju_algorithm.py diff --git a/data_structures/graphs/kosaraju_algorithm.py b/data_structures/graphs/kosaraju_algorithm.py new file mode 100644 index 00000000..cfc2a2b0 --- /dev/null +++ b/data_structures/graphs/kosaraju_algorithm.py @@ -0,0 +1,65 @@ +# Reference - https://www.geeksforgeeks.org/strongly-connected-components/ + +# This is used to find all the strongly connected components and does DFS +# 2 times. + +from collections import defaultdict + + +class Graph: + + def __init__(self, vertices): + self.V = vertices + self.graph = defaultdict(list) + + + def add_edge(self, u, v): + self.graph[u].append(v) + + + def dfs_util(self, v, visited): + visited[v] = True + print(v, end=' ') + + for i in self.graph[v]: + if visited[i] == False: + self.dfs_util(i, visited) + + + def fill_order(self, v, visited, stack): + visited[v] = True + for i in self.graph[v]: + if visited[i] == False: + self.fill_order(i, visited, stack) + stack.append(v) + + + def get_transpose(self): + g = Graph(self.V) + + for i in self.graph: + for j in self.graph[i]: + g.add_edge(j, i) + + return g + + + def kosaraju(self): + stack = [] + visited = [False] * self.V + + for i in range(self.V): + if visited[i] == False: + self.fill_order(i, visited, stack) + + gr = self.get_transpose() + + visited = [False] * self.V + + while stack: + i = stack.pop() + if visited[i] == False: + gr.dfs_util(i, visited) + print() + + From b0ffd60867a019c79ce95ccd297a59ed61bceabf Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 3 Dec 2019 11:16:49 +0530 Subject: [PATCH 078/302] Create activity_selection.py --- algorithms/greedy/activity_selection.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 algorithms/greedy/activity_selection.py diff --git a/algorithms/greedy/activity_selection.py b/algorithms/greedy/activity_selection.py new file mode 100644 index 00000000..8dbd822f --- /dev/null +++ b/algorithms/greedy/activity_selection.py @@ -0,0 +1,18 @@ +#Prints a maximum set of activities that can be done by a +#single person, one at a time +#n --> Total number of activities +#s[]--> An array that contains start time of all activities +#f[] --> An array that contains finish time of all activities + +def print_max_activities(s, f): + n = len(f) + + # the first activity is always selected + i = 0 + print(i, end=' ') + + # for the rest + for j in range(n): + if s[j] >= f[i]: + print(j, end=' ') + i = j From 3e7f8fdbcfdcc91ae22369055d354c8d80478b80 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 3 Dec 2019 11:21:15 +0530 Subject: [PATCH 079/302] Create egyptian_fraction.py --- algorithms/greedy/egyptian_fraction.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 algorithms/greedy/egyptian_fraction.py diff --git a/algorithms/greedy/egyptian_fraction.py b/algorithms/greedy/egyptian_fraction.py new file mode 100644 index 00000000..3d3ea79d --- /dev/null +++ b/algorithms/greedy/egyptian_fraction.py @@ -0,0 +1,13 @@ +# Reference - https://www.geeksforgeeks.org/greedy-algorithm-egyptian-fraction/ + +import math + +def egyptian_fraction(nr, dr): + ef = [] + + while nr != 0: + x = math.ceil(dr / nr) + ef.append(x) + + nr = x * nr - dr + dr = dr * x From a8e927939a6e111956891115f0912853a3ddaf4d Mon Sep 17 00:00:00 2001 From: Tejesh Date: Wed, 4 Dec 2019 14:56:35 +0530 Subject: [PATCH 080/302] Update index_updater.py --- index_updater.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/index_updater.py b/index_updater.py index 296518da..7f4778ae 100755 --- a/index_updater.py +++ b/index_updater.py @@ -16,7 +16,7 @@ curr_folder = os.path.basename(root) for name in files: - if name.endswith('.py') and not name == '__init__py' and not dirs: + if name.endswith('.py') and not name == '__init__.py' and not dirs: curr_files.append(name) # If we have files, write "index.md" @@ -24,4 +24,5 @@ with open(os.path.join(root, 'index.md'), mode='w') as md_file: md_file.write('# Index of {}\n\n'.format(curr_folder)) for line in curr_files: - md_file.write('* ' + line + '\n') + file_name = line.split('.')[0].replace('_',' ').title() + md_file.write('* [' + file_name + '](' +line + ')\n') From cfe92c10d61aeb1de0fe1abf0bf27150c7ec0e72 Mon Sep 17 00:00:00 2001 From: vernalhav Date: Sun, 15 Dec 2019 19:54:39 -0300 Subject: [PATCH 081/302] Made LIS code simpler --- .../longest_increasing_subsequence.py | 85 +++++++------------ 1 file changed, 32 insertions(+), 53 deletions(-) diff --git a/algorithms/dynamic_programming/longest_increasing_subsequence.py b/algorithms/dynamic_programming/longest_increasing_subsequence.py index 30978c2f..1a00abf2 100644 --- a/algorithms/dynamic_programming/longest_increasing_subsequence.py +++ b/algorithms/dynamic_programming/longest_increasing_subsequence.py @@ -6,67 +6,46 @@ of that array ''' -def memoize(f): - """ - Generic decorator for - Dynamic Programming - problems + +def lis(s, cur_index=0, last_index=-1, cur_length=0, dp=None): """ - cache = dict() - def memoized_f(*args): - if args in cache: - global hits - hits += 1 - return cache[args] + Return length of the longest increasing + subsequence from array s. - cache[args] = f(*args) - return cache[args] + To use, simply call lis(s). The other + parameters will be used in the + recursion + """ - return memoized_f + # Initialize dp dictionary to use in the recursion + if dp == None: + dp = dict() + # Base case: we've gone through the whole array + if cur_index == len(s): + return cur_length -def lis(s): - """ Return length of LIS in array s """ + if dp.get((last_index, cur_index)) is not None: + return dp.get((last_index, cur_index)) # Return stored value ''' - NOTE: array s will be declared in the superscope - of lis_routine, so it doesn't need to be passed - as argument and subsequently not hashed by @memoize + Length of the LIS if we include cur_index + is initialized as -1 because we might not + be able to include it if it is less than + the number at last_index. If last_index is + -1, we can take cur_index, as it will be + the first integer in the possible LIS. ''' - - @memoize - def lis_routine(cur_index=0, last_index=-1, cur_length=0): - """ - Return length of the longest increasing - subsequence from array s. - - To use, simply call lis(s). The other - parameters will be used in the - recursion - """ - - if cur_index == len(s): - return cur_length - - ''' - Length of the LIS if we include cur_index - is initialized as -1 because we might not - be able to include it if it is less than - the number at last_index. If last_index is - -1, we can take cur_index, as it will be - the first integer in the possible LIS. - ''' - take = -1 - if last_index == -1 or s[last_index] < s[cur_index]: - take = lis_routine(cur_index + 1, cur_index, cur_length + 1) - - # Length of the LIS if we don't include cur_index - not_take = lis_routine(cur_index + 1, last_index, cur_length) - - # Return the greatest LIS (include cur_index or not) - return max(take, not_take) - - return lis_routine() + take = -1 + if last_index == -1 or s[last_index] < s[cur_index]: + take = lis(s, cur_index + 1, cur_index, cur_length + 1, dp) + + # Length of the LIS if we don't include cur_index + not_take = lis(s, cur_index + 1, last_index, cur_length, dp) + + # Return the greatest LIS (include cur_index or not) + dp[(last_index, cur_index)] = max(take, not_take) # Store result in cache + return dp.get((last_index, cur_index)) def main(): From f4e2f066fbc67c6f155a6db7b21f014a6255bb56 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Sun, 22 Dec 2019 10:01:58 +0530 Subject: [PATCH 082/302] Update README.md --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index c76377a1..4df4e4a9 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,6 @@ Contains all data structure questions categorised into sub-directories like stac This directory contains various types of algorithm questions like Dynamic Programming, Sorting, Greedy, etc. The current structure of this directory is like - - 1. [Dynamic Programming](algorithms/dynamic_programming) 2. [Graphs](algorithms/graph) 3. [Greedy](algorithms/greedy) @@ -37,7 +36,6 @@ This directory contains various types of algorithm questions like Dynamic Progra 5. [Misc](algorithms/miscellaneous) 6. [Sorting](algorithms/sorting) - ### Bookmarks You can find useful links in this repository in the different markdown files. Below is a table of contents. @@ -68,7 +66,6 @@ Feel free to raise new issues, file new PRs and star and fork this repo! :wink: To follow the guidelines, refer to [Contributing.md](CONTRIBUTING.md) - ## :page_facing_up: License [MIT @ Prabhu Pant](LICENSE) From 5556b7c46de4100edbd2020e03d73c22b92f7ee2 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Sun, 29 Dec 2019 21:16:08 +0530 Subject: [PATCH 083/302] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 4df4e4a9..9e789645 100644 --- a/README.md +++ b/README.md @@ -55,8 +55,6 @@ As you can see, the repo is still in its infancy. Here are some key things in th 1. Queue questions 2. Algorithms - 2.1. Dynamic Programming - 2.2. Greedy 3. More questions in data structures, especially for graph, circular linked list, tries, heaps and hash. ## :raised_hand: Contributing From cccb2723d48c7ef87191e959b29f6f6b61799840 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 9 Jan 2020 07:22:35 +0530 Subject: [PATCH 084/302] Added matrix --- ...find_in_row_and_column_wise_sorted_matrix.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 data_structures/matrix/find_in_row_and_column_wise_sorted_matrix.py diff --git a/data_structures/matrix/find_in_row_and_column_wise_sorted_matrix.py b/data_structures/matrix/find_in_row_and_column_wise_sorted_matrix.py new file mode 100644 index 00000000..cd1b07e6 --- /dev/null +++ b/data_structures/matrix/find_in_row_and_column_wise_sorted_matrix.py @@ -0,0 +1,17 @@ +def search(mat, n, x): + + i = 0 + + j = n - 1 + + while i < n and j >=0: + if mat[i][j] == x: + print("Found at - ", i, j) + return 1 + if mat[i][j] > x: + j -= 1 + else: + i += 1 + + print("Element not found") + return 0 From 396bcd5d82706218113d6274fc3fb34f586aab26 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Sun, 12 Jan 2020 15:18:00 +0530 Subject: [PATCH 085/302] Matrix question --- data_structures/matrix/find_pair.py | 0 .../matrix/flood_fill_algorithm.py | 23 +++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 data_structures/matrix/find_pair.py create mode 100644 data_structures/matrix/flood_fill_algorithm.py diff --git a/data_structures/matrix/find_pair.py b/data_structures/matrix/find_pair.py new file mode 100644 index 00000000..e69de29b diff --git a/data_structures/matrix/flood_fill_algorithm.py b/data_structures/matrix/flood_fill_algorithm.py new file mode 100644 index 00000000..d5d3da24 --- /dev/null +++ b/data_structures/matrix/flood_fill_algorithm.py @@ -0,0 +1,23 @@ +# Reference - https://www.geeksforgeeks.org/flood-fill-algorithm-implement-fill-paint/ + +# Dimensions of paint screen +M = 8 +N = 8 + +def flood_fill_util(screen, x, y prev_color, new_color): + if x < 0 or x >= M or y < 0 or y >= N or screen[x][y] != prev_color or screen[x][y] == new_color: + return + + screen[x][y] = new_color + flood_fill_util(screen, x + 1, y, prev_color, new_color) + flood_fill_util(screen, x - 1, y, prev_color, new_color) + flood_fill_util(screen, x, y + 1, prev_color, new_color) + flood_fill_util(screen, x, y - 1, prev_color, new_color) + + +def flood_fill(screen, x, y, new_color): + prev_color = screen[x][y] # Finding the previous color on x and y + flood_fill_util(screen, x, y, prev_color, new_color) + + + From e975b326d0bd3fb1eafc9fcd989773519e5c6aab Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 16 Jan 2020 21:39:14 +0530 Subject: [PATCH 086/302] Update README.md From 9aabe86224b25ca70ac9ad61681b9bb431cd7ebf Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 20 Jan 2020 15:19:19 +0530 Subject: [PATCH 087/302] Create find_common_in_three_arrays.py --- .../array/find_common_in_three_arrays.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 data_structures/array/find_common_in_three_arrays.py diff --git a/data_structures/array/find_common_in_three_arrays.py b/data_structures/array/find_common_in_three_arrays.py new file mode 100644 index 00000000..7c254ef8 --- /dev/null +++ b/data_structures/array/find_common_in_three_arrays.py @@ -0,0 +1,26 @@ +# Find the common elements in three arrays + +def find_common(arr1, arr2, arr3): + i, j, k = 0, 0, 0 + + while i < len(arr1) and j < len(arr2) and k < len(arr3): + if arr1[i] == arr2[j] == arr3[k]: + print(arr1[i]) + i += 1 + j += 1 + k += 1 + + elif arr1[i] < arr2[j]: + i += 1 + + elif arr2[j] < arr3[k]: + j += 1 + + else: + k += 1 + +arr1 = [1,2,3,4,5,6] +arr2 = [5,6,7,8,9] +arr3 = [4,5,6,9,10] + +find_common(arr1, arr2, arr3) From d34e1529b3a8c5f1f8ece2e6b292330423a77978 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 20 Jan 2020 15:38:46 +0530 Subject: [PATCH 088/302] Create find_given_sum_in_array.py --- .../array/find_given_sum_in_array.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 data_structures/array/find_given_sum_in_array.py diff --git a/data_structures/array/find_given_sum_in_array.py b/data_structures/array/find_given_sum_in_array.py new file mode 100644 index 00000000..0aacc5b4 --- /dev/null +++ b/data_structures/array/find_given_sum_in_array.py @@ -0,0 +1,27 @@ +# Find if a given sum exists in an array +# Reference - https://www.geeksforgeeks.org/find-subarray-with-given-sum/ + +def find_sum(arr, s): + curr_sum = arr[0] + start = 0 + n = len(arr) - 1 + + i = 1 + + while i <= n: + + while curr_sum > s and start < i: + curr_sum = curr_sum - arr[start] + start += 1 + + if curr_sum == s: + return "Found between {} and {}".format(start, i - 1) + + curr_sum = curr_sum + arr[i] + i += 1 + + return "Sum not found" + +arr = [15, 2, 4, 8, 9, 5, 10, 23] + +print(find_sum(arr, 6)) From 75c815c771c04201910a84761ff177b5e7e708ff Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 21 Jan 2020 12:54:42 +0530 Subject: [PATCH 089/302] Delete daysofweek.py --- data_structures/array/daysofweek.py | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 data_structures/array/daysofweek.py diff --git a/data_structures/array/daysofweek.py b/data_structures/array/daysofweek.py deleted file mode 100644 index 2b279f23..00000000 --- a/data_structures/array/daysofweek.py +++ /dev/null @@ -1,18 +0,0 @@ -''' -Given a date, return the corresponding day of the week for that date. -The input is given as three integers representing the day, month and year respectively. -Return the answer as one of the following values {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}. -The given dates are valid dates between the years 1971 and 2100. - -Example 1: -Input: day = 31, month = 8, year = 2019 -Output: "Saturday" -''' - # :type day: int , :type month: int , :type year: int , :rtype: str - -class Solution(object): - def dayOfTheWeek(self, day, month, year): - day_of_week_map = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"] - t = [ 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 ] - year -= month < 3 - return day_of_week_map[((year + int(year / 4) - int(year / 100) + int(year / 400) + t[month - 1] + day) % 7)] \ No newline at end of file From b9d84e962a7b0beefca9607d6a406f98199e2430 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 21 Jan 2020 13:49:06 +0530 Subject: [PATCH 090/302] Delete matrix_layer_rotation.py --- .../array/matrix_layer_rotation.py | 88 ------------------- 1 file changed, 88 deletions(-) delete mode 100644 data_structures/array/matrix_layer_rotation.py diff --git a/data_structures/array/matrix_layer_rotation.py b/data_structures/array/matrix_layer_rotation.py deleted file mode 100644 index ef5d36c7..00000000 --- a/data_structures/array/matrix_layer_rotation.py +++ /dev/null @@ -1,88 +0,0 @@ -""" -Description: - -Matrix Layer Rotation - -You are given a 2D matrix of dimension mxn and a positive integer r. You have to rotate the -matrix r times and print the resultant matrix. Rotation should be in anti-clockwise direction. -Rotation of a 4x5 matrix is represented by the following figure. Note that in one rotation, -you have to shift elements by one step only. This is shifting the elemment. -Note:- Minimum of m and n will be even. - -Start First Second - 1 2 3 4 2 3 4 5 3 4 5 6 -12 1 2 5 -> 1 2 3 6 -> 2 3 4 7 -11 4 3 6 12 1 4 7 1 2 1 8 -10 9 8 7 11 10 9 8 12 11 10 9 -""" - - -# Function to rotate the sides of the matrix in place. -def matrix_rotate(matrix, m, n, i=0, j=0): - if (m, n) == (1, 1): - return matrix - if (m, n) == (2, 2): - temp = matrix[i][j] - matrix[i][j] = matrix[i + 1][j] - matrix[i + 1][j] = matrix[i + 1][j + 1] - matrix[i + 1][j + 1] = matrix[i + 1][j] - matrix[i + 1][j] = temp - return matrix - else: - temp = matrix[i][j] - # top - for a in range(j, n - j - 1): - matrix[i][a] = matrix[i][a + 1] - matrix[i][n - j - 1] = matrix[i + 1][n - j - 1] - # right - for a in range(i + 1, m - i - 2): - matrix[a][n - 1 - j] = matrix[a + 1][n - 1 - j] - matrix[m - j - 2][n - j - 1] = matrix[m - j - 1][n - j - 1] - # bottom - for a in range(n - j - 1, j, -1): - matrix[m - j - 1][a] = matrix[m - j - 1][a - 1] - matrix[m - j - 1][j] = matrix[m - j - 2][j] - # left - for a in range(m - i - 2, i, -1): - matrix[a][i] = matrix[a - 1][i] - matrix[i + 1][j] = temp - return matrix - - -def driver_code(matrix, r): - m = len(matrix) - n = len(matrix[0]) - i, j = 0, 0 - s = 0 - while (i, j) < (m // 2, n // 2): # Checking for the maximum values of i, j. - for _ in range(r): - s = matrix_rotate(matrix, m, n, i, j) - i += 1 - j += 1 - print_matrix(s) - - -def print_matrix(matrix): - m = len(matrix) - n = len(matrix[0]) - print('\n'.join([' '.join(['{:n}'.format(item) for item in row]) - for row in matrix])) - - -if __name__ == '__main__': - mnr = input().rstrip().split() - - m = int(mnr[0]) - - n = int(mnr[1]) - - r = int(mnr[2]) - - matrix2d = [] - - for _ in range(m): - matrix2d.append(list(map(int, input().rstrip().split()))) - - driver_code(matrix2d, r) - - From 004c3cc63a93bf2a3b11bfde95de34e12c7a1684 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 21 Jan 2020 13:55:25 +0530 Subject: [PATCH 091/302] Update min_product.py --- data_structures/array/min_product.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/array/min_product.py b/data_structures/array/min_product.py index bdf7cbf3..e83cf5e6 100644 --- a/data_structures/array/min_product.py +++ b/data_structures/array/min_product.py @@ -7,7 +7,7 @@ # If there are odd number of negative numbers and no zeros, # the result is simply the product of all -# If there is a zero, then the result is zero +# If there is a zero and al other are positive, then the result is zero # If there are only positive numbers, the the result is # the smallest positive number From b54017fe5bdd74956c145d668f09e473b62c83e8 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 23 Jan 2020 10:44:08 +0530 Subject: [PATCH 092/302] Update mother_vertex.py --- data_structures/graphs/mother_vertex.py | 58 +++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/data_structures/graphs/mother_vertex.py b/data_structures/graphs/mother_vertex.py index bc996c78..40f8ac10 100644 --- a/data_structures/graphs/mother_vertex.py +++ b/data_structures/graphs/mother_vertex.py @@ -1,5 +1,63 @@ # A mother vertex is a vertex such that all other vertices # can be reached by a path from this vertex +# Reference - https://www.geeksforgeeks.org/find-a-mother-vertex-in-a-graph/ +# Time complexity - 2 * O(V + E) = O(V + E) +from collections import defaultdict + +class Graph: + + def __init__(self, vertices): + self.V = vertices + self.graph = defaultdict(list) + + + def dfs_util(self, v, visited): + visited[v] = True + + for i in self.graph[v]: + if visited[i] == False: + self.dfs_util(i, visited) + + + def add_edge(self, v, w): + self.graph[v].append(w) + + + def find_mother(self): + visited = [False] * self.V + + v = 0 + + for i in range(self.V): + if visited[i] == False: + self.dfs_util(i, visited) + v = i + + # Now check if v is one of the mother vertex + # Reset all the values of visited and do DFS beginning from v + # to check if all the vertices are reachable from it or not + + visited = [False] * self.V + self.dfs_util(v, visited) + + if any(i == False for i in visited): + return -1 + + else: + return v + + +g = Graph(7) +g.add_edge(0, 1) +g.add_edge(0, 2) +g.add_edge(1, 3) +g.add_edge(4, 1) +g.add_edge(6, 4) +g.add_edge(5, 6) +g.add_edge(5, 2) +g.add_edge(6, 0) + +print("Mother vertex is - ", g.find_mother()) From 72fed7a11a9bb0f03be044f7ab28fcf7bc858faf Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 23 Jan 2020 10:55:04 +0530 Subject: [PATCH 093/302] Create iterative_dfs.py --- data_structures/graphs/iterative_dfs.py | 37 +++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 data_structures/graphs/iterative_dfs.py diff --git a/data_structures/graphs/iterative_dfs.py b/data_structures/graphs/iterative_dfs.py new file mode 100644 index 00000000..face3aaf --- /dev/null +++ b/data_structures/graphs/iterative_dfs.py @@ -0,0 +1,37 @@ +# The code is almost same to BFS, the only difference being queue +# is replaced by stack + +from collections import defaultdict + +class Graph: + + def __init__(self, vertices): + self.V = vertices + self.graph = defaultdict(list) + + + def add_edge(self, u, v): + self.graph[u].append(v) + + + def dfs(self, s): + visited = [False] * self.V + + stack = [] + + stack.append(s) + + while stack: + s = stack[-1] + stack.pop() + + if not visited[s]: + print(s, end=' ') + visited[s] = True + + for i in self.graph[s]: + if not visited[i]: + stack.append(i) + + + From 6ffbe5169c7ef81bc400315b05efd9283153ed45 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 23 Jan 2020 11:02:02 +0530 Subject: [PATCH 094/302] Create transpose.py --- data_structures/graphs/transpose.py | 44 +++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 data_structures/graphs/transpose.py diff --git a/data_structures/graphs/transpose.py b/data_structures/graphs/transpose.py new file mode 100644 index 00000000..02270c55 --- /dev/null +++ b/data_structures/graphs/transpose.py @@ -0,0 +1,44 @@ +from collections import defaultdict + + +class Graph: + + def __init__(self, vertices): + self.V = vertices + self.graph = defaultdict(list) + + + def add_edge(self, u, v): + self.graph[u].append(v) + + + def print_graph(self): + for i in self.graph: + print(i, " --> ", end=" ") + for j in self.graph[i]: + print(j, end=" ") + print() + + + def transpose(self): + g = Graph(self.V) + + for i in self.graph: + for j in self.graph[i]: + g.add_edge(j, i) + + return g + + +g = Graph(5) +g.add_edge(1, 0) +g.add_edge(0, 2) +g.add_edge(2, 1) +g.add_edge(0, 3) +g.add_edge(3, 4) +g.print_graph() + +print('---------') + +t = g.transpose() +t.print_graph() From f59acf175ebbd20862cd6f3493b57e8008f08d63 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 23 Jan 2020 12:50:45 +0530 Subject: [PATCH 095/302] Create bipartite_graph.py --- data_structures/graphs/bipartite_graph.py | 46 +++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 data_structures/graphs/bipartite_graph.py diff --git a/data_structures/graphs/bipartite_graph.py b/data_structures/graphs/bipartite_graph.py new file mode 100644 index 00000000..0c851248 --- /dev/null +++ b/data_structures/graphs/bipartite_graph.py @@ -0,0 +1,46 @@ +# Check for bipartite graph + +# Do a BFS and make source of red color and its neighbour blue +# Keep on doing this. +# If self loop, return false +# If current color == neighbour color, false, else true + +# Reference - https://www.geeksforgeeks.org/bipartite-graph/ + +from collections import defaultdict + +class Graph: + + def __init__(self, vertices): + self.V = vertices + self.graph = defaultdict(list) + + + def is_bipartite(self, s): + # 0 -> color 0 + # 1 -> color 1 + # -1 -> no color assigned + + colors = [-1] * self.V + colors[s] = 1 + + queue = [] + queue.append(s) + + while queue: + u = queue.pop() + + if self.graph[u][v] == 1: # Check for self loop + return False + + # An edge u to v exists and destination is not + # colored + for v in range(self.V): + if self.graph[u][v] == 1 and colors[v] == -1: + colors[v] = 1 - colors[u] + queue.append(v) + + elif self.graph[u][v] == 1 and colors[v] == colors[u]: + return False + + return True From 4d8482186dcf8d32fbe489f17bb62a2184a88d77 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 23 Jan 2020 15:34:02 +0530 Subject: [PATCH 096/302] Create count_paths_between_nodes.py --- .../graphs/count_paths_between_nodes.py | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 data_structures/graphs/count_paths_between_nodes.py diff --git a/data_structures/graphs/count_paths_between_nodes.py b/data_structures/graphs/count_paths_between_nodes.py new file mode 100644 index 00000000..3b1f71de --- /dev/null +++ b/data_structures/graphs/count_paths_between_nodes.py @@ -0,0 +1,47 @@ +from collections import defaultdict + +class Graph: + + def __init__(self, vertices): + self.V = vertices + self.graph = defaultdict(list) + + + def add_edge(self, u, v): + self.graph[u].append(v) + + + def count_paths_util(self, u, d, visited, path_count): + visited[u] = True + + if u == d: + path_count[0] += 1 + + else: + i = 0 + for i in range(len(self.graph[u])): + if not visited[self.graph[u][i]]: + self.count_paths_util(self.graph[u][i], d, visited, path_count) + + visited[u] = False + + + def count_paths(self, s, d): + visited = [False] * self.V + path_count = [0] + self.count_paths_util(s, d, visited, path_count) + return path_count[0] + + +g = Graph(4) +g.add_edge(0, 1) +g.add_edge(0, 2) +g.add_edge(0, 3) +g.add_edge(2, 0) +g.add_edge(2, 1) +g.add_edge(1, 3) + +s = 2 +d = 3 + +print(g.count_paths(s, d)) From fc3eae1c2bd94ebca302622aa0e871e11fac705e Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 23 Jan 2020 16:06:40 +0530 Subject: [PATCH 097/302] Create cycle_in_directed_graph.py --- .../graphs/cycle_in_directed_graph.py | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 data_structures/graphs/cycle_in_directed_graph.py diff --git a/data_structures/graphs/cycle_in_directed_graph.py b/data_structures/graphs/cycle_in_directed_graph.py new file mode 100644 index 00000000..2a2b3253 --- /dev/null +++ b/data_structures/graphs/cycle_in_directed_graph.py @@ -0,0 +1,40 @@ +from collections import defaultdict + + +class Graph: + + def __init__(self, vertices): + self.V = vertices + self.graph = defaultdict(list) + + + def add_edge(self, u, v): + self.graph[u].append(v) + + + def is_cyclic_util(self, v, visited, rec_stack): + visited[v] = True + rec_stack[v] = True + + for neighbour in self.graph[v]: + if visited[neighbour] == False: + if self.is_cyclic_util(neighbour, visited, rec_stack): + return True + + elif rec_stack[neighbour] == True: + return True + + rec_stack[v] = False + return False + + + def is_cyclic(self): + visited = [False] * self.V + rec_stack = [False] * self.V + + for i in range(self.V): + if visited[i] == False: + if self.is_cyclic_util(node, visited, rec_stack) == True: + return True + + return False From 4cfffdbd9293dfed6e560ebeb2a8a10ac9808c3e Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 23 Jan 2020 16:17:39 +0530 Subject: [PATCH 098/302] Create cyclic_in_undirected_graph.py --- .../graphs/cyclic_in_undirected_graph.py | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 data_structures/graphs/cyclic_in_undirected_graph.py diff --git a/data_structures/graphs/cyclic_in_undirected_graph.py b/data_structures/graphs/cyclic_in_undirected_graph.py new file mode 100644 index 00000000..bb16b122 --- /dev/null +++ b/data_structures/graphs/cyclic_in_undirected_graph.py @@ -0,0 +1,37 @@ +from collections import defaultdict + + +class Graph: + + def __init__(self, vertices): + self.V = vertices + self.graph = defaultdict(list) + + + def add_edge(self, u, v): + self.graph[u].append(v) + + + def is_cyclic_util(self, v, visited, parent): + visited[v] = True + + for i in self.graph[v]: + if visited[i] == False: + if self.is_cyclic_util(i, visited, v): + return True + + elif parent != i: + return True + + return False + + + def is_cyclic(self): + visited = [False] * (self.V) + + for i in range(self.V): + if visited[i] == False: + if self.is_cyclic_util(i, visited, -1): + return True + + return False From 9652add89dc6bd30221c332f04bb99e44c2131ce Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Fri, 24 Jan 2020 13:00:53 +0530 Subject: [PATCH 099/302] Create topological_sort.py --- data_structures/graphs/topological_sort.py | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 data_structures/graphs/topological_sort.py diff --git a/data_structures/graphs/topological_sort.py b/data_structures/graphs/topological_sort.py new file mode 100644 index 00000000..d0fb65fa --- /dev/null +++ b/data_structures/graphs/topological_sort.py @@ -0,0 +1,33 @@ +from collections import defaultdict + + +class Graph: + + def __init__(self, vertices): + self.V = vertices + self.graph = defaultdict(list) + + + def add_edge(self, u, v): + self.graph[u].append(v) + + + def topo_sort_util(self, v, visited, stack): + visited[v] = True + + for i in self.graph[v]: + if visited[i] == False: + self.topo_sort_util(i, visited, stack) + + stack.insert(0, v) + + + def topo_sort(self): + visited = [False] * self.V + stack = [] + + for i in range(self.V): + if visited[i] == False: + self.topo_sort_util(i, visited, stack) + + print(stack) From ef7b1e29e141a428c656b80c3b2eff4abbd0a0ab Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 27 Jan 2020 15:15:34 +0530 Subject: [PATCH 100/302] Create root_which_gives_min_height.py --- .../graphs/root_which_gives_min_height.py | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 data_structures/graphs/root_which_gives_min_height.py diff --git a/data_structures/graphs/root_which_gives_min_height.py b/data_structures/graphs/root_which_gives_min_height.py new file mode 100644 index 00000000..77a738a9 --- /dev/null +++ b/data_structures/graphs/root_which_gives_min_height.py @@ -0,0 +1,56 @@ +# Reference - https://www.geeksforgeeks.org/roots-tree-gives-minimum-height/ + +from collections import defaultdict +from queue import Queue + +class Graph: + + def __init__(self, vertices): + self.V = vertices + self.graph = defaultdict(list) + self.degree = [0] * vertices + + + def add_edge(self, v, w): + self.graph[v].append(w) + self.graph[w].append(v) + self.degree[v] += 1 + self.degree[w] += 1 + + + def root_min_height(self): + q = Queue() + + for i in range(self.V): + if self.degree[i] == 1: + q.put(i) + + + while self.V > 2: + for i in range(q.qsize()): + t = q.get() + self.V -= 1 + + # For each neighbour decrease its degree and if it becomes + # leaf, insert into the queue + for j in self.graph[t]: + self.degree[j] -= 1 + if self.degree[j] == 1: + q.put(j) + + + res = list() + while q.qsize() > 0: + res.append(q.get()) + + + return res + +g = Graph(6) +g.add_edge(0, 3) +g.add_edge(1, 3) +g.add_edge(2, 3) +g.add_edge(4, 3) +g.add_edge(5, 4) + +print(g.root_min_height()) From 34029c1c899101fd7e6ff7709dee552c70863f6e Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 27 Jan 2020 15:25:12 +0530 Subject: [PATCH 101/302] Create longest_path.py --- data_structures/graphs/longest_path.py | 1 + 1 file changed, 1 insertion(+) create mode 100644 data_structures/graphs/longest_path.py diff --git a/data_structures/graphs/longest_path.py b/data_structures/graphs/longest_path.py new file mode 100644 index 00000000..e3334433 --- /dev/null +++ b/data_structures/graphs/longest_path.py @@ -0,0 +1 @@ +# https://www.geeksforgeeks.org/longest-path-between-any-pair-of-vertices/ From 3818db23a15c06068b77fb75e3dc191b2ad4dd71 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 28 Jan 2020 11:41:20 +0530 Subject: [PATCH 102/302] Create trie.py --- data_structures/trie/trie.py | 91 ++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 data_structures/trie/trie.py diff --git a/data_structures/trie/trie.py b/data_structures/trie/trie.py new file mode 100644 index 00000000..c4c533ba --- /dev/null +++ b/data_structures/trie/trie.py @@ -0,0 +1,91 @@ +class TrieNode(): + def __init__(self): + + self.children = {} + self.last = False + +class Trie(): + def __init__(self): + + self.root = TrieNode() + self.word_list = [] + + def formTrie(self, keys): + + for key in keys: + self.insert(key) + + def insert(self, key): + + node = self.root + + for a in list(key): + if not node.children.get(a): + node.children[a] = TrieNode() + + node = node.children[a] + + node.last = True + + def search(self, key): + + node = self.root + found = True + + for a in list(key): + if not node.children.get(a): + found = False + break + + node = node.children[a] + + return node and node.last and found + + def suggestionsRec(self, node, word): + + if node.last: + self.word_list.append(word) + + for a,n in node.children.items(): + self.suggestionsRec(n, word + a) + + def printAutoSuggestions(self, key): + + node = self.root + not_found = False + temp_word = '' + + for a in list(key): + if not node.children.get(a): + not_found = True + break + + temp_word += a + node = node.children[a] + + if not_found: + return 0 + elif node.last and not node.children: + return -1 + + self.suggestionsRec(node, temp_word) + + for s in self.word_list: + print(s) + return 1 + +keys = ["hello", "dog", "hell", "cat", "a", + "hel", "help", "helps", "helping"] +key = "hel" +status = ["Not found", "Found"] + +t = Trie() + +t.formTrie(keys) + +comp = t.printAutoSuggestions(key) + +if comp == -1: + print("No other strings found with this prefix\n") +elif comp == 0: + print("No string found with this prefix\n") From cb23bfffff63f1057b802ca56dc8b7bcde3783c0 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 28 Jan 2020 12:56:32 +0530 Subject: [PATCH 103/302] Create notes.md --- notes.md | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 notes.md diff --git a/notes.md b/notes.md new file mode 100644 index 00000000..5be5193e --- /dev/null +++ b/notes.md @@ -0,0 +1,123 @@ +# Notes + +## Linked List + +### Advantages over Array + +1. Dynamic size +2. Ease of insertion/deletion + +### Drawbacks + +1. Random access is not allowed +2. Extra memory is required with each pointer +3. Not cache friendly. Since array elements are contiguous locations, there is locality of reference which is not there in case of linked lists. + +### Applications + +1. Implementation of stack and queue and adjacency list representation of graphs +2. Dynamic memory allocation [Why?](https://www.slideshare.net/profansari/linked-list-static-and-dynamic-memory-allocation) +3. Maintaining directory of names +4. Image viewer, where images are linked in slideshows +5. Previos and next page in web browsers +6. Playlist in music players + +--- + +## Circular Linked List + +### Advantages + +1. Any node can be a starting point +2. Easy to go from the last node to the first node + +### Disadvantages + +1. More memory +2. Not easy to reverse the list + +### Applications + +1. Computers use Circular Linked List to cycle through active applications. Basically Round Robin Scheduling algorithm +2. Task queues +3. Snake game on Nokia phones +4. Never ending playlist + +--- + +## Doubly Linked List + +### Advantages + +1. Can be traversed in both directions +2. Deletion is more efficient as we can easily fetch the previous node + +### Disadvantages + +1. Consumes more space because of extra pointer + +[See XOR Linked List](https://www.geeksforgeeks.org/xor-linked-list-a-memory-efficient-doubly-linked-list-set-1/) + +### Applications + +1. Schedulers in operating systems +2. Undo-Redo functionality +3. MRU and LRU in operating systems + +--- + +## Tree + +### Applications + +1. Store hierarchial data +2. Trie are used in autocompletion and suggestion of words +3. BST can be used in searching +4. B-Tree and B+ Trees are used in database indexing + +### Misc + +1. [Advantages of BST over Hash Table](https://www.geeksforgeeks.org/advantages-of-bst-over-hash-table/) +2. [Ternary Search Tree - space efficient Trie](https://www.geeksforgeeks.org/ternary-search-tree/) +3. Heaps are better at finding Min/Max whereas BSTs are finding specific values +4. Insertion in heaps is O(1) whereas it is O(log(n)) for BST. This is the killer feature of heaps +5. Binary heap creation is O(n) whereas it is O(n log(n)) for BST. + +### Advantages of BST over heap + +1. Search for arbitary element is O(log(n)) in BST whereas it is O(n) for heap. [Reference](https://stackoverflow.com/questions/6147242/heap-vs-binary-search-tree-bst) + +--- + +## Heap + +### Applications + +1. Graph algorithms like Djikstra +2. Priority queues + +### Misc + +For differences between Heap and BST - [Reference](https://stackoverflow.com/questions/6147242/heap-vs-binary-search-tree-bst) + +[Why is binary heap preferred over BST for priority queue](https://www.geeksforgeeks.org/why-is-binary-heap-preferred-over-bst-for-priority-queue/) + +--- + +## Graph + + +### Difference between Graph and Tree + +| Graphs | Trees | +| --- | --- | --- | +| No unique node called root | Has a unique root node | +| There can be a cycle | No cycle | +| Network model | Hierarchial model | + +### Applications + +1. Networking +2. Social networks to find friends +3. Maps +4. Finding dependencies (Topological Sort) From 9a29687a304b5d2b6dfe8dee68d0ad49f8f9a77e Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 28 Jan 2020 13:52:13 +0530 Subject: [PATCH 104/302] Update notes.md --- notes.md | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/notes.md b/notes.md index 5be5193e..1220a6ab 100644 --- a/notes.md +++ b/notes.md @@ -121,3 +121,60 @@ For differences between Heap and BST - [Reference](https://stackoverflow.com/que 2. Social networks to find friends 3. Maps 4. Finding dependencies (Topological Sort) +5. Topological sort - + 1. Finding dependencies + 2. Job scheduling among dependent jobs +6. Kosaraju's algorithm - + 1. To find strongly connected components (which are used in social networks) +7. Bipartite Graph - + 1. Student and class scheduling + 2. Stable marriage + 3. Text analyzer to cluster documents + 4. Netflix movie preference algorithm +8. Depth First Search - + 1. For a **weighted** graph, DFS produces Minimum Spanning Tree + 2. Cycle check + 3. Path finding + 4. Topological Sorting + 5. Finding strongly connected components +9. Breadth First Search - + 1. For a **unweighted** graph, BFS produces Minimum Spanning Tree + 2. Used in BitTorrent to find all neighbour nodes + 3. Crawlers in search engine [Why BFS not DFS is used in web crawlers](https://stackoverflow.com/a/20580936/12360506) + 4. Broadcasting in networking + 5. Garbage collection. Breadth First Search is preferred over Depth First Search because of better locality of reference. + 6. Ford-Fulkerson algorithm +10. Minimum Spanning Tree - + 1. Network design (like connecting all offices in a city with the lowest cost of cables) +11. Articulation Point - + 1. Articulation points represent vulnerabilities in a connected network – single points whose failure would split the network into 2 or more disconnected components. They are useful for designing reliable networks. + +--- + +## Stack + +### Application + +1. Expression handling, infix to postfix etc +2. Function calls +3. Parenthesis checking +4. Backtracking + +--- + +## Queue + +### Application + +1. BFS traversal +2. Handling interrupts in operating system +3. IO Buffers, pipes + +--- + +## Priority Queue + +### Application + +1. Prim's algorithm +2. Data compression. Used in Huffman coding From 07b5f44cc5543a06f6dc1bd5b393437b83ff8c6c Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 29 Jan 2020 14:41:02 +0530 Subject: [PATCH 105/302] Create count_edges.py --- data_structures/graphs/count_edges.py | 42 +++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 data_structures/graphs/count_edges.py diff --git a/data_structures/graphs/count_edges.py b/data_structures/graphs/count_edges.py new file mode 100644 index 00000000..f1601542 --- /dev/null +++ b/data_structures/graphs/count_edges.py @@ -0,0 +1,42 @@ +# Use handshaking lemma +# deg(v) = 2|E| +# Time - O(V) + +class Graph: + + def __init__(self, vertices): + self.V = vertices + self.graph = [[] for i in range(vertices)] + + + def add_edge(self, u, v): + self.graph[u].append(v) + self.graph[v].append(u) + + + def count_edges(self): + s = 0 + + for i in range(self.V): + s += len(self.graph[i]) + + return s // 2 + + +g = Graph(9) +g.add_edge(0, 1 ) +g.add_edge(0, 7 ) +g.add_edge(1, 2 ) +g.add_edge(1, 7 ) +g.add_edge(2, 3 ) +g.add_edge(2, 8 ) +g.add_edge(2, 5 ) +g.add_edge(3, 4 ) +g.add_edge(3, 5 ) +g.add_edge(4, 5 ) +g.add_edge(5, 6 ) +g.add_edge(6, 7 ) +g.add_edge(6, 8 ) +g.add_edge(7, 8 ) + +print(g.count_edges()) From 5b7f8ed993e22186ed1565cb21505a45f6410608 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 29 Jan 2020 14:58:33 +0530 Subject: [PATCH 106/302] Create number_of_triangles.py --- data_structures/graphs/number_of_triangles.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 data_structures/graphs/number_of_triangles.py diff --git a/data_structures/graphs/number_of_triangles.py b/data_structures/graphs/number_of_triangles.py new file mode 100644 index 00000000..aa0a1669 --- /dev/null +++ b/data_structures/graphs/number_of_triangles.py @@ -0,0 +1,30 @@ +# Reference - https://www.geeksforgeeks.org/number-of-triangles-in-a-undirected-graph/ +# Reference - https://www.geeksforgeeks.org/number-of-triangles-in-directed-and-undirected-graphs/ + +# In case of undirected graph - trace(A^3)/6 +# For undirected graph, just check if an edge exists among all the three vertices + +class Graph: + + def __init__(self, vertices, is_directed): + self.V = vertices + self.graph = [[] for i in range(vertices)] + self.is_directed = is_directed + + + def add_edge(self, u, v): + self.graph[u].append(v) + self.graph[v].append(u) + + + def count_triangles(self): + nodes = len(self.graph) + count = 0 + + for i in range(nodes): + for j in range(nodes): + for k in range(nodes): + if i != j and j != k and k != i and self.graph[i][j] and self.graph[j][k] and self.graph[k][i]: + count += 1 + + return count // 3 if is_directed else count // 6 From fe202544bdd9c6f34f70209e83074d3c29ae3850 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 29 Jan 2020 16:23:39 +0530 Subject: [PATCH 107/302] Create not_reachable_nodes.py --- data_structures/graphs/not_reachable_nodes.py | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 data_structures/graphs/not_reachable_nodes.py diff --git a/data_structures/graphs/not_reachable_nodes.py b/data_structures/graphs/not_reachable_nodes.py new file mode 100644 index 00000000..df2e765a --- /dev/null +++ b/data_structures/graphs/not_reachable_nodes.py @@ -0,0 +1,44 @@ +from collections import defaultdict + +class Graph: + + def __init__(self, vertices): + self.V = vertices + self.graph = defaultdict(list) + + + def add_edge(self, u, v): + self.graph[u].append(v) + self.graph[v].append(u) + + + def dfs_util(self, v, visited): + visited[v] = True + + for i in self.graph[v]: + if visited[i] == False: + self.dfs_util(i, visited) + + + def count_nodes(self, v): + visited = [False] * self.V + + self.dfs_util(v, visited) + + count = 0 + + for i in range(self.V): + if visited[i] == False: + count += 1 + + return count + +g = Graph(8) +g.add_edge(0, 1) +g.add_edge(0, 2) +g.add_edge(1, 2) +g.add_edge(3, 4) +g.add_edge(4, 5) +g.add_edge(6, 7) + +print(g.count_nodes(0)) From 46d0606fc35156f0c0549bb6e7c447b9b4f81445 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Fri, 31 Jan 2020 11:58:58 +0530 Subject: [PATCH 108/302] Create database.md --- bookmarks/database.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 bookmarks/database.md diff --git a/bookmarks/database.md b/bookmarks/database.md new file mode 100644 index 00000000..5a4e2fd3 --- /dev/null +++ b/bookmarks/database.md @@ -0,0 +1 @@ +https://stackoverflow.com/questions/23435361/does-mysql-update-the-index-on-all-inserts-can-i-make-it-update-after-every-x-i From 9f6dedc9b71ce14ceeb4aa8e49ed416b0eed19bb Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Fri, 31 Jan 2020 15:18:01 +0530 Subject: [PATCH 109/302] Create reverse_with_special_chars.py --- .../strings/reverse_with_special_chars.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 data_structures/strings/reverse_with_special_chars.py diff --git a/data_structures/strings/reverse_with_special_chars.py b/data_structures/strings/reverse_with_special_chars.py new file mode 100644 index 00000000..6d4aa95b --- /dev/null +++ b/data_structures/strings/reverse_with_special_chars.py @@ -0,0 +1,25 @@ +# Reverse a string making sure that special characters remain +# in their place + +# a#bcd#efg -> g#fed#cba + + +def reverse(s): + i = 0 + j = len(s) - 1 + + while i < j: + if s[i].isalnum() and s[j].isalnum(): + s[i], s[j] = s[j], s[i] + i += 1 + j -= 1 + if not s[i].isalnum(): + i += 1 + if not s[j].isalnum(): + j -= 1 + return ''.join(s) + + +s = 'a#bcd#efg' +print(s) +print(reverse(list(s))) From d42c5946f5ca1b1c98e72b2da75b497f3e396752 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Sat, 1 Feb 2020 10:11:44 +0530 Subject: [PATCH 110/302] Change bfs and dfs graph --- data_structures/graphs/bfs.py | 11 +++++++++++ data_structures/graphs/iterative_dfs.py | 25 +++++++++++++++---------- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/data_structures/graphs/bfs.py b/data_structures/graphs/bfs.py index 72a0fff6..82bda7d3 100644 --- a/data_structures/graphs/bfs.py +++ b/data_structures/graphs/bfs.py @@ -26,3 +26,14 @@ def bfs(self, s): if visited[i] == False: queue.append(i) visited[i] = True + + +g = Graph() +g.add_edge(0, 1) +g.add_edge(0, 2) +g.add_edge(1, 2) +g.add_edge(2, 0) +g.add_edge(2, 3) +g.add_edge(3, 3) + +g.bfs(0) diff --git a/data_structures/graphs/iterative_dfs.py b/data_structures/graphs/iterative_dfs.py index face3aaf..65c092dc 100644 --- a/data_structures/graphs/iterative_dfs.py +++ b/data_structures/graphs/iterative_dfs.py @@ -5,8 +5,7 @@ class Graph: - def __init__(self, vertices): - self.V = vertices + def __init__(self): self.graph = defaultdict(list) @@ -15,23 +14,29 @@ def add_edge(self, u, v): def dfs(self, s): - visited = [False] * self.V + visited = [False] * len(self.graph) stack = [] stack.append(s) + visited[s] = True while stack: - s = stack[-1] - stack.pop() - - if not visited[s]: - print(s, end=' ') - visited[s] = True + s = stack.pop() + print(s, end=' ') for i in self.graph[s]: - if not visited[i]: + if visited[i] == False: stack.append(i) + visited[i] = True +g = Graph() +g.add_edge(0, 1) +g.add_edge(0, 2) +g.add_edge(1, 2) +g.add_edge(2, 0) +g.add_edge(2, 3) +g.add_edge(3, 3) +g.dfs(0) From b58ee744033b84d74fb69f6ce45b932ecee5d66d Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Sun, 2 Feb 2020 11:54:21 +0530 Subject: [PATCH 111/302] Add 01 Knapsack --- algorithms/dynamic_programming/01_knapsack.py | 26 +++++ .../dynamic_programming/bit_masking1.py | 99 ------------------- .../dynamic_programming/climbing_stairs.py | 22 ----- algorithms/dynamic_programming/coin_change.py | 26 ----- algorithms/dynamic_programming/dice.py | 24 ----- .../dynamic_programming/edit_distance.py | 31 ------ algorithms/dynamic_programming/index.md | 11 --- .../dynamic_programming/k_palindrome1.py | 65 ------------ .../longest_common_subsequence.py | 23 ----- .../longest_increasing_subsequence.py | 63 ------------ .../longest_palindromic_subsequence.py | 40 -------- .../dynamic_programming/max_subarray.py | 26 ----- algorithms/dynamic_programming/rod_cutting.py | 22 ----- .../dynamic_programming/unique_grid_paths.py | 26 ----- 14 files changed, 26 insertions(+), 478 deletions(-) create mode 100644 algorithms/dynamic_programming/01_knapsack.py delete mode 100644 algorithms/dynamic_programming/bit_masking1.py delete mode 100644 algorithms/dynamic_programming/climbing_stairs.py delete mode 100644 algorithms/dynamic_programming/coin_change.py delete mode 100644 algorithms/dynamic_programming/dice.py delete mode 100644 algorithms/dynamic_programming/edit_distance.py delete mode 100644 algorithms/dynamic_programming/index.md delete mode 100644 algorithms/dynamic_programming/k_palindrome1.py delete mode 100644 algorithms/dynamic_programming/longest_common_subsequence.py delete mode 100644 algorithms/dynamic_programming/longest_increasing_subsequence.py delete mode 100644 algorithms/dynamic_programming/longest_palindromic_subsequence.py delete mode 100644 algorithms/dynamic_programming/max_subarray.py delete mode 100644 algorithms/dynamic_programming/rod_cutting.py delete mode 100644 algorithms/dynamic_programming/unique_grid_paths.py diff --git a/algorithms/dynamic_programming/01_knapsack.py b/algorithms/dynamic_programming/01_knapsack.py new file mode 100644 index 00000000..652c65e9 --- /dev/null +++ b/algorithms/dynamic_programming/01_knapsack.py @@ -0,0 +1,26 @@ +def knapsack(values, weights, total): + total_items = len(weights) + + rows = total_items + 1 + cols = total + 1 + + # rows are the number of items + # columns are the values of weights required + + t = [[0 for i in range(cols)] for i in range(rows)] + + for i in range(1, rows): + for j in range(1, cols): + if j < weights[i-1]: + t[i][j] = t[i-1][j] + else: + t[i][j] = max(t[i-1][j], values[i-1] + t[i-1][j-weights[i-1]]) + + return t[rows-1][cols-1] + + +weights = [1,3,4,5] +values = [1,4,5,7] + +ans = knapsack(values, weights, 7) +print(ans) diff --git a/algorithms/dynamic_programming/bit_masking1.py b/algorithms/dynamic_programming/bit_masking1.py deleted file mode 100644 index b5e3de9b..00000000 --- a/algorithms/dynamic_programming/bit_masking1.py +++ /dev/null @@ -1,99 +0,0 @@ -""" -Consider the below problems statement. - -There are 100 different types of caps each having a unique id from 1 to 100. Also, -there are ā€˜n’ persons each having a collection of a variable number of caps. -One day all of these persons decide to go in a party wearing a cap but to look unique -they decided that none of them will wear the same type of cap. So, count the total number -of arrangements or ways such that none of them is wearing the same type of cap. - -""" - -# Python program to find number of ways to wear hats -from collections import defaultdict - - -class AssignCap: - - # Initialize variables - def __init__(self): - - self.allmask = 0 - - self.total_caps = 100 - - self.caps = defaultdict(list) - - # Mask is the set of persons, i is the current cap number. - def count_ways_util(self, dp, mask, cap_no): - - # If all persons are wearing a cap so we - # are done and this is one way so return 1 - if mask == self.allmask: - return 1 - - # If not everyone is wearing a cap and also there are no more - # caps left to process, so there is no way, thus return 0; - if cap_no > self.total_caps: - return 0 - - # If we have already solved this subproblem, return the answer. - if dp[mask][cap_no] != -1: - return dp[mask][cap_no] - - # Ways, when we don't include this cap in our arrangement - # or solution set - ways = self.count_ways_util(dp, mask, cap_no + 1) - - # assign ith cap one by one to all the possible persons - # and recur for remaining caps. - if cap_no in self.caps: - - for ppl in self.caps[cap_no]: - - # if person 'ppl' is already wearing a cap then continue - if mask & (1 << ppl): - continue - - # Else assign him this cap and recur for remaining caps with - # new updated mask vector - ways += self.count_ways_util(dp, mask | (1 << ppl), cap_no + 1) - - ways = ways % (10**9 + 7) - - # Save the result and return it - dp[mask][cap_no] = ways - - return dp[mask][cap_no] - - def count_ways(self, N): - - # Reads n lines from standard input for current test case - # create dictionary for cap. cap[i] = list of person having - # cap no i - for ppl in range(N): - - cap_possessed_by_person = map(int, input().strip().split()) - - for i in cap_possessed_by_person: - - self.caps[i].append(ppl) - - # allmask is used to check if all persons - # are included or not, set all n bits as 1 - self.allmask = (1 << N) - 1 - - # Initialize all entries in dp as -1 - dp = [[-1 for j in range(self.total_caps + 1)] for i in range(2 ** N)] - - # Call recursive function countWaysUtil - # result will be in dp[0][1] - print(self.count_ways_util(dp, 0, 1,)) - -# Driver Program - - -def main(): - No_of_people = int(input()) # number of persons in every test case - - AssignCap().count_ways(No_of_people) diff --git a/algorithms/dynamic_programming/climbing_stairs.py b/algorithms/dynamic_programming/climbing_stairs.py deleted file mode 100644 index b47ffa3a..00000000 --- a/algorithms/dynamic_programming/climbing_stairs.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -High Level Description: -You are climbing a stair case. It takes n steps to reach to the top. -Each time you can either climb 1 or 2 steps. In how many distinct ways can you -climb to the top? - -Time Complexity: -O(n) -""" - -def climb_stairs(n): - if n==0 or n==1: - return 1 - first= 1 - second= 1 - ans= 0 - - for i in range(2, n+1): - ans = first + second - second = first - first = ans - return ans \ No newline at end of file diff --git a/algorithms/dynamic_programming/coin_change.py b/algorithms/dynamic_programming/coin_change.py deleted file mode 100644 index fcf8d87b..00000000 --- a/algorithms/dynamic_programming/coin_change.py +++ /dev/null @@ -1,26 +0,0 @@ -# Dynamic Programming Python implementation of Coin -# Change problem -def count(S, m, n): - # We need n+1 rows as the table is constructed - # in bottom up manner using the base case 0 value - # case (n = 0) - table = [[0 for x in range(m)] for x in range(n+1)] - - # Fill the entries for 0 value case (n = 0) - for i in range(m): - table[0][i] = 1 - - # Fill rest of the table entries in bottom up manner - for i in range(1, n+1): - for j in range(m): - - # Count of solutions including S[j] - x = table[i - S[j]][j] if i-S[j] >= 0 else 0 - - # Count of solutions excluding S[j] - y = table[i][j-1] if j >= 1 else 0 - - # total count - table[i][j] = x + y - - return table[n][m-1] diff --git a/algorithms/dynamic_programming/dice.py b/algorithms/dynamic_programming/dice.py deleted file mode 100644 index 4c4ec68f..00000000 --- a/algorithms/dynamic_programming/dice.py +++ /dev/null @@ -1,24 +0,0 @@ -''' -Given n dices each with m faces, numbered from 1 to m, -find the number of ways to get a given sum X. -X is the summation of values on each face when all the dice are thrown. - -''' - -dp = [[-1 for i in range(x+1)] for j in range(n+1)] - - -def num_of_ways(m, n, x): - if x == 0 and n == 0: - return 1 - if x < 0 or n == 0: - return 0 - if dp[n][x] != -1: - return dp[n][x] - - ans = 0 - for i in range(1, m + 1): - ans += num_of_ways(m, n - 1, x - i) - - dp[n][x] = ans - return ans diff --git a/algorithms/dynamic_programming/edit_distance.py b/algorithms/dynamic_programming/edit_distance.py deleted file mode 100644 index dde466a9..00000000 --- a/algorithms/dynamic_programming/edit_distance.py +++ /dev/null @@ -1,31 +0,0 @@ -""" -High Level Description: -Given two words word1 and word2, find the minimum number of operations -required to convert word1 to word2. You have the following 3 operations -permitted on a word: -Insert a character -Delete a character -Replace a character - -Time Complexity: -O(m*n) -""" - - -def edit_dist(str1, str2, m, n): - dp = [[0 for x in range(n+1)] for x in range(m+1)] - - for i in range(m+1): - for j in range(n+1): - if i == 0: - dp[i][j] = j - elif j == 0: - dp[i][j] = i - elif str1[i-1] == str2[j-1]: - dp[i][j] = dp[i-1][j-1] - else: - dp[i][j] = 1 + min(dp[i][j-1], # Insert - dp[i-1][j], # Remove - dp[i-1][j-1]) # Replace - - return dp[m][n] diff --git a/algorithms/dynamic_programming/index.md b/algorithms/dynamic_programming/index.md deleted file mode 100644 index 0a50f2c6..00000000 --- a/algorithms/dynamic_programming/index.md +++ /dev/null @@ -1,11 +0,0 @@ -# Index of dynamic_programming - -* [Climbing Stairs](climbing_stairs.py) -* [Coin Change](coin_change.py) -* [Dice](dice.py) -* [Edit Distance](edit_distance.py) -* [Longest Common Subsequence](longest_common_subsequence.py) -* [Longest Palindromic Subsequence](longest_palindromic_subsequence.py) -* [Max Subarray](max_subarray.py) -* [Rod Cutting](rod_cutting.py) -* [Unique Grid Paths](unique_grid_paths.py) diff --git a/algorithms/dynamic_programming/k_palindrome1.py b/algorithms/dynamic_programming/k_palindrome1.py deleted file mode 100644 index 8c69e5af..00000000 --- a/algorithms/dynamic_programming/k_palindrome1.py +++ /dev/null @@ -1,65 +0,0 @@ -# code to find if given string -# is K-Palindrome or not - -""" -Explanation - -Process all characters one by one staring from either from left or right sides of both strings. -Let us traverse from the right corner, there are two possibilities for every pair of character being traversed. - -If last characters of two strings are same, we ignore last characters and get count for remaining strings. -So we recur for lengths m-1 and n-1 where m is length of str1 and n is length of str2. -If last characters are not same, we consider remove operation on last character of first string and -last character of second string, recursively compute minimum cost for the operations and take minimum of two values. -Remove last char from str1: Recur for m-1 and n. -Remove last char from str2: Recur for m and n-1. -""" - -# Find if given string -# is K-Palindrome or not - - -def is_kpalrec(str1, str2, m, n): - - # If first string is empty, - # the only option is to remove - # all characters of second string - if not m: - return n - - # If second string is empty, - # the only option is to remove - # all characters of first string - if not n: - return m - - # If last characters of two strings - # are same, ignore last characters - # and get count for remaining strings. - if str1[m - 1] == str2[n - 1]: - return isKPalRec(str1, str2, m - 1, n - 1) - - # If last characters are not same, - # 1. Remove last char from str1 and recur for m-1 and n - # 2. Remove last char from str2 and recur for m and n-1 - # Take minimum of above two operations - res = 1 + min(is_kpalrec(str1, str2, m - 1, n), # Remove from str1 - (is_kpalrec(str1, str2, m, n - 1))) # Remove from str2 - - return res - -# Returns true if str is k palindrome. - - -def is_kPal(string, k): - revStr = string[::-1] - l = len(string) - - return (is_kpalrec(string, revStr, l, l) <= k * 2) - - -# Driver program -string = "acdcb" -k = 2 - -print("Yes" if is_kPal(string, k) else "No") diff --git a/algorithms/dynamic_programming/longest_common_subsequence.py b/algorithms/dynamic_programming/longest_common_subsequence.py deleted file mode 100644 index d8a5e66e..00000000 --- a/algorithms/dynamic_programming/longest_common_subsequence.py +++ /dev/null @@ -1,23 +0,0 @@ -''' -We are given two sequences and we -need to find the length of the -longest common subsequence -''' - - -def lcs(S1, S2): - m = len(S1) - n = len(S2) - - LCS = [[-1]*(n + 1) for i in range(m + 1)] - - for i in range(m + 1): - for j in range(n + 1): - if i == 0 or j == 0: - LCS[i][j] = 0 - elif S1[i-1] == S2[j-1]: - LCS[i][j] = LCS[i-1][j-1]+1 - else: - LCS[i][j] = max(LCS[i-1][j], LCS[i][j-1]) - - return LCS[m][n] diff --git a/algorithms/dynamic_programming/longest_increasing_subsequence.py b/algorithms/dynamic_programming/longest_increasing_subsequence.py deleted file mode 100644 index 1a00abf2..00000000 --- a/algorithms/dynamic_programming/longest_increasing_subsequence.py +++ /dev/null @@ -1,63 +0,0 @@ -''' -Problem statement: -given an array of N elements, -return the length of the -longest increasing subsequence -of that array -''' - - -def lis(s, cur_index=0, last_index=-1, cur_length=0, dp=None): - """ - Return length of the longest increasing - subsequence from array s. - - To use, simply call lis(s). The other - parameters will be used in the - recursion - """ - - # Initialize dp dictionary to use in the recursion - if dp == None: - dp = dict() - - # Base case: we've gone through the whole array - if cur_index == len(s): - return cur_length - - if dp.get((last_index, cur_index)) is not None: - return dp.get((last_index, cur_index)) # Return stored value - - ''' - Length of the LIS if we include cur_index - is initialized as -1 because we might not - be able to include it if it is less than - the number at last_index. If last_index is - -1, we can take cur_index, as it will be - the first integer in the possible LIS. - ''' - take = -1 - if last_index == -1 or s[last_index] < s[cur_index]: - take = lis(s, cur_index + 1, cur_index, cur_length + 1, dp) - - # Length of the LIS if we don't include cur_index - not_take = lis(s, cur_index + 1, last_index, cur_length, dp) - - # Return the greatest LIS (include cur_index or not) - dp[(last_index, cur_index)] = max(take, not_take) # Store result in cache - return dp.get((last_index, cur_index)) - - -def main(): - """ Simple test cases """ - t1 = [1, 6, 2, 3, 7, 9, 4, 8, 5] - t2 = [9, 8, 7, 6, 5, 4, 3, 2, 1] - t3 = [-1, -1, -1, -1, -1, -1] - - print('LIS of {}: {}'.format(t1, lis(t1))) # Should be 5 - print('LIS of {}: {}'.format(t2, lis(t2))) # Should be 1 - print('LIS of {}: {}'.format(t3, lis(t3))) # Should be 1 - - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/algorithms/dynamic_programming/longest_palindromic_subsequence.py b/algorithms/dynamic_programming/longest_palindromic_subsequence.py deleted file mode 100644 index e0d6f3bd..00000000 --- a/algorithms/dynamic_programming/longest_palindromic_subsequence.py +++ /dev/null @@ -1,40 +0,0 @@ -''' -Question : -Given a string consisting of English alphabets, the task is to count the alphabets in the longest palindromic subsequence. - -For example : -Input: str = "BBABCBCAB" -Output: 7 -"BABCBAB" is the longest palindromic subseuqnce in it. "BBBBB"" and "BBCBB" are also palindromic subsequences of the given sequence, but not the longest ones. - -Source: https://www.geeksforgeeks.org/python-program-for-longest-palindromic-subsequence-dp-12/ -''' - -def lps(str): - n = len(str) - - # Create a table to store results of subproblems - L = [[0 for x in range(n)] for x in range(n)] - - # Strings of length 1 are palindrome of length 1 - for i in range(n): - L[i][i] = 1 - - # Build the table. Note that the lower - # diagonal values of table are - # useless and not filled in the process. - for cl in range(2, n + 1): - for i in range(n-cl + 1): - j = i + cl-1 - if str[i] == str[j] and cl == 2: - L[i][j] = 2 - elif str[i] == str[j]: - L[i][j] = L[i + 1][j-1] + 2 - else: - L[i][j] = max(L[i][j-1], L[i + 1][j]); - - return L[0][n-1] - -# Test inputs -seq = "BBABCBCAB" -print("The length of the LPS is " + str(lps(seq))) diff --git a/algorithms/dynamic_programming/max_subarray.py b/algorithms/dynamic_programming/max_subarray.py deleted file mode 100644 index 422c29c9..00000000 --- a/algorithms/dynamic_programming/max_subarray.py +++ /dev/null @@ -1,26 +0,0 @@ -""" -High Level Description: -Given an integer array nums, find the contiguous subarray (containing at least -one number) which has the largest sum and return its sum. - -Time Complexity: -O(n) -""" - - -# Iterative Solution - Kadane's algorithm -def max_sub_array(arr): - if not arr: - return 0 - - cur_sum = max_sum = arr[0] - for num in arr[1:]: - cur_sum = max(num, cur_sum + num) - max_sum = max(max_sum, cur_sum) - - return max_sum - - - -print max_sub_array([1,2,-100,3,4]) - diff --git a/algorithms/dynamic_programming/rod_cutting.py b/algorithms/dynamic_programming/rod_cutting.py deleted file mode 100644 index 9e807bb0..00000000 --- a/algorithms/dynamic_programming/rod_cutting.py +++ /dev/null @@ -1,22 +0,0 @@ -''' -Given a rod of length n units and an -array of prices that contains prices -of all pieces of size less than n. We -need to find the maximum maximum price -obtainable by cutting the rod and -selling it. -''' -INT_MIN = -32767 - - -def cutRod(price, n): - values = [0 for i in range(n+1)] - values[0] = 0 - - for i in range(1, n+1): - max_value = INT_MIN - for j in range(i): - max_value = max(max_value, price[j] + values[i-j-1]) - values[i] = max_value - - return values[n] diff --git a/algorithms/dynamic_programming/unique_grid_paths.py b/algorithms/dynamic_programming/unique_grid_paths.py deleted file mode 100644 index a5518ba3..00000000 --- a/algorithms/dynamic_programming/unique_grid_paths.py +++ /dev/null @@ -1,26 +0,0 @@ -""" -High Level Description: -A preson is located at the top-left corner of a m x n grid (marked 'Start' in -the diagram below). The preson can only move either down or right at any point -in time. The preson is trying to reach the bottom-right corner of the grid -(marked 'Finish' in the diagram below). -How many possible unique paths are there? - -Time Complexity: -O(m*n) -""" - - -def number_of_paths(m, n): - count = [[0 for x in range(m)] for y in range(n)] - - for i in range(m): - count[i][0] = 1 - - for j in range(n): - count[0][j] = 1 - - for i in range(1, m): - for j in range(n): - count[i][j] = count[i-1][j] + count[i][j-1] - return count[m-1][n-1] From b7d04e814dc2e416ad8e3ebf1673524acb435cce Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Sun, 2 Feb 2020 20:06:31 +0530 Subject: [PATCH 112/302] Add dynamic questions --- algorithms/dynamic_programming/coin_change.py | 16 ++++++++++++++++ .../longest_common_subsequence.py | 18 ++++++++++++++++++ .../longest_common_substring.py | 15 +++++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 algorithms/dynamic_programming/coin_change.py create mode 100644 algorithms/dynamic_programming/longest_common_subsequence.py create mode 100644 algorithms/dynamic_programming/longest_common_substring.py diff --git a/algorithms/dynamic_programming/coin_change.py b/algorithms/dynamic_programming/coin_change.py new file mode 100644 index 00000000..88056015 --- /dev/null +++ b/algorithms/dynamic_programming/coin_change.py @@ -0,0 +1,16 @@ +# Concept is almost same as 01 Knapsack Problem + +def min_coin(coins, total): + cols = total + 1 + rows = len(coins) + + t = [ [0] if col == 0 else float('inf') for col in range(cols)] for i in range(rows)] + + for i in range(rows): + for j in range(1, cols): + if j < coins[i]: + t[i][j] = t[i-1][j] + else: + t[i][j] = min(t[i-1][j], 1 + t[i][j-coins[i]) + + return t[rows-1][cols-1] diff --git a/algorithms/dynamic_programming/longest_common_subsequence.py b/algorithms/dynamic_programming/longest_common_subsequence.py new file mode 100644 index 00000000..2c60beda --- /dev/null +++ b/algorithms/dynamic_programming/longest_common_subsequence.py @@ -0,0 +1,18 @@ +def lcs(s1, s2): + cols = len(s1) + 1 + rows = len(s2) + 1 + + t = [[0 for i in range(cols)] for i in range(rows)] + + max_length = 0 + + for i in range(1, rows): + for j in range(1, cols): + if s2[i-1] == s1[j-1]: + t[i][j] = 1 + t[i-1][j-1] + else: + t[i][j] = max(t[i-1][j], t[i][j-1]) + + max_length = max(max_length, t[i][j]) + + return max_length diff --git a/algorithms/dynamic_programming/longest_common_substring.py b/algorithms/dynamic_programming/longest_common_substring.py new file mode 100644 index 00000000..7777feb2 --- /dev/null +++ b/algorithms/dynamic_programming/longest_common_substring.py @@ -0,0 +1,15 @@ +def lcs(s1, s2): + cols = len(s1) + 1 + rows = len(s2) + 1 + + t = [[0 for i in range(cols)] for i in range(rows)] + + max_length = 0 + + for i in range(1, rows): + for j in range(1, cols): + if s[i-1] == s[j-1]: + t[i][j] = t[i-1][j-1] + 1 + max_length = max(max_length, t[i][j]) + + return max_length From 5ffc4f7a7da7796ca426f2083f1b3ffe033c9ff4 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 5 Feb 2020 15:45:58 +0530 Subject: [PATCH 113/302] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9e789645..35224879 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![logo](logo/logo.png) +![logo](logo/logo.png) # Python Data Structures and Algorithms From 279c93aa6f81ee789a47f3adc0b7b4bd4b788d3f Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 11 Feb 2020 14:15:42 +0530 Subject: [PATCH 114/302] Create all_paths_between_two_vertices.py --- .../graphs/all_paths_between_two_vertices.py | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 data_structures/graphs/all_paths_between_two_vertices.py diff --git a/data_structures/graphs/all_paths_between_two_vertices.py b/data_structures/graphs/all_paths_between_two_vertices.py new file mode 100644 index 00000000..958a2b82 --- /dev/null +++ b/data_structures/graphs/all_paths_between_two_vertices.py @@ -0,0 +1,50 @@ +# Use backtracking +# The only with this approach is that if there is a cycle, then +# it can show infinitely many paths +# Reference - https://www.geeksforgeeks.org/count-possible-paths-two-vertices/ + +class Graph: + + def __init__(self, vertices): + self.vertices = vertices + self.graph = [[] for i in range(vertices)] + + + def add_edge(self, u, v): + self.graph[u].append(v) + + + def count_paths_util(self, u, v, visited, counter): + visited[u] = True + + # If the destination vertex is found + if u == v: + counter[0] += 1 + + else: + for i in range(len(self.graph[u])): + if not visited[self.graph[u][i]]: + self.count_paths_util(self.graph[u][i], v, visited, counter) + + visited[u] = False + + + def count_paths(self, u, v): + visited = [False] * self.vertices + + counter = [0] + + self.count_paths_util(u, v, visited, counter) + + return counter[0] + + +g = Graph(4) +g.add_edge(0, 1) +g.add_edge(0, 2) +g.add_edge(0, 3) +g.add_edge(2, 0) +g.add_edge(2, 1) +g.add_edge(1, 3) + +print(g.count_paths(2, 3)) From 01dcf738f13ef76b70bf62e1788d78d43098b329 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 11 Feb 2020 15:23:30 +0530 Subject: [PATCH 115/302] Create tree_stays_bipartite.py --- .../graphs/tree_stays_bipartite.py | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 data_structures/graphs/tree_stays_bipartite.py diff --git a/data_structures/graphs/tree_stays_bipartite.py b/data_structures/graphs/tree_stays_bipartite.py new file mode 100644 index 00000000..cda2299a --- /dev/null +++ b/data_structures/graphs/tree_stays_bipartite.py @@ -0,0 +1,56 @@ +# All trees are bipartite graphs +# Reference - https://www.geeksforgeeks.org/maximum-number-edges-added-tree-stays-bipartite-graph/ + +# Traverse the tree (dfs or bfs) and color nodes with two colors and count each like +# count_color1 and count_color2. Then the max edges that the graph can have are +# count_color1 * count_color2, and the max edges of a tree are n-1 + +# Therefore the answer is = count_color1 * count_color2 - (n-1) + +class Graph: + + def __init__(self, vertices): + self.vertices = vertices + self.graph = [[] for i in range(vertices)] + + + def add_edge(self, u, v): + self.graph[u].append(v) + + + def bfs(self, s): + visited = [False] * self.vertices + color_count = [0, 0] + + colors = [-1] * self.vertices + colors[s] = 1 + + queue = [] + + queue.append(s) + visited[s] = True + + while queue: + u = queue.pop(0) + + for v in self.graph[u]: + if colors[v] == -1: # This is a tree. So not visited and not colored is same as there is no cycle + colors[v] = 1 - colors[u] + queue.append(v) + color_count[colors[v]] += 1 + visited[v] = True + + # Counting the max number of edges for graph + graph_edges = color_count[0] * color_count[1] + + return graph_edges + + +# Number of tree nodes +n = 5 + +g = Graph(5) +g.add_edge(1, 2) +g.add_edge(1, 3) +g.add_edge(2, 4) +g.add_edge(3, 5) From 56e7b1301f6a388dc27f824a1d18442e6b6f71b4 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Sun, 16 Feb 2020 09:14:09 +0530 Subject: [PATCH 116/302] Update README.md From b7cab9de7b49b62a91849d458d800517116eca4d Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Sun, 16 Feb 2020 09:14:33 +0530 Subject: [PATCH 117/302] Update README.md From 81f71e5ec4732f2b5ce8a19245638671c90a1009 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 25 Feb 2020 22:40:18 +0100 Subject: [PATCH 118/302] Add GitHub Action to lint Python code --- .github/workflows/lint_python.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/workflows/lint_python.yml diff --git a/.github/workflows/lint_python.yml b/.github/workflows/lint_python.yml new file mode 100644 index 00000000..507beee3 --- /dev/null +++ b/.github/workflows/lint_python.yml @@ -0,0 +1,18 @@ +name: lint_python +on: + pull_request: + push: + # branches: [master] +jobs: + lint_python: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - uses: actions/setup-python@master + - run: pip install black codespell flake8 isort pytest + - run: black . --diff || true + - run: codespell --quiet-level=2 || true # --ignore-words-list="" --skip="" + - run: flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + - run: isort --recursive . || true + - run: pip install -r requirements.txt || true + - run: pytest . || true From 899d4c26790e849a8daf6651870373db6fc92f51 Mon Sep 17 00:00:00 2001 From: cclauss Date: Tue, 25 Feb 2020 22:57:28 +0100 Subject: [PATCH 119/302] Fix typos found by codespell --- CONTRIBUTING.md | 2 +- README.md | 2 +- notes.md | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1f0c24e6..be0d596c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,7 +32,7 @@ For filing a PR for a new question, please open a issue first for the same and t ### Bookmarks -The Bookmarks directory is for storing awesome links to articles, videos, slides, talks, etc that are interesting and can help in increasing knowledge for a specific topic. There has been many PRs for adding new links in Bookmarks and most of them refered to either a whole book or DS Algo MOOCs, please refrain from adding them. Here are some points that you must consider before contributing to Bookmarks - +The Bookmarks directory is for storing awesome links to articles, videos, slides, talks, etc that are interesting and can help in increasing knowledge for a specific topic. There has been many PRs for adding new links in Bookmarks and most of them referred to either a whole book or DS Algo MOOCs, please refrain from adding them. Here are some points that you must consider before contributing to Bookmarks - * Don't add a link to a MOOC or course (like DS Algo MIT lectures) diff --git a/README.md b/README.md index 35224879..14069301 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # Python Data Structures and Algorithms -This repository contains data structures and algorithms concepts and questions userful for interviews in Python. +This repository contains data structures and algorithms concepts and questions useful for interviews in Python. ## :dart: Objective diff --git a/notes.md b/notes.md index 1220a6ab..ad364f49 100644 --- a/notes.md +++ b/notes.md @@ -19,7 +19,7 @@ 2. Dynamic memory allocation [Why?](https://www.slideshare.net/profansari/linked-list-static-and-dynamic-memory-allocation) 3. Maintaining directory of names 4. Image viewer, where images are linked in slideshows -5. Previos and next page in web browsers +5. Previous and next page in web browsers 6. Playlist in music players --- @@ -85,7 +85,7 @@ ### Advantages of BST over heap -1. Search for arbitary element is O(log(n)) in BST whereas it is O(n) for heap. [Reference](https://stackoverflow.com/questions/6147242/heap-vs-binary-search-tree-bst) +1. Search for arbitrary element is O(log(n)) in BST whereas it is O(n) for heap. [Reference](https://stackoverflow.com/questions/6147242/heap-vs-binary-search-tree-bst) --- From a6ec61b5103aa918cfe3c89e032df4312ab03e3f Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 25 Feb 2020 23:19:12 +0100 Subject: [PATCH 120/302] Fix Python syntax error --- data_structures/doubly_linked_list/doubly_linked_list.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data_structures/doubly_linked_list/doubly_linked_list.py b/data_structures/doubly_linked_list/doubly_linked_list.py index 2702ac1a..9feb64b0 100644 --- a/data_structures/doubly_linked_list/doubly_linked_list.py +++ b/data_structures/doubly_linked_list/doubly_linked_list.py @@ -1,7 +1,7 @@ class Node: - def __init__(self, data = None, next, previous = None): + def __init__(self, data = None, next = None, previous = None): self.data = data - self.next = None + self.next = next self.previous = previous class Lista: From db906aff3a12a9326031d81a78febdf16dbe5f43 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 25 Feb 2020 23:21:05 +0100 Subject: [PATCH 121/302] Fix Python syntax error --- data_structures/matrix/flood_fill_algorithm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/matrix/flood_fill_algorithm.py b/data_structures/matrix/flood_fill_algorithm.py index d5d3da24..935bfd4b 100644 --- a/data_structures/matrix/flood_fill_algorithm.py +++ b/data_structures/matrix/flood_fill_algorithm.py @@ -4,7 +4,7 @@ M = 8 N = 8 -def flood_fill_util(screen, x, y prev_color, new_color): +def flood_fill_util(screen, x, y, prev_color, new_color): if x < 0 or x >= M or y < 0 or y >= N or screen[x][y] != prev_color or screen[x][y] == new_color: return From 35a088a0648ea54f3db971b4c74b812b5eefe943 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 25 Feb 2020 23:22:31 +0100 Subject: [PATCH 122/302] Fix Python syntax error --- data_structures/array/pivot_index.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/data_structures/array/pivot_index.py b/data_structures/array/pivot_index.py index dd2a9e21..d15ce1cd 100644 --- a/data_structures/array/pivot_index.py +++ b/data_structures/array/pivot_index.py @@ -2,9 +2,7 @@ def pivot(arr): s = sum(arr) left_sum = 0 for i, x in enumerate(arr): - if left_sum = (s - x - left_sum): + if left_sum == (s - x - left_sum): return i left_sum += x return -1 - - From df9c8a856875ea8bb13cb055258166ce4936e735 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 25 Feb 2020 23:23:45 +0100 Subject: [PATCH 123/302] Fix Python syntax error --- data_structures/bst/print_ancestor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/bst/print_ancestor.py b/data_structures/bst/print_ancestor.py index 8158d037..b443c559 100644 --- a/data_structures/bst/print_ancestor.py +++ b/data_structures/bst/print_ancestor.py @@ -11,7 +11,7 @@ def print_ancestor_recursive(root, key): return False if root.val == key: return True - if print_ancestor_recursive(root.left, key) || print_ancestor_recursive(root.right, key): + if print_ancestor_recursive(root.left, key) or print_ancestor_recursive(root.right, key): return root.data return False From 7a816e763628b84068c05b0a3fe8d246c7939a94 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 25 Feb 2020 23:26:51 +0100 Subject: [PATCH 124/302] Comment out Python TokenError --- data_structures/bst/linked_list_to_bst.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data_structures/bst/linked_list_to_bst.py b/data_structures/bst/linked_list_to_bst.py index 4b3a9aca..ac980985 100644 --- a/data_structures/bst/linked_list_to_bst.py +++ b/data_structures/bst/linked_list_to_bst.py @@ -28,5 +28,6 @@ def linked_list_to_bst(head): def ll_to_bst_recur(head, n): if n <= 0: return None - left = ll_to_bst_recur( + # TODO: Fix me! + # left = ll_to_bst_recur( From 2e137da1f36450e76ac289d18185a5b6e4efb470 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 25 Feb 2020 23:28:29 +0100 Subject: [PATCH 125/302] Use print() function in both Python 2 and Python 3 --- data_structures/linked_list/merge_linked_list.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/linked_list/merge_linked_list.py b/data_structures/linked_list/merge_linked_list.py index 572f18c4..11220bd8 100644 --- a/data_structures/linked_list/merge_linked_list.py +++ b/data_structures/linked_list/merge_linked_list.py @@ -29,6 +29,6 @@ def merge(l1, l2): ptr = head_merged while ptr: - print ptr.val + print(ptr.val) ptr = ptr.next From 2364edebac1453a1b84aed09bf05e374c87d0130 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 25 Feb 2020 23:30:01 +0100 Subject: [PATCH 126/302] Use print() function in both Python 2 and Python 3 --- data_structures/stack/stack_using_linked_list.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/data_structures/stack/stack_using_linked_list.py b/data_structures/stack/stack_using_linked_list.py index 35323074..794541b5 100644 --- a/data_structures/stack/stack_using_linked_list.py +++ b/data_structures/stack/stack_using_linked_list.py @@ -62,9 +62,9 @@ def pop(self): # Test stack functionality stack.push(e2) stack.push(e3) -print stack.pop().value -print stack.pop().value -print stack.pop().value -print stack.pop() +print(stack.pop().value) +print(stack.pop().value) +print(stack.pop().value) +print(stack.pop()) stack.push(e4) -print stack.pop().value +print(stack.pop().value) From ab69a75a31c304bb0689a29eff308b8dfa0b2c01 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 25 Feb 2020 23:31:15 +0100 Subject: [PATCH 127/302] Use print() function in both Python 2 and Python 3 --- algorithms/sorting/insertion_sort.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/algorithms/sorting/insertion_sort.py b/algorithms/sorting/insertion_sort.py index b19d9ddd..5d0ec752 100644 --- a/algorithms/sorting/insertion_sort.py +++ b/algorithms/sorting/insertion_sort.py @@ -15,12 +15,11 @@ def insertion_sort(lst): return lst test_data = [5,9,4,27,3,6] -print insertion_sort(test_data) +print(insertion_sort(test_data)) test_data = ['f','b','z','a','x'] -print insertion_sort(test_data) +print(insertion_sort(test_data)) # Resulting output: # [3, 4, 5, 6, 9, 27] # ['a', 'b', 'f', 'x', 'z'] - From 9d4796af65779a4f56d9914b2240b6c96062e8a0 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 25 Feb 2020 23:34:12 +0100 Subject: [PATCH 128/302] Fix Python IndentationError --- data_structures/bst/duplicate_keys.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/data_structures/bst/duplicate_keys.py b/data_structures/bst/duplicate_keys.py index e044b7ce..4e0e5cbf 100644 --- a/data_structures/bst/duplicate_keys.py +++ b/data_structures/bst/duplicate_keys.py @@ -43,9 +43,6 @@ def delete(root, val): if root.val == val: if root.count > 1: root.count -= 1 - else: - - root = Node(5) From 39bee5c57d7a71d4f890390ca5fa253fbabe8417 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 25 Feb 2020 23:35:35 +0100 Subject: [PATCH 129/302] Fix Python syntax error --- algorithms/dynamic_programming/coin_change.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/algorithms/dynamic_programming/coin_change.py b/algorithms/dynamic_programming/coin_change.py index 88056015..0f2a8ff7 100644 --- a/algorithms/dynamic_programming/coin_change.py +++ b/algorithms/dynamic_programming/coin_change.py @@ -4,7 +4,7 @@ def min_coin(coins, total): cols = total + 1 rows = len(coins) - t = [ [0] if col == 0 else float('inf') for col in range(cols)] for i in range(rows)] + t = [[ [0] if col == 0 else float('inf') for col in range(cols)] for i in range(rows)] for i in range(rows): for j in range(1, cols): From b86d1756c4153474a34b4e51a8309b5ab85a6b6b Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 25 Feb 2020 23:37:42 +0100 Subject: [PATCH 130/302] Use print() function in both Python 2 and Python 3 --- algorithms/graph/dfs.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/algorithms/graph/dfs.py b/algorithms/graph/dfs.py index fbd33795..4a452536 100644 --- a/algorithms/graph/dfs.py +++ b/algorithms/graph/dfs.py @@ -1,4 +1,5 @@ -# Python program to print DFS traversal for complete graph +# Python program to print DFS traversal for complete graph +from __future__ import print_function from collections import defaultdict # This class represents a directed graph using adjacency @@ -20,7 +21,7 @@ def DFSUtil(self, v, visited): # Mark the current node as visited and print it visited[v]= True - print v, + print(v, end=" ") # Recur for all the vertices adjacent to # this vertex @@ -42,4 +43,4 @@ def DFS(self): # by one for i in range(V): if visited[i] == False: - self.DFSUtil(i, visited) \ No newline at end of file + self.DFSUtil(i, visited) From 264f40f5079b30e9768c537278bc80115c711dfd Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Tue, 25 Feb 2020 23:43:57 +0100 Subject: [PATCH 131/302] Fix Python syntax errors --- algorithms/dynamic_programming/coin_change.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/algorithms/dynamic_programming/coin_change.py b/algorithms/dynamic_programming/coin_change.py index 0f2a8ff7..96b57648 100644 --- a/algorithms/dynamic_programming/coin_change.py +++ b/algorithms/dynamic_programming/coin_change.py @@ -4,13 +4,13 @@ def min_coin(coins, total): cols = total + 1 rows = len(coins) - t = [[ [0] if col == 0 else float('inf') for col in range(cols)] for i in range(rows)] + t = [[[0] if col == 0 else float('inf') for col in range(cols)] for i in range(rows)] for i in range(rows): for j in range(1, cols): if j < coins[i]: t[i][j] = t[i-1][j] else: - t[i][j] = min(t[i-1][j], 1 + t[i][j-coins[i]) + t[i][j] = min(t[i-1][j], 1 + t[i][j-coins[i]]) return t[rows-1][cols-1] From dbece378ba131cd899ac9ff88194618f4a7e6436 Mon Sep 17 00:00:00 2001 From: tasbihaasim Date: Fri, 28 Feb 2020 20:59:09 +0500 Subject: [PATCH 132/302] Make Adjacency matrix part of the graphs folder --- data_structures/graphs/Adjacency_matrix.py | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 data_structures/graphs/Adjacency_matrix.py diff --git a/data_structures/graphs/Adjacency_matrix.py b/data_structures/graphs/Adjacency_matrix.py new file mode 100644 index 00000000..7895a279 --- /dev/null +++ b/data_structures/graphs/Adjacency_matrix.py @@ -0,0 +1,35 @@ +class Graph: + + def __init__(self, vertices, directed: bool): + self.V = vertices + self.e = 0 + self.d = directed + self.graph = [] + for i in range(self.V): + lst = [0] * self.V + self.graph.append(lst) + + def add_edge(self, ver1, ver2): + if self.d: + self.graph[ver1][ver2] = 1 + else: + self.graph[ver1][ver2] = 1 + self.graph[ver2][ver1] = 1 + + def remove_edge(self, ver1, ver2): + if self.d[ver1][ver2] == 0: + print("No edge between %d and %d" % (ver1, ver2)) + return + if self.d: + self.graph[ver1][ver2] = 0 + else: + self.graph[ver1][ver2] = 0 + self.graph[ver2][ver1] = 0 + + def print_graph(self): + for i in self.graph: + print(i) + + + + From 38889cf10bda1633d457c83ba302c33a002a203c Mon Sep 17 00:00:00 2001 From: owais4321 Date: Fri, 20 Mar 2020 03:45:12 -0700 Subject: [PATCH 133/302] added question description to array datastructure index.md --- data_structures/array/index.md | 110 +++++++++++++++++++++++++++++---- 1 file changed, 99 insertions(+), 11 deletions(-) diff --git a/data_structures/array/index.md b/data_structures/array/index.md index 8b964508..c549554c 100644 --- a/data_structures/array/index.md +++ b/data_structures/array/index.md @@ -1,34 +1,122 @@ # Index of array * [Permumations of Word](permutations_of_word.py) + +Find Permuatation of a given word. * [Common Elements of three sorted arrays](sorted_array_three_common_elements.py) + +Find Common elements in three array given that all three arrays are sorted * [Dutch Flag Problem](dutch_flag_problem.py) + + Given an array containing only 0s, 1s and 2s in a random order, arrange the array such that all 0s come + before 1s which in turn come before all 2s + +Input - [1,2,0,1,2,1,0,1,2,1,0] + +Output - [0,0,0,1,1,1,1,1,2,2,2] * [Partition an array into three parts with equal sum](partition_three_parts_equal_sum.py) -* [Binary search on an Infinite array](binary_search_infinite_array.py) + +Divide an array into three parts and sum all three parst must be same. +* [Binary search on a finite array](binary_search_infinite_array.py) + +Performing binary search on a finite array + * [Largest Element](largest_element.py) -* [Right Place](right_place.py) + +Find out the largest element in an array + * [Rotation](rotation.py) + +Rotate an array for given number such that the number goes to the end of array + +input=[1,2,3,4,5] rotate around + +output= [4,5,1,2,3] * [Find missing number](find_missing_numbers.py) + +find missing number between smallest and largest number in array which are not present in array + +input=[1,1,1,4] +output=[2,3] + * [Three Largest Elements](three_largest_elements.py) + +Find three largest numbers from an array * [Triplet Sum](triplet_sum.py) -* [Max Product](max_product.py) + +Find three elements of an array whose sum is eqaul to a given value + * [Moves to Zero](moves_zeros_to_end.py) + +Given an array move all zeros in arrays to the end. * [Pivot Index](pivot_index.py) + +Find the index of element whose right element when added give the same value. * [Intersection of Two Sorted Arrays](intersection_sorted_array.py) + + find out the common elements from two arrays * [Max Triplet Sum](max_triplet_sum.py) -* [Number of 1's in Sorted Array](number_of_1_in_sorted_array.py) + +Find out maximium sum of any three elements for a given array + * [Square of Sorted Array](square_of_sorted_array.py) -* [Max Consecutive 1's](max_consecutive_ones.py) -* [Max Product Three Elements](max_product_three_elements.py) -* [Kadane Algorithm](kadane_algorithm.py) + +For a given array return an array that contains square of elements. + * [All Numbers Divisible](all_numbers_divisible.py) -* [Duplicates](duplicates.py) + + Find a number in the array such that all the elements in the array are divisible by it + + + * [Majority Element](majority_element.py) + +Find an element in an array which has most occurences * [Find Sum](find_sum.py) + +Find if sum of any elements in array is eqaul to a given number * [Quick Sort](quick_sort.py) -* [Peak Element](peak_element.py) + +### Implement Quick Sort algorithm + +Quicksort Running Time: +Quick sort average case is O(n log n) + each level takes O(n) but splitting the data is O(log n) + O(n) * O(log n) = O(n log n) +Worse case is O(log n2) + if pivot is smallest value, each level is O(n) and splitting the data is O(n) + O(n) * O(n) = O(n2) + * [Union Sorted Array](union_sorted_array.py) -* [Min Product](min_product.py) + +Perform Union operations on two arrays + * [Sort By Parity](sort_by_parity.py) + +Given an array A of non-negative integers, return an array consisting of all the even elements of A, followed by all the odd elements of A. * [Duplicate](duplicate.py) -* [Product of Array Except Self](product_of_array_except_self.py) \ No newline at end of file + + Find duplicate in an array of integers given that the integers are in random order and +not necessarily each integer i is 0 <= i <= N where N = length of array +* [Product of Array Except Self](product_of_array_except_self.py) + +find the product of all elements in an array + +* [Right Place](right_place.py) + +Placing elements at right position in an array +* [Max Product Three Elements](max_product_three_elements.py) + +Find out highest sum of three numbers in an array +* [Max Consecutive 1's](max_consecutive_ones.py) + +Counts max number of one's in an array + +* [Kadane Algorithm](kadane_algorithm.py) + +Implementation of Kadane Algorithm +* [Max Product](max_product.py) +* [Number of 1's in Sorted Array](number_of_1_in_sorted_array.py) +* [Duplicates](duplicates.py) +* [Peak Element](peak_element.py) +* [Min Product](min_product.py) \ No newline at end of file From 6abe444c6c480c7a6c966013791dc0e0a6fa0530 Mon Sep 17 00:00:00 2001 From: Gavin Spearhead Date: Sat, 28 Mar 2020 16:29:20 +0000 Subject: [PATCH 134/302] Update longest_common_substring.py --- algorithms/dynamic_programming/longest_common_substring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/algorithms/dynamic_programming/longest_common_substring.py b/algorithms/dynamic_programming/longest_common_substring.py index 7777feb2..bf6995ad 100644 --- a/algorithms/dynamic_programming/longest_common_substring.py +++ b/algorithms/dynamic_programming/longest_common_substring.py @@ -8,7 +8,7 @@ def lcs(s1, s2): for i in range(1, rows): for j in range(1, cols): - if s[i-1] == s[j-1]: + if s2[i-1] == s1[j-1]: t[i][j] = t[i-1][j-1] + 1 max_length = max(max_length, t[i][j]) From 817cf18156b86d1d665f4b59d04a216d662baeea Mon Sep 17 00:00:00 2001 From: rogervieiraa Date: Sat, 4 Apr 2020 14:51:55 -0300 Subject: [PATCH 135/302] add number_convertion --- algorithms/math/number_convertion.py | 115 +++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 algorithms/math/number_convertion.py diff --git a/algorithms/math/number_convertion.py b/algorithms/math/number_convertion.py new file mode 100644 index 00000000..533f8ef6 --- /dev/null +++ b/algorithms/math/number_convertion.py @@ -0,0 +1,115 @@ +bases = { + "binary": 2, + "octal": 8, + "decimal": 10, + "hex": 16, + "hexadecimal": 16 +} + +default = 10 + + +def verify_base(x): + """ + Verify if already is an integer + If is not verify if is in the bases + If is not return the default base + """ + try: + return int(x) + except: + if x in bases: + return bases[x] + else: + return default + + +def decimal_value(x): + """ + ord(x) is a function that return the number in asc2 table + we use ord to get the number of an caracter + """ + # TODO verify if in the base exist the character like: + # 'z' doesnt exisist in decimal values + if(x >= '0' and x <= '9'): + return int(x) + elif(x >= 'a' and x <= 'z'): + return int(ord(x) - ord('a') + 10) + elif(x >= 'A' and x <= 'Z'): + return int(ord(x) - ord('A') + 10) + else: + # Error + raise Exception('Number not valid for: ', x) + + +def to_special_caracter(x): + if(x >= 0 and x <= 9): + return str(x) + elif(x > 9): + return chr(ord('a') + x - 10) + else: + raise Exception('Not valid negative number in converter: ', x) + + +def convert(n, from_base, to_base): + """ + This algorithm convert numbers between any base to any base like: + + convert("10",2,10) + ~> "2" + + This function recive 3 parameters + n -> the number + from_base -> base of n | you can pass as number like base 2 or as string like "binary" + to_base -> base of the result | you can pass as number like base 2 or as string like "binary" + + Why the n and the return is an string? + Because bases greater the 10 use leathers to represents the numbers + """ + # TODO verify if number is negative + + n = str(n) + from_base = verify_base(from_base) + to_base = verify_base(to_base) + + # We convert to decimal because is the easy way to convert to all + multi = 1 + decimal_number = 0 + if(from_base == 10): + decimal_number = int(n) + else: + for i in range(len(n) - 1, -1, -1): + decimal_number += (multi * decimal_value(n[i])) + multi *= from_base + + if(to_base == 10): + return str(decimal_number) + + result = "" + + while(decimal_number > 0): + value = decimal_number % to_base + result = to_special_caracter(value) + result + decimal_number = int((decimal_number - value)/to_base) + + return result + + +def test_convert(): + print(convert("1111000111", 2, 8) == "1707") + print(convert("1111000111", 2, 10) == "967") + print(convert("1111000111", 2, 16) == "3c7") + print(convert("1234567", 8, 2) == "1010011100101110111") + print(convert("1234567", 8, 10) == "342391") + print(convert("1234567", 8, 16) == "53977") + print(convert("987123", 10, 2) == "11110000111111110011") + print(convert("987123", 10, 8) == "3607763") + print(convert("987123", 10, 16) == "f0ff3") + print(convert("abcdef", 16, 2) == "101010111100110111101111") + print(convert("abcdef", 16, 8) == "52746757") + print(convert("abcdef", 16, 10) == "11259375") + + print(convert("179", 10, 16) == "b3") + print(convert("b3", 16, 10) == "179") + +test_convert() From 793d958d8a08ac2276c099f2a43a08314f0f8bc3 Mon Sep 17 00:00:00 2001 From: rogervieiraa Date: Sat, 4 Apr 2020 14:58:56 -0300 Subject: [PATCH 136/302] fix issue with negative numbers --- algorithms/math/number_convertion.py | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/algorithms/math/number_convertion.py b/algorithms/math/number_convertion.py index 533f8ef6..aa7c81a2 100644 --- a/algorithms/math/number_convertion.py +++ b/algorithms/math/number_convertion.py @@ -66,12 +66,16 @@ def convert(n, from_base, to_base): Why the n and the return is an string? Because bases greater the 10 use leathers to represents the numbers """ - # TODO verify if number is negative - n = str(n) from_base = verify_base(from_base) to_base = verify_base(to_base) + if(n[0] == '-'): + n = n[1:] + negative = True + else: + negative = False + # We convert to decimal because is the easy way to convert to all multi = 1 decimal_number = 0 @@ -83,7 +87,11 @@ def convert(n, from_base, to_base): multi *= from_base if(to_base == 10): - return str(decimal_number) + decimal_number = str(decimal_number) + if(negative): + decimal_number = '-' + decimal_number + + return decimal_number result = "" @@ -92,6 +100,9 @@ def convert(n, from_base, to_base): result = to_special_caracter(value) + result decimal_number = int((decimal_number - value)/to_base) + if(negative): + result = '-' + result + return result @@ -112,4 +123,10 @@ def test_convert(): print(convert("179", 10, 16) == "b3") print(convert("b3", 16, 10) == "179") + # Negative Tests + print("Negative Tests") + print(convert("-179", 10, 16) == "-b3") + print(convert("-b3", 16, 10) == "-179") + print(convert("-1111000111", 2, 10) == "-967") + test_convert() From 20be9fd9b6a24065e5d50a3b6788b331dbddf87b Mon Sep 17 00:00:00 2001 From: rogervieiraa Date: Sat, 4 Apr 2020 14:59:46 -0300 Subject: [PATCH 137/302] add corner case 0 --- algorithms/math/number_convertion.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/algorithms/math/number_convertion.py b/algorithms/math/number_convertion.py index aa7c81a2..2d3e2c75 100644 --- a/algorithms/math/number_convertion.py +++ b/algorithms/math/number_convertion.py @@ -70,6 +70,10 @@ def convert(n, from_base, to_base): from_base = verify_base(from_base) to_base = verify_base(to_base) + # Corner case 0 + if(n == "0"): + return n + if(n[0] == '-'): n = n[1:] negative = True From 985d77b426d47ac3fb70be7991898cc6ed5e4e8e Mon Sep 17 00:00:00 2001 From: rogervieiraa Date: Sat, 4 Apr 2020 15:03:35 -0300 Subject: [PATCH 138/302] fix pep8 on comments --- algorithms/math/number_convertion.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/algorithms/math/number_convertion.py b/algorithms/math/number_convertion.py index 2d3e2c75..e119eb9c 100644 --- a/algorithms/math/number_convertion.py +++ b/algorithms/math/number_convertion.py @@ -60,8 +60,9 @@ def convert(n, from_base, to_base): This function recive 3 parameters n -> the number - from_base -> base of n | you can pass as number like base 2 or as string like "binary" - to_base -> base of the result | you can pass as number like base 2 or as string like "binary" + from_base -> base of n | + to_base -> base of the result | + you can pass the bases as number like base 2 or as string like "binary" Why the n and the return is an string? Because bases greater the 10 use leathers to represents the numbers From 3e2263cd7ddd0056d59c66b676fbf595549f2ec6 Mon Sep 17 00:00:00 2001 From: rogervieiraa Date: Sat, 4 Apr 2020 15:05:03 -0300 Subject: [PATCH 139/302] add in the documents --- algorithms/math/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/algorithms/math/index.md b/algorithms/math/index.md index e84f7095..fc7b2649 100644 --- a/algorithms/math/index.md +++ b/algorithms/math/index.md @@ -5,4 +5,4 @@ * [Nth Prime Number](prime.py) * [Sieve of Erastothenes](sieve_of_eratosthenes.py) * [Perfect Square](perfect_square.py) - +* [Number Convertion](number_convertion.py) From 8e0d2b6d8b2cb20deae1252bd1b87461451b29bd Mon Sep 17 00:00:00 2001 From: Tanmoy Mukherjee Date: Wed, 15 Apr 2020 01:59:14 +0530 Subject: [PATCH 140/302] Update maxprod.py --- data_structures/array/max_product.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/data_structures/array/max_product.py b/data_structures/array/max_product.py index e69de29b..81ee1f70 100644 --- a/data_structures/array/max_product.py +++ b/data_structures/array/max_product.py @@ -0,0 +1,16 @@ +def max_product(arr): + n = len(arr) + if n == 0: + return 0 + if n == 1: + return arr[0] + a = arr[0] + b = arr[1] + maxprod = a * b + for i in range(n): + for j in range(i + 1, n): + if (arr[i] * arr[j]) > maxprod: + a = arr[i] + b = arr[j] + maxprod = a * b + return maxprod From bee1ee73669281c9c2910ffafd23da16d72731a4 Mon Sep 17 00:00:00 2001 From: durid17 Date: Sat, 18 Apr 2020 14:54:22 +0400 Subject: [PATCH 141/302] Z_Algorithm --- algorithms/dynamic_programming/Z_Algorithm.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 algorithms/dynamic_programming/Z_Algorithm.py diff --git a/algorithms/dynamic_programming/Z_Algorithm.py b/algorithms/dynamic_programming/Z_Algorithm.py new file mode 100644 index 00000000..6af4c894 --- /dev/null +++ b/algorithms/dynamic_programming/Z_Algorithm.py @@ -0,0 +1,30 @@ +class Z_Algorithm(): + """ + return all occurences of string s in text, returns its indexes starting from zero + delimeter should be charachter which will not occur neither is S nor in text + by default its '$' + """ + @staticmethod + def find_occurrences(s:str , text:str , delimeter = '$'): + return Z_Algorithm.z_function(s + delimeter + text , len(s)) + + @staticmethod + def z_function(text:str , size:int): + l = 0 + r = 0 + z = [0] * len(text) + for i in range(1 , len(text)): + if i <= r: + z[i] = min(r - i + 1 , z[i - l]) + while i + z[i] < len(text) and text[z[i]] == text[i + z[i]]: + z[i] += 1 + + if i + z[i] - 1 > r: + l = i + r = i + z[i] - 1 + + res = [] + for i in range(size , len(text)): + if z[i] == size: + res.append(i - size - 1) + return res \ No newline at end of file From 520e89923c5a50c9f7e5050c8e111500c87245bd Mon Sep 17 00:00:00 2001 From: shotanozadze Date: Mon, 20 Apr 2020 23:19:58 +0400 Subject: [PATCH 142/302] Deque Implementation --- .DS_Store | Bin 0 -> 8196 bytes data_structures/.DS_Store | Bin 0 -> 8196 bytes data_structures/deque/.DS_Store | Bin 0 -> 6148 bytes data_structures/deque/deque.py | 68 ++++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+) create mode 100644 .DS_Store create mode 100644 data_structures/.DS_Store create mode 100644 data_structures/deque/.DS_Store create mode 100644 data_structures/deque/deque.py diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..796478d40382de070f3963a44c55518e0a16a8ce GIT binary patch literal 8196 zcmeHMUvC>l5T8vAxpQcIX%muEMLJ<2DmAK7InW1G)i^Q5qTpbgG$C!>vv1>^a=Eqc z&PkIH6e017#2Xax#vk=FAR$C~fKLD~RX+kqhzFj^>>sBWJE1~I2(`P??#%7Z%zA&b zGpk(#04a3b^8gb7U|{9c8p7s~!pC{-D+8)$7%4%0fDk;0VHMUP>XX(T8Uc-fMnEH= z5zq+y9}vJZn-}AVb6<|?RwJMhcp?$t`N77@XHN`X`(6}JPya#&j-{S@ zdeAV_L*~%%ka@kj$~LR96L+G56V|QMRnMgjC%o#p@oJ3*MW1fapd4OtVj3=U;TmH; z3P|2*EO>OYZjH{eAa=ZfhQgk-aqX%XxNNh)I)NJrd1YMi^G>{qc8qME+F}u=Vb-mQ zot<3nr71f%liQuLcP?C*p0a0hFYoS}hB5i#Yn2eQ?j5BtiiL`?p?VX!^_|LQxPXDRv^q;#c>18r zlfIBX{rCPgj7Rx${Dt!uOE=fIws+p!eg9KjB9?teX5{yNdmFh7{4Ho+b3^TQ@@;q7 z_bsctaNOAH2Y;WXD;A>X32%x7W2@6hE|=(*Ll z)AWMYVoYzvRd1WttrI<>73$u2*j3wVqs-{T4q@(cNNFJKl~-0G8ZRdJrMi`gnj!Q3 zc@}xG$AYD65e8T(rt76(h2e}F7+mExABq-e7$NP`SzL0$&!w9iRi(B!Ul1HB)RLAS5K;)?&>K<^8~~+p91;u14zWX8LQpRJ z190WUZ*b!a_yc}`4}dqjOJqAOLGnEHHp~HW%xZ_rAJoTEl>0 z;J;*m_Xiu5Wl77il5*=nBU1p#94^a(KJoymV{2K`a;&6O#h5C45L#8}6hkO=+_xDH zS<-T>q*5oL)JbT|LT4yKT8Ex3;Ur2*n$|F27?@^&bN3~gvwIYz^7rEdKWsRD=m5cs z>N@J>ud<*=l&3oNaMUS_e4jxslY@~1i9d#|7+OsnQQCr7&*;rTFQPbudX+(~Q3Ip* z(DuofHfoS;?+I+Uu*YZ9<9x}ClLxj*Pccd}ZILh^ag>_*1nCT-uIA{Y)AhY5-roKs z&dufW^9z<$unOl3kE-o(P>t(xKPuOI5BTg(J#IU?e>V*MNx$yg^O}R&%G#|ki0fX^ z>`7(MZ36P}z8ARRpd9uCH2F z*80Vr8wZD-3C^``)I(G*j2kN{RnW+E98#v^kdr?Q g(YFC*osyPgC2X8`y+#aAI`XaRdf}Lubo00w ZeCKQj`k#A9M z-V+t2fD|}Z;4-&!_WyhMnfd>iq@5Iy0{=<@pRFEOOT1F`*2&AU*EaYQoHZYC8rDHU mh;|H&c8m?%@pTksUE><(y>LtnI`TmW>dydmkx7BSR^SVP1shiY literal 0 HcmV?d00001 diff --git a/data_structures/deque/deque.py b/data_structures/deque/deque.py new file mode 100644 index 00000000..d578c8e2 --- /dev/null +++ b/data_structures/deque/deque.py @@ -0,0 +1,68 @@ +class Deque(): + def __init__(self): + self.data = list() + + def push_front(self, elem): + temp = list() + temp.append(elem) + + for i in self.data: + temp.append(i) + + self.data = temp + + def push_back(self, elem): + self.data.append(elem) + + def pop_front(self): + temp = list() + + for i in range(0, len(self.data)): + if not i==0: + temp.append(self.data[i]) + + self.data = temp + + def pop_back(self): + temp = list() + + for i in range(0, len(self.data)): + if not i==len(self.data)-1: + temp.append(self.data[i]) + + self.data = temp + + def get_first(self): + if(len(self.data)>0): + return self.data[0] + else: + return "Deque is empty" + + def get_last(self): + if(len(self.data)>0): + return self.data[len(self.data)-1] + else: + return "Deque is empty" + + def size(self): + return len(self.data) + + def isEmpty(self): + if len(self.data) == 0: + return True + return False + + def contains(self, elem): + for i in self.data: + if i==elem: + return True + + return False + + def printElems(self): + result = "" + + for i in self.data: + result += str(i) + " | " + + print(result) \ No newline at end of file From 51774fe95eaf5703c9174cfad73a651e50cf1f18 Mon Sep 17 00:00:00 2001 From: Shota Nozadze <48485182+shotanozadze@users.noreply.github.com> Date: Tue, 21 Apr 2020 13:51:10 +0400 Subject: [PATCH 143/302] Delete ds_store --- .DS_Store | Bin 8196 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 796478d40382de070f3963a44c55518e0a16a8ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHMUvC>l5T8vAxpQcIX%muEMLJ<2DmAK7InW1G)i^Q5qTpbgG$C!>vv1>^a=Eqc z&PkIH6e017#2Xax#vk=FAR$C~fKLD~RX+kqhzFj^>>sBWJE1~I2(`P??#%7Z%zA&b zGpk(#04a3b^8gb7U|{9c8p7s~!pC{-D+8)$7%4%0fDk;0VHMUP>XX(T8Uc-fMnEH= z5zq+y9}vJZn-}AVb6<|?RwJMhcp?$t`N77@XHN`X`(6}JPya#&j-{S@ zdeAV_L*~%%ka@kj$~LR96L+G56V|QMRnMgjC%o#p@oJ3*MW1fapd4OtVj3=U;TmH; z3P|2*EO>OYZjH{eAa=ZfhQgk-aqX%XxNNh)I)NJrd1YMi^G>{qc8qME+F}u=Vb-mQ zot<3nr71f%liQuLcP?C*p0a0hFYoS}hB5i#Yn2eQ?j5BtiiL`?p?VX!^_|LQxPXDRv^q;#c>18r zlfIBX{rCPgj7Rx${Dt!uOE=fIws+p!eg9KjB9?teX5{yNdmFh7{4Ho+b3^TQ@@;q7 z_bsctaNOAH2Y;WXD;A>X32%x7W2@6hE|=(*Ll z)AWMYVoYzvRd1WttrI<>73$u2*j3wVqs-{T4q@(cNNFJKl~-0G8ZRdJrMi`gnj!Q3 zc@}xG$AYD65e8T(rt76(h2e}F7+mExABq-e7$NP`SzL0$& Date: Wed, 22 Apr 2020 11:33:06 +0400 Subject: [PATCH 144/302] Delete .DS_Store --- data_structures/.DS_Store | Bin 8196 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 data_structures/.DS_Store diff --git a/data_structures/.DS_Store b/data_structures/.DS_Store deleted file mode 100644 index e8e8cc9df611b98d9d158f1c9f0b16d2d2b5410d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHM!EVz)5S^t->!w9iRi(B!Ul1HB)RLAS5K;)?&>K<^8~~+p91;u14zWX8LQpRJ z190WUZ*b!a_yc}`4}dqjOJqAOLGnEHHp~HW%xZ_rAJoTEl>0 z;J;*m_Xiu5Wl77il5*=nBU1p#94^a(KJoymV{2K`a;&6O#h5C45L#8}6hkO=+_xDH zS<-T>q*5oL)JbT|LT4yKT8Ex3;Ur2*n$|F27?@^&bN3~gvwIYz^7rEdKWsRD=m5cs z>N@J>ud<*=l&3oNaMUS_e4jxslY@~1i9d#|7+OsnQQCr7&*;rTFQPbudX+(~Q3Ip* z(DuofHfoS;?+I+Uu*YZ9<9x}ClLxj*Pccd}ZILh^ag>_*1nCT-uIA{Y)AhY5-roKs z&dufW^9z<$unOl3kE-o(P>t(xKPuOI5BTg(J#IU?e>V*MNx$yg^O}R&%G#|ki0fX^ z>`7(MZ36P}z8ARRpd9uCH2F z*80Vr8wZD-3C^``)I(G*j2kN{RnW+E98#v^kdr?Q g(YFC*osyPgC2 Date: Wed, 22 Apr 2020 11:33:24 +0400 Subject: [PATCH 145/302] Delete .DS_Store --- data_structures/deque/.DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 data_structures/deque/.DS_Store diff --git a/data_structures/deque/.DS_Store b/data_structures/deque/.DS_Store deleted file mode 100644 index 581a88fc38e6837702b00784b44de149a97e16b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKF-`+P474G|Ni-=bw@igZO|yzZLCptH61qr%A_d)5yo;Z~jBO#JODaTz#*#g| zUe9fAigRpczC3Ji&E{q{z=`(GFg2djCw5U82g31;XS=Z%dwbaJHX8`y+#aAI`XaRdf}Lubo00w ZeCKQj`k#A9M z-V+t2fD|}Z;4-&!_WyhMnfd>iq@5Iy0{=<@pRFEOOT1F`*2&AU*EaYQoHZYC8rDHU mh;|H&c8m?%@pTksUE><(y>LtnI`TmW>dydmkx7BSR^SVP1shiY From e44a71a05f19ef94464fca553884fa3d3d679d4b Mon Sep 17 00:00:00 2001 From: tasbihaasim Date: Wed, 22 Apr 2020 17:23:53 +0500 Subject: [PATCH 146/302] Add front and back search --- .../miscellaneous/front_and_back_search.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 algorithms/miscellaneous/front_and_back_search.py diff --git a/algorithms/miscellaneous/front_and_back_search.py b/algorithms/miscellaneous/front_and_back_search.py new file mode 100644 index 00000000..04e129ac --- /dev/null +++ b/algorithms/miscellaneous/front_and_back_search.py @@ -0,0 +1,26 @@ +def front_and_back_search(lst, item): + ''' + args: + lst: an unsorted array of integers + item: data to be found + + return: + item which is found else False + ''' + rear=0 + front=len(lst)-1 + u=None + if rear>front: + return False + else: + while rear<=front: + if item==lst[rear] or item==lst[front]: + u='' + return True ##item found + elif item!=lst[rear] and item!=lst[front]: + if item > lst[rear]: + rear=rear+1 + elif item < lst[front]: + front=front-1 + if u==None: + return False From 4974fbc4a81a57057dbb913321595d8ef5ecd05d Mon Sep 17 00:00:00 2001 From: Rithwik Ediga Lakhamsani Date: Sat, 25 Apr 2020 17:46:14 -0700 Subject: [PATCH 147/302] Add Longest Palindromic Substring --- .../longest_palindromic_substring.py | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 algorithms/dynamic_programming/longest_palindromic_substring.py diff --git a/algorithms/dynamic_programming/longest_palindromic_substring.py b/algorithms/dynamic_programming/longest_palindromic_substring.py new file mode 100644 index 00000000..251d2e7f --- /dev/null +++ b/algorithms/dynamic_programming/longest_palindromic_substring.py @@ -0,0 +1,57 @@ +def longest_palindromic_substring_DP(s): + + S = [[False for i in range(len(s))] for j in range(len(s))] + + max_palindrome = "" + + for i in range(len(s))[::-1]: + for j in range(i, len(s)): + # if j - 1 < 3, then there is one or two characters between these + # two positions, implying that if s[i] == s[j] + # then that small string is a palindrome + # We check if the above cases is valid or i + # they are larger, we use DP to check the substring + # in between j and i + S[i][j] = s[i] == s[j] and (j - i < 3 or S[i+1][j-1]) + if S[i][j] and j - i + 1 > len(max_palindrome): + max_palindrome = s[i:j+1] + + return max_palindrome + + +def longest_palindromic_substring_expansion(s): + max_palindrome = "" + + for i in range(len(s) * 2 - 1): + if i % 2 == 0: + # This is when you are "on" an actual character + # o = offset, ind = current character + o = 0 + ind = i // 2 + while ind + o < len(s) and ind - o >= 0: + if(s[ind + o] != s[ind - o]): + break + if ind + o - (ind - o) + 1 > len(max_palindrome): + max_palindrome = s[ind-o:ind+o + 1] + o += 1 + else: + # This is when you are "in the middle of" two characters + # o = offset, sind = start char, eind = end char + o = 0 + sind = i // 2 + eind = i // 2 + 1 + while sind - o >= 0 and eind + o < len(s): + if(s[sind - o] != s[eind + o]): + break + if eind + o - (sind - o) + 1 > len(max_palindrome): + max_palindrome = s[sind - o:eind + o + 1] + o += 1 + + return max_palindrome + + +input_string = "abbbacdcaacdca" + +ans_DP = longest_palindromic_substring_DP(input_string) +ans_expansion = longest_palindromic_substring_expansion(input_string) +print("DP Solution: {}, Expansion Solution: {}".format(ans_DP, ans_expansion)) From 53a140dee849ffb7c4dac747e9262cf706ee063d Mon Sep 17 00:00:00 2001 From: chandanatochandu Date: Tue, 28 Apr 2020 15:04:57 +0500 Subject: [PATCH 148/302] KMP Pattern Searching Algorithm --- data_structures/strings/KMP_Pattern_Search.py | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 data_structures/strings/KMP_Pattern_Search.py diff --git a/data_structures/strings/KMP_Pattern_Search.py b/data_structures/strings/KMP_Pattern_Search.py new file mode 100644 index 00000000..37bfcd2c --- /dev/null +++ b/data_structures/strings/KMP_Pattern_Search.py @@ -0,0 +1,57 @@ +#Python program for KMP Algorithm +def KMP_pattern_search(pattern, text): + P = len(pattern) + Q = len(text) + + # create long_prefix_suffix[] that will hold the longest prefix suffix + # values for pattern + long_prefix_suffix = [0]*P + + # index for pattern[] + j=0 + + # preprocess the pattern (caluclate long_prefix_suffix[] array) + long_Prefix_Suffix_Array(pattern, P, long_prefix_suffix) + + # index for text[] + i=0 + + while i < Q: + if pattern[j] == text[i]: + i += 1 + j += 1 + + if j == P: + print("Pattern found at index " + str(i-j)) + j=long_prefix_suffix[j-1] + + # mismatch after j matches + elif i < Q and pattern[j] != text[i]: + if j != 0: + j=long_prefix_suffix[j-1] + else: + i += 1 + +def long_Prefix_Suffix_Array(pattern, P, long_prefix_suffix): + # length of the previous longest prefix suffix + l=0 + long_prefix_suffix[0]=0 + i=1 + + # the loop calculates long_prefix_suffix[i] for i = 1 to P-1 + while i < P: + if pattern[i] == pattern[l]: + l += 1 + long_prefix_suffix[i] = l + i += 1 + else: + if l != 0: + l=long_prefix_suffix[l-1] + else: + long_prefix_suffix[i] = 0 + i += 1 + +text = "ABABDABACDABABCABAB" +pattern = "ABABCABAB" +KMP_pattern_search(pattern, text) + From 52653e640806621bddcd5cc61d7c069edbd3a8b8 Mon Sep 17 00:00:00 2001 From: lucifermorningstar Date: Sun, 3 May 2020 03:49:11 -0500 Subject: [PATCH 149/302] Bubble Sort Fix --- algorithms/sorting/bubble_sort.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/algorithms/sorting/bubble_sort.py b/algorithms/sorting/bubble_sort.py index 85668cac..7cd5321e 100644 --- a/algorithms/sorting/bubble_sort.py +++ b/algorithms/sorting/bubble_sort.py @@ -1,12 +1,18 @@ -''' +""" Bubble Sort worst time complexity occurs when array is reverse sorted - O(n^2) Best time scenario is when array is already sorted - O(n) -''' +""" + def bubble_sort(array): - n = len(array) + has_swapped = True + + num_of_iterations = 0 - for i in range(n): - for j in range(0, n-i-1): - if array[j] > array[j+1]: - array[j], array[j+1] = array[j+1], array[j] \ No newline at end of file + while has_swapped: + has_swapped = False + for i in range(len(array) - num_of_iterations - 1): + if array[i] > array[i + 1]: + array[i], array[i + 1] = array[i + 1], array[i] + has_swapped = True + num_of_iterations += 1 From 114541e7ef1098ce13e4e08aaef37b607a45cb1b Mon Sep 17 00:00:00 2001 From: lucifermorningstar Date: Sun, 3 May 2020 04:11:20 -0500 Subject: [PATCH 150/302] min_product fix --- data_structures/array/min_product.py | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/data_structures/array/min_product.py b/data_structures/array/min_product.py index e83cf5e6..01bbfcb9 100644 --- a/data_structures/array/min_product.py +++ b/data_structures/array/min_product.py @@ -7,45 +7,44 @@ # If there are odd number of negative numbers and no zeros, # the result is simply the product of all -# If there is a zero and al other are positive, then the result is zero +# If there is a zero and all other are positive, then the result is zero # If there are only positive numbers, the the result is # the smallest positive number + def find(arr): if len(arr) == 1: return arr[0] - + count_negative = 0 - count_positive = 0 count_zero = 0 max_neg = float('-inf') min_pos = float('inf') - + prod = 1 - + for num in arr: if num == 0: count_zero += 1 continue if num < 0: - count_neg += 1 + count_negative += 1 max_neg = max(max_neg, num) if num > 0: min_pos = min(min_pos, num) - prod = prod * num + prod *= num - if count_zero == len(arr) or (count_neg == 0 and count_zero > 0): + if count_zero == len(arr) or (count_negative == 0 and count_zero > 0): return 0 - - if count_neg == 0: + + if count_negative == 0: return min_pos - if count_neg & 1 == 0 and count_neg != 0: + if count_negative & 1 == 0 and count_negative != 0: prod = int(prod / max_neg) - - return prod + return prod From d16c253747923e1e93ee8222244f36a71d33cce0 Mon Sep 17 00:00:00 2001 From: bnMikheili Date: Sun, 17 May 2020 03:30:23 +0400 Subject: [PATCH 151/302] add counting sort implementation --- algorithms/sorting/counting_sort.py | 35 +++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 algorithms/sorting/counting_sort.py diff --git a/algorithms/sorting/counting_sort.py b/algorithms/sorting/counting_sort.py new file mode 100644 index 00000000..d9f359c8 --- /dev/null +++ b/algorithms/sorting/counting_sort.py @@ -0,0 +1,35 @@ +""" +High level description: +Counting sort is a sorting technique based on keys between a specific range, +with efective performance on the predetermined range size of the values. +It works by counting the number of objects having distinct key values (kind of hashing). +Then doing some arithmetic to calculate the position of each object in the output sequence. + +Time complexity: +O(n+k) where n is the number of elements in input array and k is the range of input. + +Auxiliary Space: O(n+k) +""" + +def counting_sort(arr): + # Find min and max values + min_value = min(arr) + max_value = max(arr) + + # Count number appearances in the array + counting_arr = [0]*(max_value-min_value+1) + for num in arr: + counting_arr[num-min_value] += 1 + + # Rearrange sequence in the array + index = 0 + for i, count in enumerate(counting_arr): + for _ in range(count): + arr[index] = min_value + i + index += 1 + +test_array = [3, 3, 2, 6, 4, 7, 9, 7, 8] + +counting_sort(test_array) + +print(test_array) From 7ff39c6fbee9f7399cadbe6a181dab5ca5822927 Mon Sep 17 00:00:00 2001 From: beqakd Date: Tue, 19 May 2020 18:44:31 +0400 Subject: [PATCH 152/302] add implementation of MST alghoritm --- algorithms/graph/mst.py | 97 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 algorithms/graph/mst.py diff --git a/algorithms/graph/mst.py b/algorithms/graph/mst.py new file mode 100644 index 00000000..fc1fdeb2 --- /dev/null +++ b/algorithms/graph/mst.py @@ -0,0 +1,97 @@ +# i checked your other py files and decided that i would go for default dict too +# i used same structure as needed for this repository. +from collections import defaultdict +r = range + + +class Graph: + # Class initializer + def __init__(self, vertices): + # num of vertices and our starting graph + + self.vertices = vertices + # Values will be [start_point, end_point, weight] + self.graph = [] + + # Add edge to graph + def add_edge(self, start, end, weight): + value = [start, end, weight] + self.graph.append(value) + + # Simple search alghoritm + def search(self, parent_ranks, index): + if parent_ranks[index] != index: + return self.search(parent_ranks, parent_ranks[index]) + return index + + def union(self, ranks, parent_ranks, fir, sec): + fir, sec = self.search(parent_ranks, fir), self.search( + parent_ranks, sec) + + # 3 steps. ranks lower, higher, same + + if (ranks[fir] > ranks[sec]): + parent_ranks[sec] = fir + + elif (ranks[fir] < ranks[sec]): + parent_ranks[fir] = sec + + elif (ranks[fir] == ranks[sec]): + parent_ranks[sec] = fir + ranks[fir] += 1 + + # run mst alghoritm main part. + + def run_mst(self, ranks, parent_ranks, answer): + edge, index = 0, 0 + + while True: + if ((self.vertices - 1) <= edge): + break + + # Take value + value = self.graph[index] + + # check cycle + fir, sec = self.search(parent_ranks, value[0]), self.search( + parent_ranks, value[1]) + + if fir != sec: + edge += 1 # increase edge + + # append and union + answer.append(value) + self.union(ranks, parent_ranks, fir, sec) + + index += 1 + + def print_graph(self, answer): + for start, end, weight in answer: + print(f"{start} - {end} --> {weight}") + + # Main function for mst alghoritm + def MST(self): + # sort the graph + self.graph = sorted(self.graph, key=lambda item: item[2]) + + # For this alghoritm we need two array. + ranks = [0] * self.vertices + parent_ranks = [_ for _ in r(self.vertices)] + answer = [] + + self.run_mst(ranks, parent_ranks, answer) + self.print_graph(answer) + + +def main(): + g = Graph(4) + g.add_edge(0, 1, 10) + g.add_edge(0, 2, 6) + g.add_edge(0, 3, 5) + g.add_edge(1, 3, 15) + g.add_edge(2, 3, 4) + g.MST() + + +if __name__ == "__main__": + main() From dbeea5eb05d9da00ac0b0bf86bad5f6c23985940 Mon Sep 17 00:00:00 2001 From: beqakd Date: Tue, 19 May 2020 18:48:17 +0400 Subject: [PATCH 153/302] removed extra main --- algorithms/graph/mst.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/algorithms/graph/mst.py b/algorithms/graph/mst.py index fc1fdeb2..a4c08b0e 100644 --- a/algorithms/graph/mst.py +++ b/algorithms/graph/mst.py @@ -81,17 +81,3 @@ def MST(self): self.run_mst(ranks, parent_ranks, answer) self.print_graph(answer) - - -def main(): - g = Graph(4) - g.add_edge(0, 1, 10) - g.add_edge(0, 2, 6) - g.add_edge(0, 3, 5) - g.add_edge(1, 3, 15) - g.add_edge(2, 3, 4) - g.MST() - - -if __name__ == "__main__": - main() From 75468a5b9166bf0276b4b1431b513400df82e270 Mon Sep 17 00:00:00 2001 From: beqakd Date: Tue, 19 May 2020 18:51:08 +0400 Subject: [PATCH 154/302] check for pip8 style --- algorithms/graph/mst.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/algorithms/graph/mst.py b/algorithms/graph/mst.py index a4c08b0e..930a2211 100644 --- a/algorithms/graph/mst.py +++ b/algorithms/graph/mst.py @@ -1,4 +1,4 @@ -# i checked your other py files and decided that i would go for default dict too +# i checked your other py files and decided that i would go for default dict # i used same structure as needed for this repository. from collections import defaultdict r = range From 716a4ac97fa8c9c476f15e71879e372b999aefa1 Mon Sep 17 00:00:00 2001 From: shotanozadze Date: Fri, 22 May 2020 19:09:07 +0400 Subject: [PATCH 155/302] division factors --- .gitignore | 1 + algorithms/math/divisors.py | 63 +++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 algorithms/math/divisors.py diff --git a/.gitignore b/.gitignore index c7126040..40202465 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ questions_to_do.txt +.DS_Store diff --git a/algorithms/math/divisors.py b/algorithms/math/divisors.py new file mode 100644 index 00000000..ea923837 --- /dev/null +++ b/algorithms/math/divisors.py @@ -0,0 +1,63 @@ +import math + +class divisors: + + def findAllDivisors(self, n): + result = list() + + for i in range(1, n+1): + if (n%i == 0): + result.append(i) + + return result + + def divisorsCount(self, n): + divs = self.findAllDivisors(n) + return len(divs) + + def oddFactors(self, n): + result = list() + + for i in range(1, n+1): + if (n%i == 0 and i%2==1): + result.append(i) + + return result + + def oddFactorsSum(self, n): + divs = self.evenFactors(n) + return sum(divs) + + def evenFactors(self, n): + result = list() + + for i in range(1, n+1): + if (n%i == 0 and i%2==0): + result.append(i) + + return result + + def evenFactorsSum(self, n): + divs = self.evenFactors(n) + return sum(divs) + + def primeFactors(self, n): + result = list() + + while n % 2 == 0: + result.append(2) + n = n / 2 + + for i in range(3,int(math.sqrt(n))+1,2): + while n % i== 0: + result.append(i) + n = n / i + + if n > 2: + result.append(n) + + return result + + def primeFactorsSum(self, n): + divs = self.primeFactors(n) + return sum(divs) \ No newline at end of file From aa804e3ced753d446931aa21ae140ea1b5f05442 Mon Sep 17 00:00:00 2001 From: mmbhatk Date: Fri, 22 May 2020 21:02:11 +0530 Subject: [PATCH 156/302] Find the sum of number of set bits in a range of numbers --- README.md | 1 + .../bit_manipulation/range_sum_set_bits.py | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 algorithms/bit_manipulation/range_sum_set_bits.py diff --git a/README.md b/README.md index 14069301..7b205f4e 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ This directory contains various types of algorithm questions like Dynamic Progra 4. [Math](algorithms/math) 5. [Misc](algorithms/miscellaneous) 6. [Sorting](algorithms/sorting) +7. [Bit Manipulation](algorithms/bit_manipulation) ### Bookmarks diff --git a/algorithms/bit_manipulation/range_sum_set_bits.py b/algorithms/bit_manipulation/range_sum_set_bits.py new file mode 100644 index 00000000..6250acf9 --- /dev/null +++ b/algorithms/bit_manipulation/range_sum_set_bits.py @@ -0,0 +1,19 @@ +# Question: Find the sum of number of set bits in all the numbers in the range [1, n]. + +def countBits(n): + + """ Consider a number x and half of the number (x//2). + The binary representation of x has all the digits as + the binary representation of x//2 followed by an additional + digit at the last position. Therefore, we can find the number + of set bits in x by finding the number of set bits in x//2 + and determining whether the last digit in x is 0 or 1. """ + + res = [0] * (n+1) + for i in range(1, n+1): + res[i] = res[i//2] + (i & 1) + return sum(res) + + +# Extension: Find the sum of number of set bits in all the numbers in the range [m, n]. +# Answer: In countBits(m, n), return sum(res) - sum(res[:m]) \ No newline at end of file From 9d3b6ba0c51f8510ca25eae04ec437e0b21f7ac1 Mon Sep 17 00:00:00 2001 From: durid17 Date: Mon, 25 May 2020 15:49:04 +0400 Subject: [PATCH 157/302] SumSegTree --- data_structures/segment_tree/seg_tree_sum.py | 42 ++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 data_structures/segment_tree/seg_tree_sum.py diff --git a/data_structures/segment_tree/seg_tree_sum.py b/data_structures/segment_tree/seg_tree_sum.py new file mode 100644 index 00000000..ee7481f9 --- /dev/null +++ b/data_structures/segment_tree/seg_tree_sum.py @@ -0,0 +1,42 @@ +class SumSegTree(): + + def __init__(self, n, arr = None): + self._t = [0] * (4 * n) + self._n = n + if arr: self._build(arr, 1 , 0 , n - 1) + + def _build(self, a, v, tl, tr): + if tl == tr: + self._t[v] = a[tl] + else: + tm = (tl + tr) // 2 + self._build(a, v*2, tl, tm) + self._build(a, v*2+1, tm+1, tr) + self._t[v] = self._t[v*2] + self._t[v*2+1] + + def _sum_util(self, v, tl, tr, l, r): + if l > r: return 0 + + if l == tl and r == tr : return self._t[v] + + tm = (tl + tr) // 2 + return self._sum_util(v*2, tl, tm, l, min(r, tm)) + self._sum_util(v*2+1, tm+1, tr, max(l, tm+1), r) + + def _update_util(self, v, tl, tr, pos, new_val): + if tl == tr: + self._t[v] = new_val + else: + tm = (tl + tr) // 2 + if pos <= tm: self._update_util(v*2, tl, tm, pos, new_val) + else: self._update_util(v*2+1, tm+1, tr, pos, new_val) + self._t[v] = self._t[v*2] + self._t[v*2+1] + + def sum(self, l, r): + return self._sum_util(1 , 0 , self._n - 1 , l , r) + + def update(self, pos, new_val): + self._update_util(1 , 0 , self._n - 1 , pos , new_val) + + def add(self, pos, change): + value = self._sum(pos , pos) + self._update_util(1 , 0 , self._n - 1 , pos , value + change) \ No newline at end of file From 4f8199d9d21ffb20371193292b6e0c8528da84a6 Mon Sep 17 00:00:00 2001 From: durid17 Date: Mon, 25 May 2020 16:36:15 +0400 Subject: [PATCH 158/302] MaxSegTree --- data_structures/segment_tree/seg_tree_max.py | 44 ++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 data_structures/segment_tree/seg_tree_max.py diff --git a/data_structures/segment_tree/seg_tree_max.py b/data_structures/segment_tree/seg_tree_max.py new file mode 100644 index 00000000..eb40f116 --- /dev/null +++ b/data_structures/segment_tree/seg_tree_max.py @@ -0,0 +1,44 @@ +import sys + +class MaxSegTree(): + + def __init__(self, n, arr = None): + self._t = [-sys.maxsize - 1] * (4 * n) + self._n = n + if arr: self._build(arr, 1 , 0 , n - 1) + + def _build(self, a, v, tl, tr): + if tl == tr: + self._t[v] = a[tl] + else: + tm = (tl + tr) // 2 + self._build(a, v*2, tl, tm) + self._build(a, v*2+1, tm+1, tr) + self._t[v] = max(self._t[v*2] ,self._t[v*2+1]) + + def _max_util(self, v, tl, tr, l, r): + if l > r: return -sys.maxsize - 1 + + if l == tl and r == tr : return self._t[v] + + tm = (tl + tr) // 2 + return max(self._max_util(v*2, tl, tm, l, min(r, tm)) ,self._max_util(v*2+1, tm+1, tr, max(l, tm+1), r)) + + def _update_util(self, v, tl, tr, pos, new_val): + if tl == tr: + self._t[v] = new_val + else: + tm = (tl + tr) // 2 + if pos <= tm: self._update_util(v*2, tl, tm, pos, new_val) + else: self._update_util(v*2+1, tm+1, tr, pos, new_val) + self._t[v] = max(self._t[v*2] , self._t[v*2+1]) + + def max_element(self, l, r): + return self._max_util(1 , 0 , self._n - 1 , l , r) + + def update(self, pos, new_val): + self._update_util(1 , 0 , self._n - 1 , pos , new_val) + + def add(self, pos, change): + value = self.max_element(pos , pos) + self._update_util(1 , 0 , self._n - 1 , pos , value + change) \ No newline at end of file From 49d1b54d13f129b9619813f6845cb8d5536ac1d5 Mon Sep 17 00:00:00 2001 From: beqakd Date: Thu, 4 Jun 2020 19:09:19 +0400 Subject: [PATCH 159/302] add dijkstra alghoritm. --- algorithms/graph/dijkstra.py | 55 ++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 algorithms/graph/dijkstra.py diff --git a/algorithms/graph/dijkstra.py b/algorithms/graph/dijkstra.py new file mode 100644 index 00000000..91dbe362 --- /dev/null +++ b/algorithms/graph/dijkstra.py @@ -0,0 +1,55 @@ +# i checked your other py files and decided that i would go for default dict +# i used same structure as needed for this repository. +from collections import defaultdict +import sys +r = range +# min weight goes for 0 in this case +max_weight = sys.maxsize + + +class Graph: + # Class initializer + def __init__(self, vertices): + # num of vertices and our starting graph + self.vertices = vertices + + # Values will be [[]] two deminsial array with + # columns for start going to rows. + self.graph = [[0] * self.vertices for _ in r(self.vertices)] + self.visited = [0] * self.vertices # to control visited vertices + # for our distances to minimaze them. + self.distances = [max_weight] * self.vertices + + # Add edge to graph start --> end point with specific weight! + def add_edge(self, start, end, weight): + self.graph[start][end] = weight + + def print_dist(self, dist): + for _ in r(self.vertices): + print("vert ", _, "\tdist ", self.distances[_]) + + def dijkstra(self, end_point): + self.distances[end_point] = 0 + + for vert in r(self.vertices): + + # we need to check for minimum but not visited!! + my_min, min_index = max_weight, 0 + for _ in r(self.vertices): + if not self.visited[_]: + if my_min > self.distances[_]: + my_min = self.distances[_] + min_index = _ + + # check the flag for visited + self.visited[min_index] = 1 + + # # iterate and update if needed + for adj in r(self.vertices): + # check for edge and visited + val = self.graph[min_index][adj] + if not self.visited[adj] and val != 0: + # check if needed update + if self.distances[adj] > self.distances[min_index] + val: + self.distances[adj] = self.distances[min_index] + val + self.print_dist(self.distances) From 733df666bfbd9a1009507ba0ce507a9006c95bd4 Mon Sep 17 00:00:00 2001 From: beqakd Date: Fri, 5 Jun 2020 17:20:01 +0400 Subject: [PATCH 160/302] implement of gnome sort algorithm --- algorithms/sorting/gnome_sort.py | 38 ++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 algorithms/sorting/gnome_sort.py diff --git a/algorithms/sorting/gnome_sort.py b/algorithms/sorting/gnome_sort.py new file mode 100644 index 00000000..444b127d --- /dev/null +++ b/algorithms/sorting/gnome_sort.py @@ -0,0 +1,38 @@ +''' +Gnome sort is not best sorting algorithms but sure it takes its pride. +It has time O(n^2) +''' + + +def gnome_sort(arr): + """ + Examples: + >>> gnome_sort([0, 5, 2, 3, 2]) + [0, 2, 2, 3, 5] + + >>> gnome_sort([]) + [] + >>> gnome_sort([-2, -45, -5]) + [-45, -5, -2] + """ + + # first case + size = len(arr) + + if size <= 1: + return arr + ind = 0 + # while loop + while ind < size: + if ind == 0: + ind += 1 + elif arr[ind] >= arr[ind - 1]: + ind += 1 + else: + # swap + temp = arr[ind - 1] + arr[ind - 1] = arr[ind] + arr[ind] = temp + ind -= 1 + + return arr From 018c3e8ac51f70fd59cf3d2f56602c6af02ba7af Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Sun, 7 Jun 2020 13:59:38 +0530 Subject: [PATCH 161/302] Removing auto linting check --- .github/workflows/lint_python.yml | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 .github/workflows/lint_python.yml diff --git a/.github/workflows/lint_python.yml b/.github/workflows/lint_python.yml deleted file mode 100644 index 507beee3..00000000 --- a/.github/workflows/lint_python.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: lint_python -on: - pull_request: - push: - # branches: [master] -jobs: - lint_python: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - uses: actions/setup-python@master - - run: pip install black codespell flake8 isort pytest - - run: black . --diff || true - - run: codespell --quiet-level=2 || true # --ignore-words-list="" --skip="" - - run: flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - - run: isort --recursive . || true - - run: pip install -r requirements.txt || true - - run: pytest . || true From 79a4faec5c9f78b1a97508c20e2b6af7e99a3ae3 Mon Sep 17 00:00:00 2001 From: durid17 Date: Mon, 8 Jun 2020 13:34:14 +0400 Subject: [PATCH 162/302] Longest Increasing Subsequence --- .../longest_increasing_subsequence.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 algorithms/dynamic_programming/longest_increasing_subsequence.py diff --git a/algorithms/dynamic_programming/longest_increasing_subsequence.py b/algorithms/dynamic_programming/longest_increasing_subsequence.py new file mode 100644 index 00000000..8a9fa822 --- /dev/null +++ b/algorithms/dynamic_programming/longest_increasing_subsequence.py @@ -0,0 +1,13 @@ +def LIS(arr): + n = len(arr) + if n == 0: return 0 + res = 1 + dp = [0] * n + dp[0] = 1 + for i in range(1, n): + dp[i] = 1; + for j in range(0 , i): + if arr[i] > arr[j]: + dp[i] = max(dp[i] , dp[j] + 1) + res = max(res , dp[i]) + return res \ No newline at end of file From 99944fbbf2d4a3556907c922678001feb7d7799e Mon Sep 17 00:00:00 2001 From: cheymonty <45781686+cheymonty@users.noreply.github.com> Date: Fri, 12 Jun 2020 22:57:32 -0400 Subject: [PATCH 163/302] Add delete last occurrence --- .../linked_list/delete_last_occurrence.py | 30 +++++++++++++++++++ data_structures/linked_list/index.md | 1 + 2 files changed, 31 insertions(+) create mode 100644 data_structures/linked_list/delete_last_occurrence.py diff --git a/data_structures/linked_list/delete_last_occurrence.py b/data_structures/linked_list/delete_last_occurrence.py new file mode 100644 index 00000000..c4e9d95c --- /dev/null +++ b/data_structures/linked_list/delete_last_occurrence.py @@ -0,0 +1,30 @@ +class Node(): + + def __init__(self, val): + self.val = val + self.next = None + +def delete_last_occurrence(head, val): + if not head: + return None + + curr = head + prev = None + final_prev = None + final_occ = None + + while curr != None: + if curr.val == val: + final_prev = prev + final_occ = curr + + prev = curr + curr = curr.next + + if final_occ: + if final_prev: + final_prev.next = final_occ.next + else: + head = None + + return head \ No newline at end of file diff --git a/data_structures/linked_list/index.md b/data_structures/linked_list/index.md index 7c598aed..47a0074e 100644 --- a/data_structures/linked_list/index.md +++ b/data_structures/linked_list/index.md @@ -9,3 +9,4 @@ * [Odd-Even Arrangement](odd_even_arrangement.py) * [Merge Linked List](merge_linked_list.py) * [Remove Duplicates](remove_duplicates.py) +* [Delete Last Occurrence](delete_last_occurrence.py) From 48ae026fd5bae7bb9fdd00ca9e7c7ea356b737b1 Mon Sep 17 00:00:00 2001 From: cheymonty <45781686+cheymonty@users.noreply.github.com> Date: Fri, 12 Jun 2020 23:01:09 -0400 Subject: [PATCH 164/302] Add delete last occurrence --- data_structures/linked_list/delete_last_occurrence.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data_structures/linked_list/delete_last_occurrence.py b/data_structures/linked_list/delete_last_occurrence.py index c4e9d95c..e76f1d9a 100644 --- a/data_structures/linked_list/delete_last_occurrence.py +++ b/data_structures/linked_list/delete_last_occurrence.py @@ -21,7 +21,9 @@ def delete_last_occurrence(head, val): prev = curr curr = curr.next + if final_occ: + # special case that checks for a 1 node list that equals the val if final_prev: final_prev.next = final_occ.next else: From fc0ed9bf378548b75ecee8b7dd7b257b8bc5c872 Mon Sep 17 00:00:00 2001 From: cheymonty <45781686+cheymonty@users.noreply.github.com> Date: Fri, 12 Jun 2020 23:32:12 -0400 Subject: [PATCH 165/302] Add stack using list --- data_structures/stack/stack_using_list.py | 25 +++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 data_structures/stack/stack_using_list.py diff --git a/data_structures/stack/stack_using_list.py b/data_structures/stack/stack_using_list.py new file mode 100644 index 00000000..172892dd --- /dev/null +++ b/data_structures/stack/stack_using_list.py @@ -0,0 +1,25 @@ +class Stack(): + """ + Stack follows Last-In-First-Out methodology + """ + + def __init__(self): + self.entries = [] + + def size(self): + return len(self.entries) + + def push(self, val): + self.entries.append(val) + + def pop(self): + if self.size() > 0: + self.entries.pop(self.size() - 1) + + + + + + + + \ No newline at end of file From 4deb0855684b82713eae3a7b7b327a0250ed8c17 Mon Sep 17 00:00:00 2001 From: Gega Darakhvelidze Date: Sun, 14 Jun 2020 22:56:09 +0400 Subject: [PATCH 166/302] prefix_function added --- .../dynamic_programming/prefix_function.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 algorithms/dynamic_programming/prefix_function.py diff --git a/algorithms/dynamic_programming/prefix_function.py b/algorithms/dynamic_programming/prefix_function.py new file mode 100644 index 00000000..c2cd4385 --- /dev/null +++ b/algorithms/dynamic_programming/prefix_function.py @@ -0,0 +1,19 @@ + +def prefix_function(s: str) -> [int]: + """ + The prefix function for string s is defined as an array pi of length n, + where pi[i] is the length of the longest proper prefix of the substring + s[0...i] which is also a suffix of this substring. A proper prefix of a + string is a prefix that is not equal to the string itself. + By definition, pi[0] = 0. + """ + n = len(s) + pi = [0] * n + for i in range(1, n): + j = pi[i - 1] + while (j > 0) and (s[i] != s[j]): + j = pi[j - 1] + if s[i] == s[j]: + j += 1 + pi[i] = j + return pi From 359aeee68af2a1262a29a5c3168e20bbc9d8cb69 Mon Sep 17 00:00:00 2001 From: Gega Darakhvelidze Date: Tue, 16 Jun 2020 17:56:26 +0400 Subject: [PATCH 167/302] prefix_sums added --- algorithms/dynamic_programming/prefix_sums.py | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 algorithms/dynamic_programming/prefix_sums.py diff --git a/algorithms/dynamic_programming/prefix_sums.py b/algorithms/dynamic_programming/prefix_sums.py new file mode 100644 index 00000000..2a0b70db --- /dev/null +++ b/algorithms/dynamic_programming/prefix_sums.py @@ -0,0 +1,11 @@ +def prefix_sums(ls: [int]) -> [int]: + """ + Returns list of prefix sums for given list of integers. + """ + n = len(ls) + total = 0 + sums = [0] * n + for i in range(n): + total += ls[i] + sums[i] = total + return sums From a9ba564b9e183e45db7c80fab12ae8fcce517b02 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Sat, 20 Jun 2020 07:33:19 +0530 Subject: [PATCH 168/302] Update bubble_sort.py --- algorithms/sorting/bubble_sort.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/algorithms/sorting/bubble_sort.py b/algorithms/sorting/bubble_sort.py index 7cd5321e..1c4a24cc 100644 --- a/algorithms/sorting/bubble_sort.py +++ b/algorithms/sorting/bubble_sort.py @@ -3,8 +3,20 @@ Best time scenario is when array is already sorted - O(n) """ - def bubble_sort(array): + n = len(array) + for i in range(n): + for j in range(0, n-i-1): + if array[j] > array[j+1]: + array[j], array[j+1] = array[j+1], array[j] + return array + + +def bubble_sort_optimized(array): + """ + Optimizes on bubble sort by taking care of already swapped cases + Reference - https://github.com/prabhupant/python-ds/pull/346 + """ has_swapped = True num_of_iterations = 0 From 1b37ff4b71be5ac7f3f93646e94b2b98e36e0da0 Mon Sep 17 00:00:00 2001 From: enqidu Date: Wed, 8 Jul 2020 14:48:21 +0400 Subject: [PATCH 169/302] markov chain algorithm --- algorithms/miscellaneous/markov.py | 48 ++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100755 algorithms/miscellaneous/markov.py diff --git a/algorithms/miscellaneous/markov.py b/algorithms/miscellaneous/markov.py new file mode 100755 index 00000000..bffe7675 --- /dev/null +++ b/algorithms/miscellaneous/markov.py @@ -0,0 +1,48 @@ +import codecs +import random + +MAX_LETTERS = 2000 + +def readFile(f, mp, k): + seed = '' + mostFreqSeed = seed + mostFreq = 1 + for line in f: + for ch in line: + seed, mostFreq, mostFreqSeed = processSeed(seed, mostFreqSeed, mostFreq, ch, k, mp) + return mostFreqSeed + +def processSeed(seed, mostFreqSeed, mostFreq, ch, k, mp): + seed += ch + if len(seed) == k+1: + oldSeed = seed[:-1] + mp.setdefault(oldSeed, []).append(ch) + if mostFreq < len(mp[oldSeed]): + mostFreq, mostFreqSeed = len(mp[oldSeed]), oldSeed + seed = seed[1:] + return seed, mostFreq, mostFreqSeed + +def generateText(mp, mostFreqSeed): + text, curSeed = mostFreqSeed, mostFreqSeed + while (len(text) < MAX_LETTERS): + ch = random.choice(mp[curSeed]) + text, curSeed = text+ch, curSeed+ch + curSeed = curSeed[1:] + return text + +def main(): + fileName = input("Enter the file name: ") + ".txt" + f = codecs.open(fileName, encoding='utf-8') + k = int(input("Enter the Markov order [1-10]: ")) + assert (k >= 1 and k <= 10) + mp = {} + mostFreqSeed = readFile(f, mp, k) + f.close() + text = generateText(mp, mostFreqSeed) + print(text) + result = codecs.open("result.txt", "w", encoding='utf-8') + result.write(text) + result.close() + +if __name__ == "__main__": + main() \ No newline at end of file From 16129e82716858e8ccf51abe49b1152546039b39 Mon Sep 17 00:00:00 2001 From: vakhokoto Date: Thu, 9 Jul 2020 00:54:37 +0400 Subject: [PATCH 170/302] hamilton dynamic solution for vertices <= 20 added --- .../dynamic_programming/hamilton_cycle.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 algorithms/dynamic_programming/hamilton_cycle.py diff --git a/algorithms/dynamic_programming/hamilton_cycle.py b/algorithms/dynamic_programming/hamilton_cycle.py new file mode 100644 index 00000000..21e2b4ac --- /dev/null +++ b/algorithms/dynamic_programming/hamilton_cycle.py @@ -0,0 +1,27 @@ +import functools + +def hamilton_cycle(graph, n): + height = 1 << n + + dp = [[False for _ in range(n)] for _ in range(height)] + for i in range(n): + dp[1 << i][i] = True + + for i in range(height): + ones, zeros = [], [] + for pos in range(n): + if (1 << pos) & i: + ones.append(pos) + else: + zeros.append(pos) + + for o in ones: + if not dp[i][o]: + continue + + for z in zeros: + if graph[o][z]: + new_val = i + (1 << z) + dp[new_val][z] = True + + return functools.reduce(lambda a, b: a or b, dp[height - 1]) \ No newline at end of file From 2f674efb40f0b9024e4d07f1bc8d877b83f8a768 Mon Sep 17 00:00:00 2001 From: franklindyer Date: Wed, 8 Jul 2020 21:54:22 +0000 Subject: [PATCH 171/302] Added a faster recursive fibonacci algorithm --- algorithms/math/recursive_fibonacci.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/algorithms/math/recursive_fibonacci.py b/algorithms/math/recursive_fibonacci.py index 4094e6b9..c4447a52 100644 --- a/algorithms/math/recursive_fibonacci.py +++ b/algorithms/math/recursive_fibonacci.py @@ -1,7 +1,11 @@ """ - Recursivly compute the Fibonacci sequence + Recursivly compute the Fibonacci sequence using two different methods + main() compares the amount of time taken by each algorithm + rec_fib(n) requires O(Fibo(n)) operations, whereas binary_rec_fib(n) requires less than O(n) """ +import time + def rec_fib(n): if n == 1: return 1 @@ -10,10 +14,19 @@ def rec_fib(n): else: return rec_fib(n-1)+rec_fib(n-2) +def binary_rec_fib(n): + if n == 2 or n == 1: + return 1 + elif n == 0: + return 0 + else: + sgn = n % 2 + return binary_rec_fib((n-sgn)/2+1)**2 - ((-1)**sgn)*binary_rec_fib((n+sgn)/2-1)**2 + def main(): + times = [] n : int = int(input("n := ")) - for i in range(0, n): - print(rec_fib(i)) + print(binary_rec_fib(i)) if __name__ == "__main__": main() From 614d0b0dd57adc0c30f27e68ccb8e121e4efdb08 Mon Sep 17 00:00:00 2001 From: franklindyer Date: Wed, 8 Jul 2020 22:06:12 +0000 Subject: [PATCH 172/302] Fixed a silly typo --- algorithms/math/recursive_fibonacci.py | 1 + 1 file changed, 1 insertion(+) diff --git a/algorithms/math/recursive_fibonacci.py b/algorithms/math/recursive_fibonacci.py index c4447a52..c7741977 100644 --- a/algorithms/math/recursive_fibonacci.py +++ b/algorithms/math/recursive_fibonacci.py @@ -26,6 +26,7 @@ def binary_rec_fib(n): def main(): times = [] n : int = int(input("n := ")) + for i in range(0,n): print(binary_rec_fib(i)) if __name__ == "__main__": From b11cac749aa856bb3c98d552193cd3503961f398 Mon Sep 17 00:00:00 2001 From: franklindyer Date: Wed, 8 Jul 2020 22:20:33 +0000 Subject: [PATCH 173/302] Beautified code to adhere to PEP8 standards, and added clarifying comment --- algorithms/math/recursive_fibonacci.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/algorithms/math/recursive_fibonacci.py b/algorithms/math/recursive_fibonacci.py index c7741977..eb319cd9 100644 --- a/algorithms/math/recursive_fibonacci.py +++ b/algorithms/math/recursive_fibonacci.py @@ -1,11 +1,8 @@ """ Recursivly compute the Fibonacci sequence using two different methods - main() compares the amount of time taken by each algorithm rec_fib(n) requires O(Fibo(n)) operations, whereas binary_rec_fib(n) requires less than O(n) """ -import time - def rec_fib(n): if n == 1: return 1 @@ -20,13 +17,16 @@ def binary_rec_fib(n): elif n == 0: return 0 else: + # This recursive step takes advantage of the following two properties of the fibonacci numbers: + # Fibo(2n) = Fibo(n+1)^2 + Fibo(n)^2 + # Fibo(2n+1) = Fibo(n+1)^2 - Fibo(n-1)^2 sgn = n % 2 - return binary_rec_fib((n-sgn)/2+1)**2 - ((-1)**sgn)*binary_rec_fib((n+sgn)/2-1)**2 + return binary_rec_fib((n-sgn)/2 + 1)**2 - ((-1)**sgn) * binary_rec_fib((n+sgn)/2 - 1)**2 def main(): times = [] n : int = int(input("n := ")) - for i in range(0,n): + for i in range(0, n): print(binary_rec_fib(i)) if __name__ == "__main__": From dc27092ed40a74be0e9ba30bae4db5f5c2bc73b1 Mon Sep 17 00:00:00 2001 From: Aman Gupta Date: Sun, 12 Jul 2020 15:26:52 +0530 Subject: [PATCH 174/302] Recursive & Iterative Functions added --- algorithms/math/factorial_iterative.py | 18 ++++++++++++++++++ algorithms/math/factorial_recursive.py | 16 ++++++++++++++++ algorithms/math/index.md | 2 ++ 3 files changed, 36 insertions(+) create mode 100644 algorithms/math/factorial_iterative.py create mode 100644 algorithms/math/factorial_recursive.py diff --git a/algorithms/math/factorial_iterative.py b/algorithms/math/factorial_iterative.py new file mode 100644 index 00000000..d722ec92 --- /dev/null +++ b/algorithms/math/factorial_iterative.py @@ -0,0 +1,18 @@ +#Calculate factorial of a given number using iterative method. + +def factorial(number): + + answer = 1 + + if number == 0: + return 1 + else: + for num in range(1, number+1): + answer = answer * num + return answer + +if __name__ == '__main__': + + enter_number = int(input("Enter a number whose factorial is required : ")) + result = factorial(enter_number) + print(result) \ No newline at end of file diff --git a/algorithms/math/factorial_recursive.py b/algorithms/math/factorial_recursive.py new file mode 100644 index 00000000..ed5f3b38 --- /dev/null +++ b/algorithms/math/factorial_recursive.py @@ -0,0 +1,16 @@ +#Calculate factorial of a given number using recursive method. + +def factorial(number): + + if number == 0 or number == 1: + return 1 + + answer = number * factorial(number - 1) + + return answer + +if __name__ == '__main__': + + enter_number = int(input("Enter a number whose factorial is required : ")) + result = factorial(enter_number) + print(result) \ No newline at end of file diff --git a/algorithms/math/index.md b/algorithms/math/index.md index fc7b2649..76b9dc6a 100644 --- a/algorithms/math/index.md +++ b/algorithms/math/index.md @@ -6,3 +6,5 @@ * [Sieve of Erastothenes](sieve_of_eratosthenes.py) * [Perfect Square](perfect_square.py) * [Number Convertion](number_convertion.py) +* [Iterative Factorial] (factorial_iterative.py) +* [Recursive Factorial] (factorial_recursive.py) From 7ce97e41d8bdde6f4b42a5d882a98fec5a3cf11a Mon Sep 17 00:00:00 2001 From: Aman Gupta Date: Sun, 12 Jul 2020 15:29:39 +0530 Subject: [PATCH 175/302] index.md file updated --- algorithms/math/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/algorithms/math/index.md b/algorithms/math/index.md index 76b9dc6a..d6248d88 100644 --- a/algorithms/math/index.md +++ b/algorithms/math/index.md @@ -6,5 +6,5 @@ * [Sieve of Erastothenes](sieve_of_eratosthenes.py) * [Perfect Square](perfect_square.py) * [Number Convertion](number_convertion.py) -* [Iterative Factorial] (factorial_iterative.py) -* [Recursive Factorial] (factorial_recursive.py) +* [Iterative Factorial](factorial_iterative.py) +* [Recursive Factorial](factorial_recursive.py) From 3d2716642750e9372484c0b87962e879de92afb4 Mon Sep 17 00:00:00 2001 From: Neagu Briana Date: Sun, 26 Jul 2020 00:33:26 +0300 Subject: [PATCH 176/302] Add Palindromic-Tree in data structures --- .../palindromic_tree/palindromic_tree.py | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 data_structures/palindromic_tree/palindromic_tree.py diff --git a/data_structures/palindromic_tree/palindromic_tree.py b/data_structures/palindromic_tree/palindromic_tree.py new file mode 100644 index 00000000..47992793 --- /dev/null +++ b/data_structures/palindromic_tree/palindromic_tree.py @@ -0,0 +1,68 @@ +import typing + + +class Node: + def __init__(self): + self.next: typing.Dict[str, Node] = {} + self.frequency = 0 + self.length = 0 + self.suffix = None + + +class PalindromicTree: + def __init__(self): + self.null_root = Node() + self.imaginary_root = Node() + + self.null_root.length = 0 + self.null_root.suffix = self.imaginary_root + self.imaginary_root.length = -1 + self.imaginary_root.suffix = self.imaginary_root + + self.counter = 0 + self.all_palindromes: list[Node] = [] + self.previous = self.imaginary_root + + def add_letter(self, string, index): + while index - 1 - self.previous.length < 0 or string[index - 1 - self.previous.length] != string[index]: + self.previous = self.previous.suffix + + if self.previous.next.get(string[index]) is not None: + node = self.previous.next.get(string[index]) + node.frequency += 1 + self.previous = node + return + + new_node = Node() + + self.counter += 1 + new_node.frequency = 1 + new_node.length = self.previous.length + 2 + self.previous.next[string[index]] = new_node + + if new_node.length == 1: + new_node.suffix = self.null_root + self.previous = new_node + else: + self.previous = self.previous.suffix + while index - 1 - self.previous.length < 0 or string[index - 1 - self.previous.length] != string[index]: + self.previous = self.previous.suffix + new_node.suffix = self.previous.next[string[index]] + self.previous = new_node + self.all_palindromes.append(new_node) + + def how_many_palindromes(self): + all_nr = 0 + for node in reversed(self.all_palindromes): + node.suffix.frequency += node.frequency + all_nr += node.frequency + print(f"There are {self.counter} unique palindromes and {all_nr} in total") + + +tree = PalindromicTree() + +s = "abaxxaba" +for i in range(len(s)): + tree.add_letter(s, i) +tree.how_many_palindromes() + From 6637d0ad91df599fdf2a3c9ae35db66143ebf004 Mon Sep 17 00:00:00 2001 From: adarsh ghimire Date: Tue, 11 Aug 2020 10:29:50 +0545 Subject: [PATCH 177/302] Spelling fix in index_updater.py --- index_updater.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index_updater.py b/index_updater.py index 7f4778ae..6f4e1bb3 100755 --- a/index_updater.py +++ b/index_updater.py @@ -10,7 +10,7 @@ else: mypath = sys.argv[1] -# Going trought folders and subfolders. +# Going through folders and subfolders. for root, dirs, files in os.walk(mypath): curr_files = list() curr_folder = os.path.basename(root) From 071e068c9cf688e341726df95b6b5a3553e4673e Mon Sep 17 00:00:00 2001 From: adarsh ghimire Date: Tue, 11 Aug 2020 10:55:10 +0545 Subject: [PATCH 178/302] GCD optimized with iterative process --- algorithms/math/greatest_common_divisor.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/algorithms/math/greatest_common_divisor.py b/algorithms/math/greatest_common_divisor.py index d00efe53..53e70f1d 100644 --- a/algorithms/math/greatest_common_divisor.py +++ b/algorithms/math/greatest_common_divisor.py @@ -26,4 +26,10 @@ def gcd(x, y): if y == 0: return x - return gcd(y, x % y) \ No newline at end of file + return gcd(y, x % y) + +# Iterative optimized +def gcd(x, y): + while y != 0: + x, y = y, x % y + return x From 97c1a15ed7bdd226ed84bc22f42a74fb8d0cfa0f Mon Sep 17 00:00:00 2001 From: Subhasmita <2019003860.subhasmita@ug.sharda.ac.in> Date: Wed, 12 Aug 2020 20:18:28 +0530 Subject: [PATCH 179/302] fixed spelling and grammatical errors --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7b205f4e..13793e33 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # Python Data Structures and Algorithms -This repository contains data structures and algorithms concepts and questions useful for interviews in Python. +This repository contains questions requiring implementation of data structures and algorithms concepts. It is useful for interviews in Python. ## :dart: Objective @@ -56,12 +56,12 @@ As you can see, the repo is still in its infancy. Here are some key things in th 1. Queue questions 2. Algorithms -3. More questions in data structures, especially for graph, circular linked list, tries, heaps and hash. +3. More questions in data structures, especially for graph, circular linked list, trees, heaps and hash. ## :raised_hand: Contributing Contributions are always welcomed. :smiley: -Feel free to raise new issues, file new PRs and star and fork this repo! :wink: +Feel free to raise new issues, file new PRs. Consider giving it a star and fork this repo! :wink: To follow the guidelines, refer to [Contributing.md](CONTRIBUTING.md) From cbe04c3b56ebcac1be2354557c5dcc60506eb377 Mon Sep 17 00:00:00 2001 From: bgz30 <44124521+BGZ30@users.noreply.github.com> Date: Fri, 21 Aug 2020 18:37:49 +0200 Subject: [PATCH 180/302] Check power of two --- algorithms/math/power_of_two.py | 34 +++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 algorithms/math/power_of_two.py diff --git a/algorithms/math/power_of_two.py b/algorithms/math/power_of_two.py new file mode 100644 index 00000000..f21aac10 --- /dev/null +++ b/algorithms/math/power_of_two.py @@ -0,0 +1,34 @@ +""" + This simple code is to check if a given number is a poer of two or not. + Method: + if a number is a power of two, then its binary representation is (2^k). + ex: 4 --> 2^2 --> 100 --> k = 2 + 8 --> 2^3 --> 1000 --> k = 3 + 16--> 2^4 --> 10000 --> k = 4 + + assume that n is a power of two, then (n-1)&(n) will be zero; + ex: + n = 8 --> (1000) , n-1 = 7 ---> (0111) + performing bit (and) operation between both, then n&(n-1) = 0000 + + n = 12 --> (1110) , n-1 = 11 ---> (1011) + performing bit (and) operation between both, then n&(n-1) = 1010 + + Conclusion: + The result of the above bit "and" operation will be zero, ONLY if the given number is a pwoer of two. + + NOTE: + - Since Python considers 0 as "false", then we are gonna return the inversion of the result; i.e. return not(n&(n-1). + - BUT If n = 0, the result will be zero indicating that 0 is a power of 2, wich is not true. + So to fix that, we are going to perform an extra logical "and" operation with the oreginal number. +""" + + +def pow_of_two(n): + return(n and (not(n&(n-1)))) + +for i in range(20): + if pow_of_two(i): + print(f"{i} is a power of 2.") + else: + print(f"{i} is NOT a power of 2.") \ No newline at end of file From 545a78070b936f7f85156c5ac07f8070fe730c83 Mon Sep 17 00:00:00 2001 From: Bassant Gamal <44124521+BGZ30@users.noreply.github.com> Date: Fri, 21 Aug 2020 18:50:53 +0200 Subject: [PATCH 181/302] Update power_of_two.py fixed the binary number in the second example. --- algorithms/math/power_of_two.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/algorithms/math/power_of_two.py b/algorithms/math/power_of_two.py index f21aac10..6fcfdb22 100644 --- a/algorithms/math/power_of_two.py +++ b/algorithms/math/power_of_two.py @@ -11,8 +11,8 @@ n = 8 --> (1000) , n-1 = 7 ---> (0111) performing bit (and) operation between both, then n&(n-1) = 0000 - n = 12 --> (1110) , n-1 = 11 ---> (1011) - performing bit (and) operation between both, then n&(n-1) = 1010 + n = 12 --> (1100) , n-1 = 11 ---> (1011) + performing bit (and) operation between both, then n&(n-1) = 1000 Conclusion: The result of the above bit "and" operation will be zero, ONLY if the given number is a pwoer of two. @@ -31,4 +31,4 @@ def pow_of_two(n): if pow_of_two(i): print(f"{i} is a power of 2.") else: - print(f"{i} is NOT a power of 2.") \ No newline at end of file + print(f"{i} is NOT a power of 2.") From 6508237d2a8246a38be45803204d06aa7eb51b09 Mon Sep 17 00:00:00 2001 From: matttatum97 <69768161+matttatum97@users.noreply.github.com> Date: Tue, 25 Aug 2020 12:09:51 -0400 Subject: [PATCH 182/302] Create sum_of_two_integers.py --- .../bit_manipulation/sum_of_two_integers.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 algorithms/bit_manipulation/sum_of_two_integers.py diff --git a/algorithms/bit_manipulation/sum_of_two_integers.py b/algorithms/bit_manipulation/sum_of_two_integers.py new file mode 100644 index 00000000..c8203c5a --- /dev/null +++ b/algorithms/bit_manipulation/sum_of_two_integers.py @@ -0,0 +1,22 @@ +# Question: Calculate the sum of two integers a and b but without the +# use of the operators + and -. + +#Solution +def getSum(a, b): + """ + :type a: int + :type b: int + :rtype: int + """ + + mask = 0xffffffff + diff = 0 + carry = 0 + while b & mask: + diff = a ^ b + carry = trunc(a & b) + carry = carry << 1 + a = diff + b = carry + if b > 0: return (a & mask) + else: return a \ No newline at end of file From 0652520f468039873fd1a33bfc55e146a4afd9ff Mon Sep 17 00:00:00 2001 From: Yukti Khosla <44090430+Yukti-09@users.noreply.github.com> Date: Sun, 30 Aug 2020 11:00:32 +0530 Subject: [PATCH 183/302] Create transpose_matrix.py --- data_structures/array/transpose_matrix.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 data_structures/array/transpose_matrix.py diff --git a/data_structures/array/transpose_matrix.py b/data_structures/array/transpose_matrix.py new file mode 100644 index 00000000..c7abb7f4 --- /dev/null +++ b/data_structures/array/transpose_matrix.py @@ -0,0 +1,14 @@ +class Solution: + def transpose(self, A: List[List[int]]) -> List[List[int]]: + l=[] + i=0 + while(i!=len(A[0])): + x=[] + j=0 + while(j Date: Wed, 16 Sep 2020 18:15:51 +0530 Subject: [PATCH 184/302] Update misc.md --- bookmarks/misc.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bookmarks/misc.md b/bookmarks/misc.md index 4bb89d2f..341a8684 100644 --- a/bookmarks/misc.md +++ b/bookmarks/misc.md @@ -15,3 +15,5 @@ This is a list of misc links that may be useful when learning or researching dat - https://machinelearningmastery.com - https://stackoverflow.com/questions/10631326/difference-between-select-into-and-insert-into-from-old-table + +- https://stackoverflow.com/a/33419662/6111200 From 98422fb8c13c29d525b34d0becfa5cde687045a7 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 16 Sep 2020 18:16:21 +0530 Subject: [PATCH 185/302] Update misc.md --- bookmarks/misc.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookmarks/misc.md b/bookmarks/misc.md index 341a8684..dbb88192 100644 --- a/bookmarks/misc.md +++ b/bookmarks/misc.md @@ -16,4 +16,4 @@ This is a list of misc links that may be useful when learning or researching dat - https://stackoverflow.com/questions/10631326/difference-between-select-into-and-insert-into-from-old-table -- https://stackoverflow.com/a/33419662/6111200 +- Why SSL are not issued for IP address - https://stackoverflow.com/a/33419662/6111200 From 8b4a0685df475c087c2ca440065b19c2d439a103 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 27 Oct 2020 14:25:01 +0530 Subject: [PATCH 186/302] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 13793e33..c076e8a4 100644 --- a/README.md +++ b/README.md @@ -67,4 +67,4 @@ To follow the guidelines, refer to [Contributing.md](CONTRIBUTING.md) ## :page_facing_up: License -[MIT @ Prabhu Pant](LICENSE) +[MIT](LICENSE) From fbe77052450c65a4031893e82fefac572b888131 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 27 Oct 2020 14:27:25 +0530 Subject: [PATCH 187/302] Update square_of_sorted_array.py --- data_structures/array/square_of_sorted_array.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/data_structures/array/square_of_sorted_array.py b/data_structures/array/square_of_sorted_array.py index 88ef6c87..1bebb758 100644 --- a/data_structures/array/square_of_sorted_array.py +++ b/data_structures/array/square_of_sorted_array.py @@ -26,8 +26,3 @@ def square(arr): j += 1 return ans - - - - - From cda8d2016aaf93d72518333dd58fd8edb3cfac85 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 27 Oct 2020 14:31:29 +0530 Subject: [PATCH 188/302] Added question and answer --- data_structures/array/max_product_three_elements.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/data_structures/array/max_product_three_elements.py b/data_structures/array/max_product_three_elements.py index 0d31fd53..5883172e 100644 --- a/data_structures/array/max_product_three_elements.py +++ b/data_structures/array/max_product_three_elements.py @@ -1,3 +1,6 @@ +# Q - Find the max product of three elements of an array +# A - Find the max 3 numbers and 2 min numbers. Then find the max of (min1*min2*max1, max1*max2*max3) + import sys def product(arr): From 652caac783fac0a933a49c728e0dd10a930b6b5f Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 27 Oct 2020 14:33:16 +0530 Subject: [PATCH 189/302] Fix the name of the file Change the extension of the file from pyt (not a Python file) to py --- ...eck_divide_in_two_halves.pyt => check_divide_in_two_halves.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename data_structures/binary_trees/{check_divide_in_two_halves.pyt => check_divide_in_two_halves.py} (100%) diff --git a/data_structures/binary_trees/check_divide_in_two_halves.pyt b/data_structures/binary_trees/check_divide_in_two_halves.py similarity index 100% rename from data_structures/binary_trees/check_divide_in_two_halves.pyt rename to data_structures/binary_trees/check_divide_in_two_halves.py From c91dda1874083b414e0c718fdd12aad411146a34 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 4 Jan 2021 12:14:41 +0530 Subject: [PATCH 190/302] Update misc.md --- bookmarks/misc.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bookmarks/misc.md b/bookmarks/misc.md index dbb88192..2afa94e6 100644 --- a/bookmarks/misc.md +++ b/bookmarks/misc.md @@ -17,3 +17,5 @@ This is a list of misc links that may be useful when learning or researching dat - https://stackoverflow.com/questions/10631326/difference-between-select-into-and-insert-into-from-old-table - Why SSL are not issued for IP address - https://stackoverflow.com/a/33419662/6111200 + +- PATCH vs PUT https://stackoverflow.com/questions/28459418/use-of-put-vs-patch-methods-in-rest-api-real-life-scenarios/39338329#39338329 From 6e8b81eb52a6340e5375798d0a55f796fde94bfc Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 13 Jan 2021 09:30:34 +0530 Subject: [PATCH 191/302] Update articles.md --- bookmarks/articles.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bookmarks/articles.md b/bookmarks/articles.md index a2b8e1ca..81c00863 100644 --- a/bookmarks/articles.md +++ b/bookmarks/articles.md @@ -55,3 +55,5 @@ This is a list of articles that may be useful for algorithms and data structures - https://www.ultravioletsoftware.com/single-post/2017/03/23/An-introduction-into-the-WSGI-ecosystem - https://jwt.io/introduction/ + +- https://khashtamov.com/en/how-to-become-a-data-engineer/ From 27ce2622793f4951ae166414a2a2cfbf011ddece Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 20 Jan 2021 19:22:47 +0530 Subject: [PATCH 192/302] Delete videos.md --- bookmarks/videos.md | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 bookmarks/videos.md diff --git a/bookmarks/videos.md b/bookmarks/videos.md deleted file mode 100644 index 0ac8813e..00000000 --- a/bookmarks/videos.md +++ /dev/null @@ -1,9 +0,0 @@ -# Videos - -This is a list of video links that may be useful for algorithms and data structures learning. - -## Links: - -- https://www.youtube.com/watch?v=mSzUb7f47qk - -- https://www.youtube.com/user/mycodeschool \ No newline at end of file From 79206a4bca47c265e23d4e4baee24e7c5fe63c3c Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 22 Feb 2021 18:53:39 +0530 Subject: [PATCH 193/302] Remove index updater --- index_updater.py | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100755 index_updater.py diff --git a/index_updater.py b/index_updater.py deleted file mode 100755 index 6f4e1bb3..00000000 --- a/index_updater.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python3 - -import sys -import os - -# Terminal parameters. -if len(sys.argv[1:]) == 0: - print('Please, give a path') - sys.exit(1) -else: - mypath = sys.argv[1] - -# Going through folders and subfolders. -for root, dirs, files in os.walk(mypath): - curr_files = list() - curr_folder = os.path.basename(root) - - for name in files: - if name.endswith('.py') and not name == '__init__.py' and not dirs: - curr_files.append(name) - - # If we have files, write "index.md" - if curr_files: - with open(os.path.join(root, 'index.md'), mode='w') as md_file: - md_file.write('# Index of {}\n\n'.format(curr_folder)) - for line in curr_files: - file_name = line.split('.')[0].replace('_',' ').title() - md_file.write('* [' + file_name + '](' +line + ')\n') From 4130ae411b963bbbf3655645927d845012864dcf Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 22 Feb 2021 18:55:14 +0530 Subject: [PATCH 194/302] Remove logo and emoticons --- README.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index c076e8a4..cdbc6a72 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,12 @@ -![logo](logo/logo.png) - # Python Data Structures and Algorithms This repository contains questions requiring implementation of data structures and algorithms concepts. It is useful for interviews in Python. -## :dart: Objective +## Objective The open source community has helped me a lot during my interview preparations and studies while I was in my undergrad. I always wanted to give something back to the community. In my endeavour to contribute something back, I will be uploading data structures and algorithms questions in Python in this repo. Feel free to contribute and get in touch! :smiley: -## :file_folder: Structure of the repository +## Structure of the repository As of now, the repository contains 3 main directories: [**Bookmarks**](bookmarks), [**Data Structures**](data_structures) and [**Algorithms**](algorithms). @@ -50,7 +48,7 @@ You can find useful links in this repository in the different markdown files. Be | Videos | [Click Here](bookmarks/videos.md) | | Misc. | [Click Here](bookmarks/misc.md) | -## :clipboard: Things need to be done +## Things need to be done As you can see, the repo is still in its infancy. Here are some key things in the to-do. @@ -58,13 +56,13 @@ As you can see, the repo is still in its infancy. Here are some key things in th 2. Algorithms 3. More questions in data structures, especially for graph, circular linked list, trees, heaps and hash. -## :raised_hand: Contributing +## Contributing Contributions are always welcomed. :smiley: Feel free to raise new issues, file new PRs. Consider giving it a star and fork this repo! :wink: To follow the guidelines, refer to [Contributing.md](CONTRIBUTING.md) -## :page_facing_up: License +## License [MIT](LICENSE) From a3c864c4807b709c64e5688055a762d99e3288b3 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 22 Feb 2021 19:01:08 +0530 Subject: [PATCH 195/302] Remove emoticons from contributing.md --- CONTRIBUTING.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index be0d596c..7fb881f7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ This is a project that is for the community and its true essence is only possible when it is community driven. -Please feel free to contribute to this project and be a part of this. Anything from raising issues to adding new features or even a typo in documentations, all are welcome. Please report issues here [https://github.com/prabhupant/python-ds/issues](https://github.com/prabhupant/python-ds/issues). It is also recommended to go through the Contributions Best Practices below to help organize contributions :smiley: +Please feel free to contribute to this project and be a part of this. Anything from raising issues to adding new features or even a typo in documentations, all are welcome. Please report issues here [https://github.com/prabhupant/python-ds/issues](https://github.com/prabhupant/python-ds/issues). It is also recommended to go through the Contributions Best Practices below to help organize contributions ## Contributions Best Practices @@ -18,7 +18,7 @@ Please feel free to contribute to this project and be a part of this. Anything f ### Issues -Feel free to open up any issue in the repository, whether it is about code improvements or bug fixes or documentation. You can also use any label you want to associate with the issue. Please provide a clear description of the issue while filing it :smiley: +Feel free to open up any issue in the repository, whether it is about code improvements or bug fixes or documentation. You can also use any label you want to associate with the issue. Please provide a clear description of the issue while filing it. ### Code Styling Guide @@ -26,9 +26,9 @@ Python follows a Pep8 styling. Styling the code according to it makes it univers ### Questions -While there are infinite number of data structure and algorithm questions, it is impossible to collect all of them here. So please add only those questions that are either unique or tricky or have some mind blowing approach to solve them. Also, try not to file a PR for a question which is already present in the repo. Interesting questions and implementations are always welcomed :wink: +While there are infinite number of data structure and algorithm questions, it is impossible to collect all of them here. So please add only those questions that are either unique or tricky or have some mind blowing approach to solve them. Also, try not to file a PR for a question which is already present in the repo. Interesting questions and implementations are always welcomed. -For filing a PR for a new question, please open a issue first for the same and then reference it in the PR. For example, let's say you want to add a new question called "find max element in array". So first head over to the issues tab and create a new issue called "New question: find max element in array". Then if you want to work on it, please mention it in the description. After you are done writing the code and ready to file a PR, refer to the issue number in the PR description. Let's say the issue number was #23. So in the PR description, it should be "Fixes #23". That's it! :smiley: +For filing a PR for a new question, please open a issue first for the same and then reference it in the PR. For example, let's say you want to add a new question called "find max element in array". So first head over to the issues tab and create a new issue called "New question: find max element in array". Then if you want to work on it, please mention it in the description. After you are done writing the code and ready to file a PR, refer to the issue number in the PR description. Let's say the issue number was #23. So in the PR description, it should be "Fixes #23". That's it! ### Bookmarks @@ -36,13 +36,13 @@ The Bookmarks directory is for storing awesome links to articles, videos, slides * Don't add a link to a MOOC or course (like DS Algo MIT lectures) -* Ask yourself "Is the link interesting enough that someone will really love it?" or "Is it something that an interviewer might ask in the interview to test you?" or "Is it some common or amazing thing people don't have enough knowledge about?". If yes to any of them, then sure, quickly file the PR :wink: +* Ask yourself "Is the link interesting enough that someone will really love it?" or "Is it something that an interviewer might ask in the interview to test you?" or "Is it some common or amazing thing people don't have enough knowledge about?". If yes to any of them, then sure, quickly file the PR. * If an article has more than one part, be sure to refer to the first only in the PR. ## How To Contribute? -You can add anything to the repo as long as it is related to programming and increasing knowledge :smiley: +You can add anything to the repo as long as it is related to programming and increasing knowledge. 0. Firstly, fork the repo to your GitHub account. Just to get familiar with some terms, this will be the `origin`. To state `origin` and `upstream` explicitly, @@ -80,13 +80,13 @@ $ git push origin max-number-in-array 6. Write a good brief description and refer to the issue (if any) and submit the PR. -7. Now wait for the approval :smiley: +7. Now wait for the approval. ## Join The Development Before you join the development, please fork and clone the repository to your local machine and explore it. Don't worry nothing will happen, atmost some code might not work :wink: -Feel free to contribute and be a part of this endeavour :beers: +Feel free to contribute and be a part of this endeavour. From 0894eea3d945b400c2b454a779a3698347dd5b3d Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 23 Feb 2021 11:50:04 +0530 Subject: [PATCH 196/302] remove logo --- logo/logo.png | Bin 9910 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 logo/logo.png diff --git a/logo/logo.png b/logo/logo.png deleted file mode 100644 index 28749cb76889825a2f93f55013728fad2adaabec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9910 zcma)i1yEeg*6m=y-67cEt|7P%!C`QBcZb2v_> zdVkfMsxxz1YV|&QpXpw`dPjqmq|s4GPyhe`x~vRH6##%?f!>3W-a)?$k7azJKQL~p z(h`8GiT6j)0aE4&ToV=e1wVKfCh1sO(r0|)Q30QN%at>c~7xo*Nt5*1@ zcrAM0Tf^yNaI{sN`Ovl__19u4Q2wEk=($J`AnP85bI2V{jGnr0$I%Q98{z=#8xjI* z!{<`sMhS)arfz9>P!>$Wg4|&E7s>8g(KrIIvjB-^h${)|b7G{M+uPeotX0M>&CO^e z`aP~LF2p>|A{B;`=^ig@X2M1MvUbAArd19VEmx<(jUxklGK2UP?->ns-;BWR!6ms2 z936nXWZ2Sb_)V15*iou}XluUnPry(csy7?kOFXkSTZh#;(@q#8>q9uU6P3N7QTj04 z(R3b;1$eb)U=DlrQ{=A)dzR{=v)J60gDJ`Kpig0q1@386O=DG^Sy&fvGM% z!2vdGk)lvQ^H2at<$=r$Z680{#*YB#2JnqwK!d9<=>H%sNkjg?1V+FjrcEdfdu5?q z;fcef8f4yy|6s&d^qg~0dw;8y;b>$p{#&+DezG}aZ-$y)-$QGw#-xE;Dk6(rE?0UR z1P~De*=6=F9Y#rD(;>$vOyxx=Vo@54afs*9i#dN8vgIc8bC5*B3G0ve1O#Hq2xW`p>%s;}(D_^GQ39|vDEkSM zxsdX8tbeEDs$0a+ev*5`u&m&|!5HI#SYW(Du6TRsSyls#Pphlf z7h>;@Yqpa~Po#aRZx2AFvw$xMoOoiSAYRz3nEY(glDh0zd~)dXZ6h()+6XQTfm9rEGF#-Z!R%p)r3UKDum z?nRb}Cb=tKc^O)?N2~XflMQUxrb|i4&!agHR%>O+Q+Q}P-_)hnAk~ADRPFkd!WJH3GAxVvU(P?Sxj67F-r40b8fxAlFEyuc3SnQG zx5kT+cI$%fziz&()t)fcTTW1u>6f0C<36B<70>VlMjkx6pyK* zDV{*54bS#&ioOR$eQp9UI}o$^6vr&LIKfsfSjc`_T!6>>w*o`;bw+1cCvBSh5-p6Z&&Z7y|hR^SakYy(fe4b-DN?@gIieJY|Y6VKc}f4ZK9+R zap%jR?F3tQK5=uZGPi?cggA22g>u{mGKZvEY&-*-e_b5lPwKdyr!7`!*N85@BF2d6 zoTAq};70ArVpeMe!HQKC5~9Ldcq}5?$(;!|H_rLXR~)ip;qBjkS0LDYB1t^QOPimM z0PcGkb)Cj^lzQ#)(9&=aM7>D#ZGMGK&&pH@irR&1Zi3jnBt-0?2ClAk$dQ&e{Oon9 zm3K5d&Z50jGO9D}dDMS8x0f6ZR}$5Od0krN<(63Tv>O`i#{YB~EdRDky0D725>cPm zs+Ic`R6F(9RIF8TMV~t$IBH^^v$Q#HXv;*>bDj$ zLNQHxT{O@Lla60t$B#&qoSm(_8txtdPd$@?lf~mZ`TZeIY>=xWy(k=TkmYLja=7Sd z&`iCUW^6Nwu)SG9cUj!Os5mO0^X|g^SQt9l=AtHTg!cEjYW0cVBGO z(N=qGN?rv5au6?`|6H{W!QY2Us_ke5pECng-;jnYXuT*b7$yl3gt8kIqx#pj#O!U@ z$I~7OP$Wj~*&oV@E{61hDZf;3<@^~0ejGFDrx)bN9AhFqUg>!FD z_uU=9YXnQd76Ko03ssUR%9o|TlIog8$oJeSR(gOlma>vHQ!u%_le|(+$9G4~ofw=0 z%vpe{`)rvB4hE}N>nAQ2^*!`a`K;fpb}$vJx_-VXiRVuklqq~fiLi13e;_$aa%I<{ zqlBG_uC%au_}!lXZ}1m^u=3{*JpG2L+U`IXr<&FicdSE6VHO-a;;o~&Bh&fth>Y;~ z<(Ra@i7tD&-KRC-TpL{mti6UqzRFS9p@U=*_}QLNq-fTaeH-+78)*N*<0R3L=8dBa z>j(XnUn6pyDFTU&!W1B?QmH7&1ez2`3`Za!A#4HEIoY4i{bc|lc*prKSd^vGWSPYL zj*VXSK^M6Pq77pCj0&q-zkn47_Wu_|cOwlbPMmlwMReGlVR3WL>)+yxW7woq|JoncHftc4tV#g*@oLb$)|ICDd4w?Z z!;iE3?8L@3pk(_5b9G%t0 zo{$y(Sm!+h-s7Ca8bO|GBuJbvR?ZA_uz@Hb%!0vkQ#diEHyK{F``O>Bc`ub#GKjYC zwzp@COnOx$$*f#q#i)79fKeq5Vqy^VwNe>Q|2ZID{MEf>(iS(sofIeOiYag!Y>?q0 z69XuR$@&@~t~Aj(`ML#VS*ZOpi~N;-I28^RY%TPwjU;weex{zw!bSv#($n&+SSH=e z1nsyLx_|YnPCu}+dy{t~q*vYb$~0ON8TmgE{@_Q*WgORQ=>3?zZBnv_10Y6Vo~=*V zC8SHM8goM-7z2&wuv(GGMHDYn-p_7jkVu5+ZjmaE5_V*sa;IvGSI+`6h`#!akZKg> za}Y+{=aq_=eCv{vH_0L7jwg-NQH$@v>T0?s{(-0Nw~NqU6q6CQVOP+7a733BbU$-> zZgM=VsjXWh`e)#pLZQ28f9rz8)83d6(*wXr6K`oRmz83S?MHQQ@_P5PqBYP15}yM z9LcatW%v0A*1Qvf&sFT83qgf>X4$D@Cinw=2ShO3$tqZOx9ZBxN7?Y|^>5Lz?`Y)m>|VjW+rt`&BIOfdAzK)^OkQ zr`TeN#M7Bk1qP}4<7cm&Nb{lW-_qL2>xktBubtMHr$t=m?H^|5P#7O@Lr63>SKBXXu<v}HYe6u$#Dax4+ zz8?eEAJ8oqa)U#o6&*RVv~-K`wJL<_@(E{q&ki>f89=Xle&pf77R+rL=6#xhROzpM zc>3R{;#uSP<+YSThwJ~+?dJD+2rLoO?6VycIQ1ZX1#%mcAm8EC(|y9*&%ehtgQMvHhxrl1m;CL21Ee0V z&u%47Pfs{|m$ryV5{%z+#&cs34U2mi+(?2cSR|-l&?$Av*lj%mRR%^vj}iZ9^{A$f z9C9qE(|g|8@6StoMo*rfm?#QlO36t>3X;P(neUPOmE+G!*S#Y)sCj^u852ixJTzBJ zou{sqFBbtiC^I?E|B5mCQR?F$*JhE&SL- z^g?ltE;-P`ooPO|7O%rrtbOCFK#-$gxTcSK0V=(3#T4N-44`wtg0+n=c<=f8{q+;W zkVW%fr7n`B5DPs~gyx~6j3@}aYqsi@V_y61!}8wEo?B{_Lgt>iyy#*dj;gH}%FKXl zEXmC5Y((Yj_BTBwL$thANL4|mCb}eFGJ%$4kEHOx@%vw(TWO5|@(9T~?j9XR@qipe zZ$n(fK`jGp7+nbyzxrbQCrJYPLD~q!qA*~P!|KvcH__M25k!dpEJiZoxU!sk})RD&18k2Z9Sjh7kbiA2(p!$cKMw*Y+59#QS=?W@PTpp}hihu6kpCgK-%ZBXVlQ>3}Z7vQXI{!k;^yVgph6kal# z7VhTpH+$X}^3oCv(R8a-164B_kOQfv9G9Ev{Mk*M;6>ZedUxlVlgaewJC~6|GKLG9 z15f(cI59?38ABw=tKN%2{WF>VX?jtUA+k%Z;eIA|D zv=&uNtt{AQ3YeVxgEay?jn=925d3n;w=YHJ70Ssm(BMWv z>VJ}bQVGH-KJ+{z=CYqrTfX)FZW`{N8nuG-Ljbid79e=nu#;U`8%_b6jZaX(Yb*zE zhOz=SUIIsHIYqslI5vQjzRVrvS&%|pP9P-^4n|x<7HrlLd&HIoijCAh{2|d}8ce|+ zxuVj?5iO{BOr*AQR(g#d74NDMA6zlxv#srvbzuWVQ3+_(&ai0^d#?5>JyC%8e2c@b zSKcsJ&h7ofLm5-e*aW}4u-wd$0Yn8$GvuH81XpXkeg6!Z+N=?~g-=AAGS!|mzGGos zBj+`X{DH3!h-kRMOTca~Ob`%{pBoecK*o--X^eUwhBF&VE`X9MHY4|utg7PWW`32V zTt09XtmY$-ZziMh5dt&$_!*Qyk5|YeS!EHx9!ysHwZ ztM7#>hj)3b6}2WO7z$ZoY%%!PYS^ioklQtzr8%JrZsB@vHq;=-u&A>!!r$#q3^~8~ z5T1HP?$HFv6A{2N!39L0h*BGF8}Ly@Zq+1Ut1Yxwz6mv5*|^nA5J5eBj+8u~jchD_ z`~hYH${hj`iO^JVY8`@063yruuBxTrdq=k)!rTe?Cl?zUj`yN z`brwjcptdf#mez^I!o*fp!{H*cm4^Sbq1ZNyLEl zrQ7=|elvCmPQ=3p1~=FSDcLzy%FSz{3*R{H-Btp~xXfS-8u^dQ6ymopZDY|K_$$4J z_Z`@~#JmAlbIbQN7D!hL<=jr-p>W0R08bR6r;PeSvU4AavQ?CF3PQtD-5M&e;UbGn z^#NVRfhiWM<{Sqv#Qp#VSSn4`xjE$|QX%#*k`Bv1f0VH>({{x;Q68>#z|!I+0KkI? zPAJObQ{J9WON<zHSTi#gD0aQjx2Ved~!DdZJ750ipHD;k}QG{!}33T2W9^Y1Zi+ z>Ee2zRj;swjcH5@jee>2ZPWE-+M@C&>7~dh2eBb(&9MIK%AM8UUc7){G3ME(ue;|) z&!@d)!xw31JKu*{n1?O zX1!tCP^6U(HEhtJlQ_5LR3~b-UXV($bQ3DYQPnryUsz#a9seyM6jV;761MQE2XXsj+w^xp{U%KDH7q|r*hP85_dQgoTZ11?d$QF!Hr1+%vM?`e#*teG zf3WJoNmRDA*huqkD{+VFqz3cjnX0RLRwlEo*LT4f<>4rVLs^tZ4fzQE=mhvf4)s#s zG@>*6(lVFne8}=05vPIRONU)d24rH?S2QU_`z68mZG9rvCPIVUE_z8DF(K7C_XMfg zuUu6k9%S_de;n_Ic(aYuu<;YXG6`4~v0NXQH!Dxd2tQc0v2P6p7gavI(Hym3mM&;W zeXJa5Et7K5Ih}`pbuw~bVl#T!YwXbD9W&I;ttIen8q>27yU#|`YHN=5`9O=;6V4=h z{s3K5eSa%_02>-H5#R1n*S1mHTe8Guq2m?%qw>>(T_(e^_=`?#>d&kPMIUE!iHM)! z`=RXF%ZeqD+v-fZw`0hCIpcnah#h^R3c96tSq&wG{1rY}{6#!T5XwzY5Def%+8_7;zxt6N_LNy`a^ zaZeV;=Z|(VuN`0lHr-`GMI>9d8p0DnOw1a26}ORCE!-Y`%lgR4m1qgBxkz+O16}xO z^OXV~HkEE`Y=|*XL5qTDF@PPUH0ms$hHX(D=>m)ATWXkVVCWTz<4qa36y_0~IK%jH zfpAynmJq2yTWsji4L}J_7y5mI{&%m^k`GVzRs$K7*eWo8Dt=MjVz0dg>Z_JpM^0W0 zNN7)I0Yu4&IP64k|9t$pfbFeZU7bb2za{8}PCT>4ug1tm`Nuo>>aiNJoKR#g?G=-? z*BF0YwDQl{>egi(_AED{=A8Us6A)w%Z-G=(Crr^)ogMA58sB5HBiesSeG8>VL=h%K zf1wnGnJ4lYI@zL4I;2OXiM)?2Q7XHefO`S*qSvQv*-URuNqR~*+lsA+h>P__DKf*2 zf2}4Q9{XGF%9b)u#8Cbeu!{7SyQnpB?w*dv+9_=GaLty~aZjFfOGsP$<6~yL9C zREk2}6<@taNX^{P#rxDPNT|X=XpPTyr@Zvn*udhVa&Uf^g1FSN)lrbaZ>-yrP-<csjC7ccEYGB*B+nYK>$*kLoq-pQYM%tXRQ&(H_j!$*Q3I1qc0+J9S zg>e5NNN;8WRS9q(AF}UB#!!Bm5Vb2wi;hte2oTGZ#9(#$lLOi zvySZ&DW%dIRV`y11<8YWy9iMQT~5aMRCP*qRJ>TD4&I+AM=RiN_Jr(%^`QS6OO)FX zBHCK6S;ky%$C>1EH1P==Tk_FIofVe-AZ#mGJ~d*o%XLQHkrU6*-w553J=Q^eGaZG$ zEPED`XP{!?(hnS|2{j3vF8bMza9G{Uz@4mA{aJ^t%$17?LG2Wrtm1ISyM$A;aJQvZ zHg2+_NA&2=f{4f<{`qx+#8QOuQ+dn?^hm6NE6aD%j*#VrX$tZC@89+VRFamIYU%<~ zsDd`?VW@6BcTILWO|-jC7}^`ncoxnDQ1oum`_{qs#SebUJg=h!X)G`dQ&{<`?^3qb z9Hsm2()Xjzt8{9OyY%qNeM!pYNI*5sZRVyhD3n|VlvYv0^oc-C8ZTQCqtBpmkB-_N z@T(I}$;suQ_R;G!RysNE>{&!SGt7RK=`ZuHvRBzbGm9zRu`^)yJ2s zD}xU2_1bZ?@^C1vEL8N;_XTsk8nt zX@VS7B4VPVzB~=@Fo)G9z^h@4NK#MML)DC7ZU=}WX;I7&19(7!XggmMzFxJ6AhCof zN2^liY4U1OQUA7=oy~?gS*rG3P()dhKrjnnDl@y{weo|K(?3Vji%xB(?B5I;lFbdv zGAK|q(~@mjjerlD?DjIDVsLq)5?)|t005r*pIm^iHeT0;{A-zI1RYiWueiu_fMMJ4 z_-;0okx+_9(Js#c4ME>or%%3Il>~HmlcAY{OU-^;q>Z0~Ho0|##XJ-44dxaGLchNw zgfSkEK{&A?Zdz)*c>~SW6^xMqnV3uuwIf{ZzdnSu_K*B3SpqP2HZKmiu*)&`)gze3 z+Bp9FB`V#!MH)K)qe=LBY*~{y~s-ljwc(uKeXOxLid`sIlux-ng$?4YZ%k`7if zslMfb4;tJ;&2^Bn4mLg!Iu-}5L6f@yY#2Ipz!}IFW?B_vgC4Y z^C~HqzLTA)%c=rw#L^uO{DyKt)X$4%OF>hV( z2{BhV_Pfu!(NPIZwKhcAti$_^Ys}ZfOXZ1mg%UQIVfym=qs&Qw;8=7@>D14}r=W3Z zFx$>2QC>^munA3UB}PTkLzYbt9#w3t(r?guqr)TOTRSM3Q!6>6?DWtYYki4}9P^LU z20}{R)lTEv5#M;UIH1{Rl!h!#W+j}1Ex z@PdJ$1I4kQJGQiFbsWA=TlENJF?4nYpeVlNd{-x01Om-F2y32Uln;bCE0^lTqP69&>)R=Em{wxNc8J_XV}R4H1JPOM!2>jiI@6b z5)gS%YZymKao8-gmN#nVY9QKodLFrfv)r61CnmQ_-Y~8ZNpOAW zqZNMPLHE-lMUg?bRHNq#4Wp(?PrcuZI^Va?GYQ`Ulj&L%Q+S=J)An zF&e#1fi51Xzs4RS`$=M6^;!1%@tFzJs8hr_dtm`EyZ}CdOW|PNgf}c12T8?WMu<~9 zP}G0|y&hn*GD9Y^eXw&KKo9B0I*@pAfFO}R3}OW56!LSzY*+Y2_2zj!dEVK@g@3!G z;yvE1)c=@@^FKAD1#i8<_4-s&cF)Hi0sydBHtO2$+KLJSW=;-lCgx727Hkj)XK3OP z03aj^aW*ltvv8+0wXm{r6sA9K>!PQ$F&C!S`k=_6=qzbrZ6o93YN6(%q;BS8XU1<% zFDil}1QCD&I9RxwP(mE+9o+;V!u0>b6@cFVQ_W6K`L8bScEa?s4klI>0s>MH8%uR3 zCwodx4mLgxdMJpixut+A=+nO;pe12?Yj<~N0d{sTFE2JPZZ;=ZD|SwPetvciE_N<1 zR%j1aH*ZIG69}uL8#NRGh4Nn*APYA$R~u({8z)D~e=toFH4@{|)W@-=H1c z{_O#%FW8|C?3`@e>`*L9N+D=TK-|OK+R0T!&BVji#MGKn)x<{VpI-mF9y%iXKSTVt zA^-o)fV%8IPxybB0Woogn!)jJGoalBBwZ~`+?`zi@t26CiKC~95c~gK{r@!Oe_020 nD%8E~{|OSb@SiYSI6`CV3Jqd21>Dm=Z-A_n5~xbTIOM+oPo8q4 From 0114e599616382e0ba770fede9c332984c5f8f06 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 24 Feb 2021 17:16:57 +0530 Subject: [PATCH 197/302] Added peak element --- data_structures/array/peak_element.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/data_structures/array/peak_element.py b/data_structures/array/peak_element.py index e69de29b..29d8b1f2 100644 --- a/data_structures/array/peak_element.py +++ b/data_structures/array/peak_element.py @@ -0,0 +1,22 @@ +# A peak element is an element such that both of its neighbours are smaller than it +# In case of corner elements, consider only one neighbour + + +def peak(arr, low, high): + n = len(arr) + + while low <= high: + mid = low + (high - low) / 2 + mid = int(mid) + + if (mid == 0 or arr[mid-1] <= arr[mid]) and (mid == n-1 or arr[mid+1] <= arr[mid]): + return(arr[mid]) + + elif mid > 0 and arr[mid-1] > arr[mid]: + high = mid - 1 + + else: + low = mid + 1 + +arr = [1, 3, 20, 4, 1, 0] +print(peak(arr, 0, len(arr) - 1)) \ No newline at end of file From a6375c3e60a46aaa2e710f819196f2df7b88d521 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 25 Feb 2021 08:17:26 +0530 Subject: [PATCH 198/302] Modified duplicates --- data_structures/array/duplicate.py | 16 +++++++++++++--- data_structures/array/duplicates.py | 2 +- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/data_structures/array/duplicate.py b/data_structures/array/duplicate.py index ad4a3fa5..1e4f6291 100644 --- a/data_structures/array/duplicate.py +++ b/data_structures/array/duplicate.py @@ -1,6 +1,12 @@ # Find duplicate in an array of integers given that the integers are in random order and # not necessarily each integer i is 0 <= i <= N where N = length of array +# Solution - use tortoise and hare algorithm. The tortoise pointer moves slower while the hare pointer +# moves faster + +# Note: this array will always contain a duplicate number due to the pigeonhole principle. You are trying to fit +# N different numbers in an array of size N - 1 so one number will be repeated + def duplicate(arr): tortoise = arr[0] hare = arr[0] @@ -11,10 +17,14 @@ def duplicate(arr): if tortoise == hare: break - ptr1 = nums[0] + ptr1 = arr[0] ptr2 = tortoise while ptr1 != ptr2: - ptr1 = nums[ptr1] - ptr2 = nums[ptr2] + ptr1 = arr[ptr1] + ptr2 = arr[ptr2] return ptr1 + + +arr = [3,5,1,2,4,5] +print(duplicate(arr)) \ No newline at end of file diff --git a/data_structures/array/duplicates.py b/data_structures/array/duplicates.py index 04940c0e..a146efba 100644 --- a/data_structures/array/duplicates.py +++ b/data_structures/array/duplicates.py @@ -4,5 +4,5 @@ def duplicate(arr): if arr[abs(x) - 1] < 0: res.append(abs(x)) else: - nums[abs(x) - 1] *= -1 + arr[abs(x) - 1] *= -1 return res From 53a1e37f81fde93665d1d8aa861053343e810d80 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 25 Feb 2021 08:17:48 +0530 Subject: [PATCH 199/302] Add rotation --- data_structures/array/rotation.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/data_structures/array/rotation.py b/data_structures/array/rotation.py index 36b9db0b..c89ab715 100644 --- a/data_structures/array/rotation.py +++ b/data_structures/array/rotation.py @@ -14,14 +14,14 @@ def rotate(arr, d): while 1: k = j + d if k >= n: - k = k -n + k -= n if k == i: break arr[j] = arr[k] j = k arr[j] = temp - + arr = [1,2,3,4,5] -rotate(arr, 1) +rotate(arr, 3) print(arr) From 1911e7069e8425fa8d4cbdf5c0044f7b8bb48fec Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Fri, 26 Feb 2021 17:40:37 +0530 Subject: [PATCH 200/302] Add program description --- data_structures/array/majority_element.py | 9 +++++++++ data_structures/array/moves_zeros_to_end.py | 3 +++ 2 files changed, 12 insertions(+) diff --git a/data_structures/array/majority_element.py b/data_structures/array/majority_element.py index 511902dd..457686ad 100644 --- a/data_structures/array/majority_element.py +++ b/data_structures/array/majority_element.py @@ -1,3 +1,7 @@ +# The only prerequisite condition of this algorithm is that the array +# definitely contains a majority element, otherwise it will just return +# the last element + def majority(arr): maj_index = 0 count = 1 @@ -11,3 +15,8 @@ def majority(arr): count = 1 return arr[maj_index] + + +arr = [3, 3, 1,5,6,8,3,0,7] + +print(majority(arr)) \ No newline at end of file diff --git a/data_structures/array/moves_zeros_to_end.py b/data_structures/array/moves_zeros_to_end.py index 036c5cd8..c5589961 100644 --- a/data_structures/array/moves_zeros_to_end.py +++ b/data_structures/array/moves_zeros_to_end.py @@ -1,3 +1,6 @@ +# Move all zeros in an array to the end + + def move(arr): count = 0 for a in arr: From b3a66193cddf0bcb0e30493e505ec291647d49c8 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Sun, 28 Feb 2021 12:31:13 +0530 Subject: [PATCH 201/302] New array questions --- data_structures/array/equilibrium_index.py | 23 +++++++++++ data_structures/array/even_more_than_odd.py | 16 ++++++++ data_structures/array/min_swaps.py | 39 +++++++++++++++++++ .../array/rearrange_positive_negative.py | 23 +++++++++++ 4 files changed, 101 insertions(+) create mode 100644 data_structures/array/equilibrium_index.py create mode 100644 data_structures/array/even_more_than_odd.py create mode 100644 data_structures/array/min_swaps.py create mode 100644 data_structures/array/rearrange_positive_negative.py diff --git a/data_structures/array/equilibrium_index.py b/data_structures/array/equilibrium_index.py new file mode 100644 index 00000000..2b1d0601 --- /dev/null +++ b/data_structures/array/equilibrium_index.py @@ -0,0 +1,23 @@ +# Find the equilibrium index of an array. An equilibrium index is such that +# the sum of elements to the left of it is equal to sum of elements to the right +# of it + +def find_equi(arr): + total_sum = sum(arr) + + left_sum = 0 + + for i, num in enumerate(arr): + + total_sum -= num + + if left_sum == total_sum: + return i + + left_sum += num + + return -1 + + +arr = [-7, 1, 5, 2, -4, 3, 0] +print(find_equi(arr)) diff --git a/data_structures/array/even_more_than_odd.py b/data_structures/array/even_more_than_odd.py new file mode 100644 index 00000000..62735d9c --- /dev/null +++ b/data_structures/array/even_more_than_odd.py @@ -0,0 +1,16 @@ +# Rearrange an array such that numbers at even indexes are greater than numbers +# at odd indexes + +def rearrange(arr): + for i in range(1, len(arr)): + if i % 2 == 0: + if arr[i] > arr[i-1]: + arr[i-1], arr[i] = arr[i], arr[i-1] + else: + if arr[i] < arr[i-1]: + arr[i-1], arr[i] = arr[i], arr[i-1] + print(arr) + + +arr = [ 1, 3, 2, 2, 5 ] +rearrange(arr) \ No newline at end of file diff --git a/data_structures/array/min_swaps.py b/data_structures/array/min_swaps.py new file mode 100644 index 00000000..3fdd13a7 --- /dev/null +++ b/data_structures/array/min_swaps.py @@ -0,0 +1,39 @@ +# Minimum swaps required to bring all elements less than or equal to k together + +def min_swaps(arr, k): + # First find out how many elements are there which are less than or + # equal to k + count = 0 + for i in arr: + if i <= k: + count += 1 + + # This count defines a window - inside this window all our elements should + # be placed + # Find the count of bad elements - elements which are more than k and that will be + # our starting answer as we will have to swap them out + bad = 0 + for i in range(0, count): + if arr[i] > k: + bad += 1 + + ans = bad + j = count + + for i in range(0, len(arr)): + if j == len(arr): + break + + if arr[i] > k: + bad -= 1 # because we have moved the bad element out of the window + + if arr[j] > k: + bad += 1 + + ans = min(bad, ans) + j += 1 + + print('answer - ', ans) + +arr = [2,7,9,5,8,7,4] +min_swaps(arr, 5) \ No newline at end of file diff --git a/data_structures/array/rearrange_positive_negative.py b/data_structures/array/rearrange_positive_negative.py new file mode 100644 index 00000000..ab1b971c --- /dev/null +++ b/data_structures/array/rearrange_positive_negative.py @@ -0,0 +1,23 @@ +# Rearragne positive and negative numbers in an array such that they appear +# alternately. If there are more numbers of any one kind, put them at the end + +def rearrange(arr): + i = -1 + + for j in range(len(arr)): + if arr[j] < 0: + i += 1 # maintaining index of the last negative number + arr[j], arr[i] = arr[i], arr[j] + + pos = i + 1 # index of first positive number + neg = 0 # index of first negative number + + while pos < len(arr) and neg < pos and arr[neg] < 0: + arr[pos], arr[neg] = arr[neg], arr[pos] + pos += 1 + neg += 2 + + print(arr) + +arr = [-1, 2, -3, 4, 5, 6, -7, 8, 9] +rearrange(arr) \ No newline at end of file From 90c562fd475bddbd1b2a3d0a051c0361c6cffd45 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 1 Mar 2021 18:55:00 +0530 Subject: [PATCH 202/302] Add bipartite graph --- data_structures/graphs/bipartite_graph.py | 56 +++++++++++++++++++---- 1 file changed, 46 insertions(+), 10 deletions(-) diff --git a/data_structures/graphs/bipartite_graph.py b/data_structures/graphs/bipartite_graph.py index 0c851248..a1ebb149 100644 --- a/data_structures/graphs/bipartite_graph.py +++ b/data_structures/graphs/bipartite_graph.py @@ -7,6 +7,12 @@ # Reference - https://www.geeksforgeeks.org/bipartite-graph/ +# A bipartite graph is a graph whose vertices can be divided into two disjoint sets U and V +# such that every edge connects a vertex in U to one in V. Also, a bipartite graph does not +# contain any odd length cycles + +# Also, a graph with no edge is a bipartite graph - https://math.stackexchange.com/a/53947 + from collections import defaultdict class Graph: @@ -16,31 +22,61 @@ def __init__(self, vertices): self.graph = defaultdict(list) + def add_edge(self, u, v): + self.graph[u].append(v) + self.graph[v].append(u) + + + def bfs(self, s): + visited = [False] * self.V + queue = [] + queue.append(s) + visited[s] = True + + while queue: + s = queue.pop(0) + print(s, end=' ') + + for i in self.graph[s]: + if not visited[i]: + visited[i] = True + queue.append(i) + + def is_bipartite(self, s): - # 0 -> color 0 - # 1 -> color 1 + # 0 -> color 0 (blue) + # 1 -> color 1 (red) # -1 -> no color assigned colors = [-1] * self.V - colors[s] = 1 + colors[s] = 1 # Color soure vertex red queue = [] queue.append(s) while queue: - u = queue.pop() + s = queue.pop(0) - if self.graph[u][v] == 1: # Check for self loop + if s in self.graph[s]: # Check for self loop return False # An edge u to v exists and destination is not # colored - for v in range(self.V): - if self.graph[u][v] == 1 and colors[v] == -1: - colors[v] = 1 - colors[u] - queue.append(v) + for i in self.graph[s]: + if colors[i] == -1: + colors[i] = 1 - colors[s] + queue.append(i) - elif self.graph[u][v] == 1 and colors[v] == colors[u]: + elif colors[i] == colors[s]: return False return True + + +g = Graph(5) +g.add_edge(0, 1) +g.add_edge(1, 2) +g.add_edge(2, 3) +g.add_edge(3, 4) +g.add_edge(4, 0) +print(g.is_bipartite(0)) \ No newline at end of file From 58232f3f95037d080131636cd74ba9b0cce54d21 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 4 Mar 2021 08:40:29 +0530 Subject: [PATCH 203/302] Modified iterative dfs to work for disconnected vertices --- data_structures/graphs/iterative_dfs.py | 51 ++++++++++++++----------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/data_structures/graphs/iterative_dfs.py b/data_structures/graphs/iterative_dfs.py index 65c092dc..d150c9cb 100644 --- a/data_structures/graphs/iterative_dfs.py +++ b/data_structures/graphs/iterative_dfs.py @@ -5,7 +5,8 @@ class Graph: - def __init__(self): + def __init__(self, vertices): + self.vertices = vertices self.graph = defaultdict(list) @@ -13,30 +14,36 @@ def add_edge(self, u, v): self.graph[u].append(v) - def dfs(self, s): - visited = [False] * len(self.graph) + def dfs(self): + visited = [False] * self.vertices - stack = [] + for s in range(self.vertices): + if not visited[s]: + visited[s] = True + + stack = [] + stack.append(s) - stack.append(s) - visited[s] = True + while stack: + s = stack.pop() + print(s, end=' ') - while stack: - s = stack.pop() - print(s, end=' ') + for i in self.graph[s]: + if visited[i] == False: + stack.append(i) + visited[i] = True - for i in self.graph[s]: - if visited[i] == False: - stack.append(i) - visited[i] = True +# g = Graph() +# g.add_edge(0, 1) +# g.add_edge(0, 2) +# g.add_edge(1, 2) +# g.add_edge(2, 0) +# g.add_edge(2, 3) +# g.add_edge(3, 3) +g = Graph(5) +g.add_edge(0, 1) +g.add_edge(0, 2) +g.add_edge(3, 4) -g = Graph() -g.add_edge(0, 1) -g.add_edge(0, 2) -g.add_edge(1, 2) -g.add_edge(2, 0) -g.add_edge(2, 3) -g.add_edge(3, 3) - -g.dfs(0) +g.dfs() From 4979d39c02179c6deb6125058971bbb00c4ea43c Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 4 Mar 2021 08:40:44 +0530 Subject: [PATCH 204/302] Add count trees --- data_structures/graphs/count_trees.py | 46 +++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 data_structures/graphs/count_trees.py diff --git a/data_structures/graphs/count_trees.py b/data_structures/graphs/count_trees.py new file mode 100644 index 00000000..84841062 --- /dev/null +++ b/data_structures/graphs/count_trees.py @@ -0,0 +1,46 @@ +# Count the number of tress in a graph (forest) + +from collections import defaultdict + +class Graph: + + def __init__(self, vertices): + self.vertices = vertices + self.graph = defaultdict(list) + + + def add_edge(self, u, v): + self.graph[v].append(u) + self.graph[u].append(v) + + + def count_trees(self): + visited = [False] * self.vertices + count = 0 + + for s in range(self.vertices): + if not visited[s]: + visited[s] = True + stack = [] + stack.append(s) + count += 1 + + while stack: + print(stack) + s = stack.pop() + + for i in self.graph[s]: + if not visited[i]: + visited[i] = True + stack.append(i) + + return count + + +g = Graph(5) +g.add_edge(0, 1) +g.add_edge(0, 2) +g.add_edge(3, 4) + +print('Count of trees - ', g.count_trees()) + From e5a98ba51a959892dced8a525ad9c5b800f263f8 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 4 Mar 2021 09:12:16 +0530 Subject: [PATCH 205/302] Add levels of nodes --- data_structures/graphs/level_of_nodes.py | 45 ++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 data_structures/graphs/level_of_nodes.py diff --git a/data_structures/graphs/level_of_nodes.py b/data_structures/graphs/level_of_nodes.py new file mode 100644 index 00000000..31d01618 --- /dev/null +++ b/data_structures/graphs/level_of_nodes.py @@ -0,0 +1,45 @@ +from collections import defaultdict + +class Graph: + + def __init__(self, vertices): + self.vertices = vertices + self.graph = defaultdict(list) + + + def add_edge(self, u, v): + self.graph[u].append(v) + self.graph[v].append(u) + + + def print_levels(self, s): + levels = [None] * self.vertices + levels[s] = 0 + queue = [] + queue.append(s) + + while queue: + s = queue.pop(0) + + for i in self.graph[s]: + if not levels[i]: + levels[i] = levels[s] + 1 + queue.append(i) + + levels[0] = 0 + + print('Node \t Level') + for node, level in enumerate(levels): + print(f'{node} \t {level}') + +g = Graph(8) +g.add_edge(0, 1) +g.add_edge(0, 2) +g.add_edge(1, 3) +g.add_edge(1, 4) +g.add_edge(1, 5) +g.add_edge(2, 5) +g.add_edge(2, 6) +g.add_edge(6, 7) +g.print_levels(0) + \ No newline at end of file From 16f7b5439f1c7501a3aa17df7c0b7bae7bdf00b1 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Sat, 6 Mar 2021 09:22:29 +0530 Subject: [PATCH 206/302] Remove check and update statement for source node --- data_structures/graphs/level_of_nodes.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/data_structures/graphs/level_of_nodes.py b/data_structures/graphs/level_of_nodes.py index 31d01618..7190341c 100644 --- a/data_structures/graphs/level_of_nodes.py +++ b/data_structures/graphs/level_of_nodes.py @@ -22,12 +22,10 @@ def print_levels(self, s): s = queue.pop(0) for i in self.graph[s]: - if not levels[i]: + if levels[i] == None: levels[i] = levels[s] + 1 queue.append(i) - - levels[0] = 0 - + print('Node \t Level') for node, level in enumerate(levels): print(f'{node} \t {level}') @@ -42,4 +40,4 @@ def print_levels(self, s): g.add_edge(2, 6) g.add_edge(6, 7) g.print_levels(0) - \ No newline at end of file + From 9eb88425822b6da4d7bd673a124c13fbe6f17523 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 9 Mar 2021 15:20:13 +0530 Subject: [PATCH 207/302] Add print in dfs --- data_structures/graphs/dfs.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/data_structures/graphs/dfs.py b/data_structures/graphs/dfs.py index b6608f2b..6af4a6cc 100644 --- a/data_structures/graphs/dfs.py +++ b/data_structures/graphs/dfs.py @@ -7,7 +7,8 @@ def __init__(self): def add_edge(self, u, v): - self.graph[u].append[v] + self.graph[u].append(v) + self.graph[v].append(u) def dfs_util(self, v, visited): @@ -22,3 +23,13 @@ def dfs_util(self, v, visited): def dfs(self, v): visited = [False] * (len(self.graph)) self.dfs_util(v, visited) + + +g = Graph() +g.add_edge(0, 1) +g.add_edge(0, 2) +g.add_edge(0, 3) +g.add_edge(1, 4) +g.add_edge(2, 5) +g.add_edge(3, 6) +print(g.dfs(0)) From b2ca87d6eb0a3828f0beb49bf1eabbc801b85f35 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 6 Apr 2021 17:01:51 +0530 Subject: [PATCH 208/302] New graph questions --- .../graphs/min_edges_between_two_vertices.py | 52 ++++++++++++ .../graphs/print_all_paths_between_nodes.py | 50 ++++++++++++ data_structures/graphs/same_path.py | 80 +++++++++++++++++++ 3 files changed, 182 insertions(+) create mode 100644 data_structures/graphs/min_edges_between_two_vertices.py create mode 100644 data_structures/graphs/print_all_paths_between_nodes.py create mode 100644 data_structures/graphs/same_path.py diff --git a/data_structures/graphs/min_edges_between_two_vertices.py b/data_structures/graphs/min_edges_between_two_vertices.py new file mode 100644 index 00000000..13456d5f --- /dev/null +++ b/data_structures/graphs/min_edges_between_two_vertices.py @@ -0,0 +1,52 @@ +from collections import defaultdict + + +class Graph: + + def __init__(self, vertices): + self.vertices = vertices + self.graph = defaultdict(list) + + + def add_edge(self, u, v): + self.graph[u].append(v) + self.graph[v].append(u) + + + def find_min_edges(self, u, v): + visited = [False] * self.vertices + distance = [0] * self.vertices + queue = [] + + queue.append(u) + visited[u] = True + + while queue: + s = queue.pop(0) + + for i in self.graph[s]: + if visited[i] == False: + distance[i] = distance[s] + 1 + queue.append(i) + visited[i] = True + + return distance[v] + + +g = Graph(9) + +g.add_edge(0, 1) +g.add_edge(0, 7) +g.add_edge(1, 7) +g.add_edge(1, 2) +g.add_edge(2, 3) +g.add_edge(2, 5) +g.add_edge(2, 8) +g.add_edge(3, 4) +g.add_edge(3, 5) +g.add_edge(4, 5) +g.add_edge(5, 6) +g.add_edge(6, 7) +g.add_edge(7, 8) + +print(g.find_min_edges(0, 5)) diff --git a/data_structures/graphs/print_all_paths_between_nodes.py b/data_structures/graphs/print_all_paths_between_nodes.py new file mode 100644 index 00000000..cbd04abf --- /dev/null +++ b/data_structures/graphs/print_all_paths_between_nodes.py @@ -0,0 +1,50 @@ +from collections import defaultdict + +class Graph: + + + def __init__(self, vertices): + self.graph = defaultdict(list) + self.vertices = vertices + + + def add_edge(self, u, v): + self.graph[u].append(v) + + + def print_path(self, s, d, visited, path): + visited[s] = True + path.append(s) + + if s == d: + print(path) + + else: + for i in self.graph[s]: + if visited[i] == False: + self.print_path(i, d, visited, path) + + path.pop() + visited[s] = False + + + def print_all_paths(self, s, d): + visited = [False] * self.vertices + path = [] + self.print_path(s, d, visited, path) + + +g = Graph(4) + +g.add_edge(0, 3) +g.add_edge(0, 1) +g.add_edge(0, 2) +g.add_edge(1, 3) +g.add_edge(2, 0) +g.add_edge(2, 1) + +s = 2 +d = 3 + +print(f'Paths from {s} to {d} are - ') +g.print_all_paths(s, d) \ No newline at end of file diff --git a/data_structures/graphs/same_path.py b/data_structures/graphs/same_path.py new file mode 100644 index 00000000..127c1b86 --- /dev/null +++ b/data_structures/graphs/same_path.py @@ -0,0 +1,80 @@ +# Check if two nodes are on the same path in a tree. Use DFS and the concept of intime and outtime. +# Intime - time when a node is visited for the first time +# Outtime - time when a node is visited for the second time after all its children have been visited +# For any pair of node if they are on the same path - +# intime[u] < intime[v] and outtime[u] > outtime[v] + +from collections import defaultdict + +class Graph: + + + def __init__(self, vertices): + self.graph = defaultdict(list) + self.vertices = vertices + self.intime = None + self.outtime = None + + + def add_edge(self, u, v): + self.graph[u].append(v) + self.graph[v].append(u) + + + def dfs(self): + visited = [False] * self.vertices + intime = [0] * self.vertices + outtime = [0] * self.vertices + timer = 0 + num_children_visited = [0] * self.vertices + + for s in range(self.vertices): + if not visited[s]: + visited[s] = True + + stack = [] + stack.append(s) + + while stack: + s = stack.pop() + timer += 1 + intime[s] = timer + + print(s) + + for i in self.graph[s]: + if visited[i] == False: + stack.append(i) + visited[i] = True + num_children_visited[s] += 1 + + if num_children_visited[i] == len(self.graph[i]): + timer += 1 + outtime[i] = timer + + print('intime - ', intime) + print('outtime - ', outtime) + print('num_children_visited - ', num_children_visited) + self.intime = intime + self.outtime = outtime + + + def check_same_path(self, u, v): + if (self.intime[u] < self.intime[v] and self.outtime[u] > self.outtime[v]) or \ + (self.intime[v] < self.intime[u] and self.outtime[v] > self.outtime[u]): + return True + return False + + +g = Graph(7) +g.add_edge(0, 1) +g.add_edge(0, 2) +g.add_edge(0, 3) +g.add_edge(1, 4) +g.add_edge(2, 5) +g.add_edge(3, 6) + +g.dfs() + +print('Same path - ', g.check_same_path(0, 6)) +print(g.graph[6]) \ No newline at end of file From 38906557a2f63c7342d240c974b349797fbe4851 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 6 Apr 2021 17:39:11 +0530 Subject: [PATCH 209/302] Add min number of operations --- .../graphs/min_number_of_operations.py | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 data_structures/graphs/min_number_of_operations.py diff --git a/data_structures/graphs/min_number_of_operations.py b/data_structures/graphs/min_number_of_operations.py new file mode 100644 index 00000000..7d783e30 --- /dev/null +++ b/data_structures/graphs/min_number_of_operations.py @@ -0,0 +1,54 @@ +""" +Minimum number of operations required to transform a number x to y +Valid operations - multiplication by 2, subtraction by 1 +Ex - x = 4, y = 7 +1. 4 * 2 = 8 +2. 8 - 1 = 7 +Answer = 2 +""" + + +from collections import defaultdict + + +class Node: + + + def __init__(self, value, level): + self.value = value + self.level = level + + +def min_steps(x, y): + node_x = Node(x, 0) + + visited = [] + queue = [] + queue.append(node_x) + + while queue: + s = queue.pop(0) + + if s.value == y: + return s.level + + visited.append(s.value) + + if s.value * 2 == y or s.value - 1 == y: + return s.level + 1 + + # If not visited already, add its children + + if s.value * 2 not in visited: + new_node = Node(s.value * 2, s.level + 1) + queue.append(new_node) + + if s.value - 1 not in visited: + new_node = Node(s.value - 1, s.level + 1) + queue.append(new_node) + + +x = 2 +y = 5 + +print(min_steps(x, y)) \ No newline at end of file From 9ad3c9aee7d5c8a3db77d17f7802878388b090b4 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 7 Apr 2021 08:45:01 +0530 Subject: [PATCH 210/302] Refactored comments --- data_structures/graphs/bipartite_graph.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/data_structures/graphs/bipartite_graph.py b/data_structures/graphs/bipartite_graph.py index a1ebb149..0296de6e 100644 --- a/data_structures/graphs/bipartite_graph.py +++ b/data_structures/graphs/bipartite_graph.py @@ -1,17 +1,19 @@ -# Check for bipartite graph +""" +Check for bipartite graph -# Do a BFS and make source of red color and its neighbour blue -# Keep on doing this. -# If self loop, return false -# If current color == neighbour color, false, else true +Do a BFS and make source of red color and its neighbour blue +Keep on doing this. +If self loop, return false +If current color == neighbour color, false, else true -# Reference - https://www.geeksforgeeks.org/bipartite-graph/ +Reference - https://www.geeksforgeeks.org/bipartite-graph/ -# A bipartite graph is a graph whose vertices can be divided into two disjoint sets U and V -# such that every edge connects a vertex in U to one in V. Also, a bipartite graph does not -# contain any odd length cycles +A bipartite graph is a graph whose vertices can be divided into two disjoint sets U and V +such that every edge connects a vertex in U to one in V. Also, a bipartite graph does not +contain any odd length cycles -# Also, a graph with no edge is a bipartite graph - https://math.stackexchange.com/a/53947 +Also, a graph with no edge is a bipartite graph - https://math.stackexchange.com/a/53947 +""" from collections import defaultdict From f0b8d79eca5a1583933431357e43257fbab61bee Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 7 Apr 2021 08:58:22 +0530 Subject: [PATCH 211/302] max_edges_to_make_bipartite.py --- .../graphs/max_edges_to_make_bipartite.py | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 data_structures/graphs/max_edges_to_make_bipartite.py diff --git a/data_structures/graphs/max_edges_to_make_bipartite.py b/data_structures/graphs/max_edges_to_make_bipartite.py new file mode 100644 index 00000000..9b42fb82 --- /dev/null +++ b/data_structures/graphs/max_edges_to_make_bipartite.py @@ -0,0 +1,60 @@ +""" +Find the max edges that can be added to a tree so that it stays a bipartite graph + +keep count of nodes of each color - say count_color1, count_color2 +These nodes can be connected in count_color1 x count_color2 ways = max no of edges of a bipartite graph +Also, a tree has n-1 edges +So answer = (count_color1 x count_color2) - (n - 1) + +If the answer comes negative, then its impossible to add any edge because of odd cycles +""" + +from collections import defaultdict + +class Graph: + + + def __init__(self, vertices): + self.graph = defaultdict(list) + self.vertices = vertices + + + def add_edge(self, u, v): + self.graph[u].append(v) + self.graph[v].append(u) + + + def bfs(self, s): + count_color0 = 0 + count_color1 = 0 + + colors = [-1] * self.vertices + colors[s] = 1 + count_color1 += 1 + + queue = [] + queue.append(s) + + while queue: + s = queue.pop(0) + + for i in self.graph[s]: + if colors[i] == -1: + colors[i] = 1 - colors[s] + if colors[i] == 0: + count_color0 += 1 + else: + count_color1 += 1 + queue.append(i) + + ans = (count_color0 * count_color1) - (self.vertices - 1) + return ans if ans > 0 else 0 + + +g = Graph(5) +g.add_edge(0, 1) +g.add_edge(0, 2) +g.add_edge(1, 3) +g.add_edge(2, 4) + +print(g.bfs(0)) \ No newline at end of file From f844c64b75834bc67669a3eb069c00b572ffa3f3 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 8 Apr 2021 17:43:56 +0530 Subject: [PATCH 212/302] Add directed cycle cycle check iterative --- .../cycle_in_directed_graph_iterative.py | 53 +++++++++++++++++++ data_structures/graphs/iterative_dfs.py | 6 +-- 2 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 data_structures/graphs/cycle_in_directed_graph_iterative.py diff --git a/data_structures/graphs/cycle_in_directed_graph_iterative.py b/data_structures/graphs/cycle_in_directed_graph_iterative.py new file mode 100644 index 00000000..b20b8002 --- /dev/null +++ b/data_structures/graphs/cycle_in_directed_graph_iterative.py @@ -0,0 +1,53 @@ +from collections import defaultdict + + +class Graph: + + + def __init__(self, vertices): + self.graph = defaultdict(list) + self.vertices = vertices + + + def add_edge(self, u, v): + self.graph[u].append(v) + + + def dfs(self): + visited = [False] * self.vertices + recursion_stack = [False] * self.vertices + stack = [] + + for s in range(self.vertices): + if visited[s] == False: + visited[s] = True + recursion_stack[s] = True + + stack.append(s) + + while stack: + s = stack.pop() + + recursion_stack[s] = True + + for i in self.graph[s]: + if visited[i] == False: + stack.append(i) + visited[i] = True + recursion_stack[i] = True + elif recursion_stack[i] == True: + return "Contains Cycle" + + recursion_stack[s] = False + + return "No cycle" + + +g = Graph(4) +g.add_edge(0, 1) +g.add_edge(0, 2) +g.add_edge(1, 2) +g.add_edge(2, 0) +g.add_edge(2, 3) +g.add_edge(3, 3) +print(g.dfs()) \ No newline at end of file diff --git a/data_structures/graphs/iterative_dfs.py b/data_structures/graphs/iterative_dfs.py index d150c9cb..c2eb7169 100644 --- a/data_structures/graphs/iterative_dfs.py +++ b/data_structures/graphs/iterative_dfs.py @@ -16,12 +16,12 @@ def add_edge(self, u, v): def dfs(self): visited = [False] * self.vertices + stack = [] for s in range(self.vertices): - if not visited[s]: + if visited[s] == False: visited[s] = True - stack = [] stack.append(s) while stack: @@ -34,7 +34,7 @@ def dfs(self): visited[i] = True -# g = Graph() +# g = Graph(4) # g.add_edge(0, 1) # g.add_edge(0, 2) # g.add_edge(1, 2) From 1702373f324b4a56430725407614a20969c14f33 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 8 Apr 2021 18:13:50 +0530 Subject: [PATCH 213/302] Refactored code and add cycle in directed graph using colors --- .../cycle_in_directed_graph_iterative.py | 12 ++-- .../cycle_in_directed_graph_using_colors.py | 60 +++++++++++++++++++ ..._graph.py => cycle_in_undirected_graph.py} | 0 .../cycle_in_undirected_graph_iterative.py | 0 .../cycle_in_undirected_graph_union_find.py | 6 ++ 5 files changed, 72 insertions(+), 6 deletions(-) create mode 100644 data_structures/graphs/cycle_in_directed_graph_using_colors.py rename data_structures/graphs/{cyclic_in_undirected_graph.py => cycle_in_undirected_graph.py} (100%) create mode 100644 data_structures/graphs/cycle_in_undirected_graph_iterative.py create mode 100644 data_structures/graphs/cycle_in_undirected_graph_union_find.py diff --git a/data_structures/graphs/cycle_in_directed_graph_iterative.py b/data_structures/graphs/cycle_in_directed_graph_iterative.py index b20b8002..cc0b3cd2 100644 --- a/data_structures/graphs/cycle_in_directed_graph_iterative.py +++ b/data_structures/graphs/cycle_in_directed_graph_iterative.py @@ -18,12 +18,12 @@ def dfs(self): recursion_stack = [False] * self.vertices stack = [] - for s in range(self.vertices): - if visited[s] == False: - visited[s] = True - recursion_stack[s] = True + for v in range(self.vertices): + if visited[v] == False: + visited[v] = True + recursion_stack[v] = True - stack.append(s) + stack.append(v) while stack: s = stack.pop() @@ -38,7 +38,7 @@ def dfs(self): elif recursion_stack[i] == True: return "Contains Cycle" - recursion_stack[s] = False + recursion_stack[v] = False return "No cycle" diff --git a/data_structures/graphs/cycle_in_directed_graph_using_colors.py b/data_structures/graphs/cycle_in_directed_graph_using_colors.py new file mode 100644 index 00000000..44dfb5ac --- /dev/null +++ b/data_structures/graphs/cycle_in_directed_graph_using_colors.py @@ -0,0 +1,60 @@ +""" +Using three colors - white, gray and black +White - vertices that are not processed (inital state of all vertices) +Gray - vertices that are in DFS +Black - fully traversed vertices (i.e its progenies are also done) + +If while traversing any adjacent node is colored Gray, that means cycle exists +""" + +from collections import defaultdict + +class Graph: + + def __init__(self, vertices): + self.vertices = vertices + self.graph = defaultdict(list) + + + def add_edge(self, u, v): + self.graph[u].append(v) + + + def detect_cycle(self): + color = ['white'] * self.vertices + visited = [False] * self.vertices + + stack = [] + + for v in range(self.vertices): + if color[v] == 'white': + color[v] = 'gray' + + stack.append(v) + + while stack: + s = stack.pop() + + for i in self.graph[s]: + if color[i] == 'white': + stack.append(i) + color[i] = 'gray' + elif color[i] == 'gray': + return "Cycle detected" + + color[v] = 'black' + + return "Cycle not present" + + +g = Graph(4) +g.add_edge(0, 1) +g.add_edge(0, 2) +g.add_edge(1, 2) +g.add_edge(2, 0) +g.add_edge(2, 3) +g.add_edge(3, 3) +# g.add_edge(0, 1) +# g.add_edge(0, 2) +# g.add_edge(1, 3) +print(g.detect_cycle()) \ No newline at end of file diff --git a/data_structures/graphs/cyclic_in_undirected_graph.py b/data_structures/graphs/cycle_in_undirected_graph.py similarity index 100% rename from data_structures/graphs/cyclic_in_undirected_graph.py rename to data_structures/graphs/cycle_in_undirected_graph.py diff --git a/data_structures/graphs/cycle_in_undirected_graph_iterative.py b/data_structures/graphs/cycle_in_undirected_graph_iterative.py new file mode 100644 index 00000000..e69de29b diff --git a/data_structures/graphs/cycle_in_undirected_graph_union_find.py b/data_structures/graphs/cycle_in_undirected_graph_union_find.py new file mode 100644 index 00000000..b1904365 --- /dev/null +++ b/data_structures/graphs/cycle_in_undirected_graph_union_find.py @@ -0,0 +1,6 @@ +""" +This method cannot be used in Directed graph because of the direction of the edge. +In a union of set containing element A and B, you cannot specify whether A is going to B +or vice versa +""" + From 66b0a6428dfeaab23f6eeff3b28bada68eb3f427 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 8 Apr 2021 18:43:21 +0530 Subject: [PATCH 214/302] cyclic graphs --- .../cycle_in_undirected_graph_iterative.py | 8 +++ .../cycle_in_undirected_graph_union_find.py | 53 +++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/data_structures/graphs/cycle_in_undirected_graph_iterative.py b/data_structures/graphs/cycle_in_undirected_graph_iterative.py index e69de29b..3a1124ec 100644 --- a/data_structures/graphs/cycle_in_undirected_graph_iterative.py +++ b/data_structures/graphs/cycle_in_undirected_graph_iterative.py @@ -0,0 +1,8 @@ +""" +This is almost same as the iterative one for directed graph but we cannot use the +concept of recursion stack here because in directed graphs, there is defined path to +traverse but in undirected its possible that an edge (or a path) can be traversed +infite number of times. + +Instead check for parents. If a parent of a node is visited and +""" \ No newline at end of file diff --git a/data_structures/graphs/cycle_in_undirected_graph_union_find.py b/data_structures/graphs/cycle_in_undirected_graph_union_find.py index b1904365..e8e0af42 100644 --- a/data_structures/graphs/cycle_in_undirected_graph_union_find.py +++ b/data_structures/graphs/cycle_in_undirected_graph_union_find.py @@ -4,3 +4,56 @@ or vice versa """ +from collections import defaultdict + + +class Graph: + + + def __init__(self, vertices): + self.vertices = vertices + self.graph = defaultdict(list) + + + def add_edge(self, u, v): + self.graph[u].append(v) + + + def union(self, parent, x, y): + parent[x] = y + + + def find_parent(self, parent, i): + if parent[i] == -1: + return i + else: + return self.find_parent(parent, parent[i]) + + + def check_cyclic(self): + parent = [-1] * self.vertices + + for i in self.graph.keys(): + for j in self.graph[i]: + x = self.find_parent(parent, i) + y = self.find_parent(parent, j) + + if x == y: + return "Cyclic" + + self.union(parent, x, y) + + return "Not cyclic" + + +g = Graph(4) +g.add_edge(0, 1) +g.add_edge(0, 2) +g.add_edge(1, 2) +g.add_edge(2, 0) +g.add_edge(2, 3) +g.add_edge(3, 3) +# g.add_edge(0, 1) +# g.add_edge(0, 2) +# g.add_edge(1, 3) +print(g.check_cyclic()) \ No newline at end of file From bb279df2d55dcddbfad04d10edbf96c275e5674d Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Fri, 9 Apr 2021 17:31:59 +0530 Subject: [PATCH 215/302] Add bellman ford --- data_structures/graphs/bellman_ford.py | 101 +++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 data_structures/graphs/bellman_ford.py diff --git a/data_structures/graphs/bellman_ford.py b/data_structures/graphs/bellman_ford.py new file mode 100644 index 00000000..35c6522d --- /dev/null +++ b/data_structures/graphs/bellman_ford.py @@ -0,0 +1,101 @@ +""" +Bellman Ford algorithm is used to find the single source shortest path in a weighted directed graph. +Example - find the shortest path from node A to F + +Advantages of this algorithm over Djikstra's - +1. Bellman Ford also works for negative weight edges +2. Also finds negative weight cycles in a graph + +Disvantage - +1. Slower than Dijsktra's + +** Idea (https://www.youtube.com/watch?v=-mOEd_3gTK0&t) + +0. Shortest path can be found as - +if distance[v] > distance[u] + weight(u, v), then the right side is the shorter path +1. Mark parent and the new weight each time this is run +2. Do this V-1 times. In the first iteration, the algorithm will find the shortest path between the source +and source's neighbours +3. In the second, between source and source's neighbours' neighbours and so on (V - 1) times +4. Do this again. If in this Vth iteration, the weights of path decrease, then there is a negative cycle in the +graph + +Time complexity - O(V * E) +Space complexity - O(V) +""" + +from collections import defaultdict + +class Edge: + + def __init__(self, source, dest, weight): + self.source = source + self.dest = dest + self.weight = weight + + +class Graph: + + + def __init__(self, vertices): + self.graph = defaultdict(list) + self.vertices = vertices + self.edges = {} + + + def add_edge(self, u, v, weight): + self.graph[u].append(v) + self.edges[(u, v)] = Edge(u, v, weight) + + + def bellman_ford(self, source, destination): + parent = [-1] * self.vertices + distance = [float("inf")] * self.vertices + + parent[source] = source + distance[source] = source + + for (u, v) in self.edges: + wt = self.edges[(u, v)].weight + + if distance[v] > distance[u] + wt: + distance[v] = distance[u] + wt + parent[v] = u + + # Now for the Vth iteration, check for the negative cycle + + negative_cycle_present = False + + for (u, v) in self.edges: + wt = self.edges[(u, v)].weight + if distance[v] > distance[u] + wt: + print('h - ', u, v) + negative_cycle_present = True + break + + if negative_cycle_present: + print('Contains negative cycle') + else: + print('No negative cycle') + + # Printing the shortest path from source to destination + + while True: + print(f'{destination}', end=' ') + destination = parent[destination] + + if destination == source: + break + + +g = Graph(5) + +g.add_edge(0, 1, 4) +g.add_edge(0, 2, 5) +g.add_edge(0, 3, 8) +g.add_edge(1, 2, -3) +g.add_edge(2, 4, 4) +g.add_edge(3, 4, 2) +g.add_edge(4, 3, 1) + +g.bellman_ford(0, 3) \ No newline at end of file From f98921fab34afdd36383ffadf4e015b577659b0b Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 12 Apr 2021 10:22:45 +0530 Subject: [PATCH 216/302] Add max edges to add to DAG --- .../max_edges_that_can_be_added_to_dag.py | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 data_structures/graphs/max_edges_that_can_be_added_to_dag.py diff --git a/data_structures/graphs/max_edges_that_can_be_added_to_dag.py b/data_structures/graphs/max_edges_that_can_be_added_to_dag.py new file mode 100644 index 00000000..acad5380 --- /dev/null +++ b/data_structures/graphs/max_edges_that_can_be_added_to_dag.py @@ -0,0 +1,81 @@ +""" +Find the max number of edges that can be added to a Directed Acyclic Graph such that +it remains a DAG. + +Solution - +The trick is to add all edges from left to right. Now adding any edge from right to left +will make the graph cyclic because that edge's counterpart will exist from left-to-right. +Hence a cycle will be formed. + +1. Topologically sort all the edges +2. If edge is not there left to right, create the edge +3. Count the number of edges added + +""" + +from collections import defaultdict + +class Graph: + + + def __init__(self, vertices): + self.graph = defaultdict(list) + self.vertices = vertices + + + def add_edge(self, u, v): + self.graph[u].append(v) + + + def topological_sort_util(self, v, visited, stack): + visited[v] = True + + for i in self.graph[v]: + if visited[i] == False: + self.topological_sort_util(i, visited, stack) + + stack.insert(0, v) + + + def topological_sort(self): + visited = [False] * self.vertices + stack = [] + + for i in range(self.vertices): + if visited[i] == False: + self.topological_sort_util(i, visited, stack) + + return stack + + + def max_edges(self): + topo = self.topological_sort() + visited = [False] * self.vertices + count = 0 + + for i in topo: + vertex = topo[i] + # Mark the connected vertices visited + for j in self.graph[vertex]: + visited[j] = True + + # Print the unmarked nodes from topo + for j in range(i+1, len(topo)): + if visited[topo[j]] == False: + print(f"{vertex} -> {topo[j]}") + count += 1 + + visited[topo[j]] = False + + print('Maximum edges that can be added - ', count) + + +g = Graph(6) +g.add_edge(5, 2) +g.add_edge(5, 0) +g.add_edge(4, 0) +g.add_edge(4, 1) +g.add_edge(2, 3) +g.add_edge(3, 1) + +g.max_edges() \ No newline at end of file From 600c8457bfedd2ef46c774342a7c30d6d5806dee Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 12 Apr 2021 12:52:39 +0530 Subject: [PATCH 217/302] Add DAG shortest and longest path --- data_structures/graphs/dag_longest_path.py | 71 ++++++++++++++++++ data_structures/graphs/dag_shortest_path.py | 79 +++++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 data_structures/graphs/dag_longest_path.py create mode 100644 data_structures/graphs/dag_shortest_path.py diff --git a/data_structures/graphs/dag_longest_path.py b/data_structures/graphs/dag_longest_path.py new file mode 100644 index 00000000..796c43da --- /dev/null +++ b/data_structures/graphs/dag_longest_path.py @@ -0,0 +1,71 @@ +""" +The idea is similar to DAG Shortest Path. Only the comparision part changes +""" + +from collections import defaultdict + +class Graph: + + + def __init__(self, vertices): + self.graph = defaultdict(list) + self.vertices = vertices + + + def add_edge(self, u, v, w): + self.graph[u].append((v, w)) + + + def topological_sort_util(self, vertex, visited, stack): + visited[vertex] = True + + for v, weight in self.graph[vertex]: + if visited[v] == False: + self.topological_sort_util(v, visited, stack) + + stack.insert(0, vertex) + + + def topological_sort(self): + visited = [False] * self.vertices + stack = [] + + for v in range(self.vertices): + if visited[v] == False: + self.topological_sort_util(v, visited, stack) + + return stack + + + def longest_path(self, s): + stack = self.topological_sort() + + distance = [-float("inf")] * self.vertices + distance[s] = 0 + + while stack: + i = stack.pop(0) + + for vertex, weight in self.graph[i]: + if distance[vertex] < distance[i] + weight: + distance[vertex] = distance[i] + weight + + for i in range(self.vertices): + print(f"{s} -> {i} = {distance[i]}") + + +g = Graph(6) +g.add_edge(0, 1, 5) +g.add_edge(0, 2, 3) +g.add_edge(1, 3, 6) +g.add_edge(1, 2, 2) +g.add_edge(2, 4, 4) +g.add_edge(2, 5, 2) +g.add_edge(2, 3, 7) +g.add_edge(3, 5, 1) +g.add_edge(3, 4, -1) +g.add_edge(4, 5, -2) + +source = 0 + +g.longest_path(source) \ No newline at end of file diff --git a/data_structures/graphs/dag_shortest_path.py b/data_structures/graphs/dag_shortest_path.py new file mode 100644 index 00000000..36bebda4 --- /dev/null +++ b/data_structures/graphs/dag_shortest_path.py @@ -0,0 +1,79 @@ +""" +Find shortest path from source vertex to all vertices + +In general, Bellaman-Ford and Dijkstra can be used to find shortest path. But for +DAG, we can improvise + +Bellman-Ford: O(V*E), Dijsktra: O(E+VlogV) + +For DAG, using Topological sort will solve this problem in O(V+E). We are using Topo +sort because it lays out a graph in its linear representation according to the paths. +Hence we can proceed in this order to find shortest path +""" + +from collections import defaultdict + +class Graph: + + + def __init__(self, vertices): + self.graph = defaultdict(list) + self.vertices = vertices + + + def add_edge(self, u, v, w): + self.graph[u].append((v, w)) + + + def topological_sort_util(self, vertex, visited, stack): + visited[vertex] = True + + for v, weight in self.graph[vertex]: + if visited[v] == False: + self.topological_sort_util(v, visited, stack) + + stack.insert(0, vertex) + + + def topological_sort(self): + visited = [False] * self.vertices + stack = [] + + for v in range(self.vertices): + if visited[v] == False: + self.topological_sort_util(v, visited, stack) + + return stack + + + def shortest_path(self, s): + stack = self.topological_sort() + + distance = [float("inf")] * self.vertices + distance[s] = 0 + + while stack: + i = stack.pop(0) + + for vertex, weight in self.graph[i]: + if distance[vertex] > distance[i] + weight: + distance[vertex] = distance[i] + weight + + for i in range(self.vertices): + print(f"{s} -> {i} = {distance[i]}") + + +g = Graph(6) +g.add_edge(0, 1, 5) +g.add_edge(0, 2, 3) +g.add_edge(1, 3, 6) +g.add_edge(1, 2, 2) +g.add_edge(2, 4, 4) +g.add_edge(2, 5, 2) +g.add_edge(2, 3, 7) +g.add_edge(3, 4, -1) +g.add_edge(4, 5, -2) + +source = 0 + +g.shortest_path(source) \ No newline at end of file From 0635e65a1112563552a6136e5afbd6e1840fb7e4 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 13 Apr 2021 17:57:31 +0530 Subject: [PATCH 218/302] Fix BFS --- data_structures/graphs/bfs.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/data_structures/graphs/bfs.py b/data_structures/graphs/bfs.py index 82bda7d3..67722def 100644 --- a/data_structures/graphs/bfs.py +++ b/data_structures/graphs/bfs.py @@ -2,8 +2,9 @@ class Graph: - def __init__(self): + def __init__(self, vertices): self.graph = defaultdict(list) + self.vertices = vertices def add_edge(self, u, v): @@ -11,29 +12,31 @@ def add_edge(self, u, v): def bfs(self, s): - visited = [False] * len(self.graph) + visited = [False] * self.vertices queue = [] queue.append(s) visited[s] = True + bfs = [] + while queue: s = queue.pop(0) print(s, end=' ') - for i in self.graph[s]: if visited[i] == False: queue.append(i) visited[i] = True +g = Graph(6) -g = Graph() -g.add_edge(0, 1) -g.add_edge(0, 2) -g.add_edge(1, 2) -g.add_edge(2, 0) -g.add_edge(2, 3) -g.add_edge(3, 3) +g.add_edge(0, 1) +g.add_edge(0, 2) +g.add_edge(1, 3) +g.add_edge(0, 3) +g.add_edge(2, 4) +g.add_edge(3, 4) +g.add_edge(3, 5) g.bfs(0) From 3e6f90d07a97468f8bc63980ee505fb621b4ede6 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 13 Apr 2021 18:15:45 +0530 Subject: [PATCH 219/302] Add description --- data_structures/graphs/level_of_nodes.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/data_structures/graphs/level_of_nodes.py b/data_structures/graphs/level_of_nodes.py index 7190341c..c453fa95 100644 --- a/data_structures/graphs/level_of_nodes.py +++ b/data_structures/graphs/level_of_nodes.py @@ -1,3 +1,10 @@ +""" +Level is the distance of a node from a source node. This concept can be used to find +the distance between 2 nodes in an unweighted graph as well. A simple BFS traversal +between these 2 nodes will give the level and level will always be the shortest distance +between nodes. +""" + from collections import defaultdict class Graph: @@ -39,5 +46,4 @@ def print_levels(self, s): g.add_edge(2, 5) g.add_edge(2, 6) g.add_edge(6, 7) -g.print_levels(0) - +g.print_levels(0) \ No newline at end of file From d6051d2d6457643d580b8423892e2f70ac0b23fc Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 13 Apr 2021 18:16:03 +0530 Subject: [PATCH 220/302] Add shortest path --- .../graphs/shortest_path_unweighted_graph.py | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 data_structures/graphs/shortest_path_unweighted_graph.py diff --git a/data_structures/graphs/shortest_path_unweighted_graph.py b/data_structures/graphs/shortest_path_unweighted_graph.py new file mode 100644 index 00000000..ca5cd60b --- /dev/null +++ b/data_structures/graphs/shortest_path_unweighted_graph.py @@ -0,0 +1,68 @@ +""" +Find the shortest path between two nodes in an unweighted undirected graph. Remember this +is about finding the shortest path, not the shortest distance. For shortest +distance you can simply calculate the level of nodes from the source vertex +and that will give the answer. For shortest path, use the concept of parents of +Bellman-Ford algorithm. + +Simply do a BFS and keep track of parents of each node. Then recursively print the +parents of destination node until the source node. +""" + +from collections import defaultdict + +class Graph: + + def __init__(self, vertices): + self.vertices = vertices + self.graph = defaultdict(list) + + + def add_edge(self, u, v): + self.graph[u].append(v) + self.graph[v].append(u) + + + def bfs(self, s): + parent = [-1] * self.vertices + visited = [False] * self.vertices + visited[s] = True + queue = [] + queue.append(s) + + while queue: + s = queue.pop(0) + + for i in self.graph[s]: + if visited[i] == False: + queue.append(i) + parent[i] = s + visited[i] = True + + return parent + + + def shortest_path(self, source, dest): + parent = self.bfs(source) + + while True: + print(dest, end=' ') + dest = parent[dest] + + if dest == source: + break + + +g = Graph(8) +g.add_edge(0, 1) +g.add_edge(0, 3) +g.add_edge(1, 2) +g.add_edge(3, 4) +g.add_edge(3, 7) +g.add_edge(4, 5) +g.add_edge(4, 6) +g.add_edge(4, 7) +g.add_edge(5, 6) +g.add_edge(6, 7) + +g.shortest_path(0, 7) \ No newline at end of file From a0e470a7acbf9d8e1de961498ecbb226a050e3f9 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 14 Apr 2021 12:45:45 +0530 Subject: [PATCH 221/302] Add comments --- data_structures/graphs/count_edges.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/data_structures/graphs/count_edges.py b/data_structures/graphs/count_edges.py index f1601542..6b9d1f87 100644 --- a/data_structures/graphs/count_edges.py +++ b/data_structures/graphs/count_edges.py @@ -1,6 +1,12 @@ -# Use handshaking lemma -# deg(v) = 2|E| -# Time - O(V) +""" +Count the number of edges in an undirected graph + +Use Handshaking Lemma (Note: Handshaking Lemma is only for undirected graph) + +For all v in V, deg(v) = 2|E| +""" + +Time - O(V) class Graph: @@ -39,4 +45,4 @@ def count_edges(self): g.add_edge(6, 8 ) g.add_edge(7, 8 ) -print(g.count_edges()) +print(g.count_edges()) \ No newline at end of file From 2f87807aef8a8a65b7777db7d3c7c7c885566d9d Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 14 Apr 2021 12:50:29 +0530 Subject: [PATCH 222/302] Add comments --- data_structures/graphs/count_trees.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/data_structures/graphs/count_trees.py b/data_structures/graphs/count_trees.py index 84841062..28033ee9 100644 --- a/data_structures/graphs/count_trees.py +++ b/data_structures/graphs/count_trees.py @@ -1,4 +1,10 @@ -# Count the number of tress in a graph (forest) +""" +Count the number of trees in a forest + +A forest is a collection of trees. Do a DFS. If any vertex if not reachable +from any other, then it means it is not a part of that subgraph (tree). Hence +it is a different tree, so increment the count +""" from collections import defaultdict @@ -42,5 +48,4 @@ def count_trees(self): g.add_edge(0, 2) g.add_edge(3, 4) -print('Count of trees - ', g.count_trees()) - +print('Count of trees - ', g.count_trees()) \ No newline at end of file From 42a6240bfaad46e6b23319d3338be9a588f7d54e Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 14 Apr 2021 18:14:37 +0530 Subject: [PATCH 223/302] Add question --- .../cycle_in_undirected_graph_iterative.py | 56 ++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/data_structures/graphs/cycle_in_undirected_graph_iterative.py b/data_structures/graphs/cycle_in_undirected_graph_iterative.py index 3a1124ec..53bca95d 100644 --- a/data_structures/graphs/cycle_in_undirected_graph_iterative.py +++ b/data_structures/graphs/cycle_in_undirected_graph_iterative.py @@ -4,5 +4,57 @@ traverse but in undirected its possible that an edge (or a path) can be traversed infite number of times. -Instead check for parents. If a parent of a node is visited and -""" \ No newline at end of file +Instead check for parents (which means vertex fro which you reached the current vertex). +If a vertex is visited and you are not coming to this vertex from the current "source" vertex +(source - vertex from which DFS has started), then it means that in the same DFS chain, there is +another path to reach this vertex - hence a cycle +""" + +from collections import defaultdict + +class Graph: + + + def __init__(self, vertices): + self.graph = defaultdict(list) + self.vertices = vertices + + + def add_edge(self, u, v): + self.graph[u].append(v) + self.graph[v].append(u) + + + def dfs(self): + visited = [False] * self.vertices + parent = [-1] * self.vertices + + stack = [] + + for v in range(self.vertices): + if visited[v] == False: + visited[v] = True + + stack.append(v) + + while stack: + s = stack.pop() + + for i in self.graph[s]: + if visited[i] == False: + parent[i] = s + stack.append(i) + visited[i] = True + elif parent[s] != i: + return "Contains Cycle" + + return "No cycle" + + +g = Graph(5) +g.add_edge(1, 0) +g.add_edge(1, 2) +g.add_edge(2, 0) +g.add_edge(0, 3) +g.add_edge(3, 4) +print(g.dfs()) \ No newline at end of file From 5fe1373e4e20e8b08845b7dbae85b619ab66e04a Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 14 Apr 2021 18:42:51 +0530 Subject: [PATCH 224/302] Add check if graph is tree --- .../graphs/check_if_graph_is_tree.py | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 data_structures/graphs/check_if_graph_is_tree.py diff --git a/data_structures/graphs/check_if_graph_is_tree.py b/data_structures/graphs/check_if_graph_is_tree.py new file mode 100644 index 00000000..90ed3425 --- /dev/null +++ b/data_structures/graphs/check_if_graph_is_tree.py @@ -0,0 +1,59 @@ +""" +A graph is a tree if - +1. It does not contain cycles +2. The graph is connected + +Do DFS and see if every vertex can be visited from a source vertex and check for cycle +""" + +from collections import defaultdict + +class Graph: + + + def __init__(self, vertices): + self.vertices = vertices + self.graph = defaultdict(list) + + + def add_edge(self, u, v): + self.graph[u].append(v) + self.graph[v].append(u) + + + def is_tree(self, s): + visited = [False] * self.vertices + parent = [-1] * self.vertices + stack = [] + + visited[s] = True + no_of_visited = 1 + stack.append(s) + + while stack: + s = stack.pop() + + for i in self.graph[s]: + if visited[i] == False: + parent[i] = s + visited[i] = True + stack.append(i) + no_of_visited += 1 + elif parent[s] != i: + return "Not a tree" + + if no_of_visited == self.vertices: + return "Graph is Tree" + else: + return "Not a tree" + + +g = Graph(7) +g.add_edge(0, 1) +g.add_edge(0, 2) +g.add_edge(1, 3) +g.add_edge(2, 4) +g.add_edge(4, 5) +g.add_edge(1, 6) + +print(g.is_tree(0)) \ No newline at end of file From 469a9bff4af81789c05a5a5add569062fa171e09 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 15 Apr 2021 11:55:26 +0530 Subject: [PATCH 225/302] Add sink nodes --- data_structures/graphs/count_sink_nodes.py | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 data_structures/graphs/count_sink_nodes.py diff --git a/data_structures/graphs/count_sink_nodes.py b/data_structures/graphs/count_sink_nodes.py new file mode 100644 index 00000000..7cce157f --- /dev/null +++ b/data_structures/graphs/count_sink_nodes.py @@ -0,0 +1,31 @@ +""" +Count the number of sink nodes + +Sink nodes are the nodes without any outgoing edge + +Solution - +vertices contains the total number of edges and graph is an adjacency list. +Simply subtract the vertices and len(graph) +""" + +from collections import defaultdict + +class Graph: + + def __init__(self, vertices): + self.graph = defaultdict(list) + self.vertices = vertices + + + def add_edge(self, u, v): + self.graph[u].append(v) + + + def count_sink_nodes(self): + return self.vertices - len(self.graph) + + +g = Graph(3) +g.add_edge(0, 1) +g.add_edge(0, 2) +print(g.count_sink_nodes()) \ No newline at end of file From 941bb7992d8a2159760008058500b7babf729092 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 15 Apr 2021 11:55:35 +0530 Subject: [PATCH 226/302] Update readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index cdbc6a72..ec31aa8c 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # Python Data Structures and Algorithms -This repository contains questions requiring implementation of data structures and algorithms concepts. It is useful for interviews in Python. +No non-sense solutions to common Data Structure and Algorithm interview questions in Python. ## Objective -The open source community has helped me a lot during my interview preparations and studies while I was in my undergrad. I always wanted to give something back to the community. In my endeavour to contribute something back, I will be uploading data structures and algorithms questions in Python in this repo. Feel free to contribute and get in touch! :smiley: +The open source community has helped me a lot during my interview preparations and studies while I was in my undergrad. I always wanted to give something back to the community. In my endeavour to contribute something back, I will be uploading data structures and algorithms questions in Python in this repo. Feel free to contribute and get in touch! ## Structure of the repository @@ -58,8 +58,8 @@ As you can see, the repo is still in its infancy. Here are some key things in th ## Contributing -Contributions are always welcomed. :smiley: -Feel free to raise new issues, file new PRs. Consider giving it a star and fork this repo! :wink: +Contributions are always welcomed. +Feel free to raise new issues, file new PRs. Consider giving it a star and fork this repo! To follow the guidelines, refer to [Contributing.md](CONTRIBUTING.md) From a6c75eaac88b0b53ae74cd24ca600428b4cf5263 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 15 Apr 2021 17:19:04 +0530 Subject: [PATCH 227/302] Two cliques --- data_structures/graphs/two_cliques.py | 75 +++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 data_structures/graphs/two_cliques.py diff --git a/data_structures/graphs/two_cliques.py b/data_structures/graphs/two_cliques.py new file mode 100644 index 00000000..4eefba9c --- /dev/null +++ b/data_structures/graphs/two_cliques.py @@ -0,0 +1,75 @@ +""" +Find if a graph can be divided into two cliques + +A clique is a subgraph such that all vertices in it are completely +connected with each other + +Solution - +A bipartite graph is a graph which can be divided into two sets U and V such +that every edge from u or v has a destination in the other. +So take the complement of the graph (create edge where there is none, and destroy +edges where present) and if the complement is a bipartite, it means that there are edges +in U and V that connect each other. So complement's complement (i.e the original graph) will +not have these edges and hence it can be divided into two clique +""" + +from collections import defaultdict + +class Graph: + + + def __init__(self, vertices): + self.graph = defaultdict(list) + self.cgraph = defaultdict(list) + self.vertices = vertices + + + def add_edge(self, u, v): + self.graph[u].append(v) + self.graph[v].append(u) + + + def is_bipartite(self): + colors = [-1] * self.vertices + queue = [] + + for v in range(self.vertices): + if colors[v] == -1: + colors[v] = 1 + + queue.append(v) + + while queue: + s = queue.pop(0) + + for i in self.cgraph[s]: + if colors[i] == -1: + colors[i] = 1 - colors[s] + queue.append(i) + + elif colors[i] == colors[s]: + return False + + return True + + + def make_complement(self): + for src, dest in self.graph.items(): + for v in range(self.vertices): + if v not in dest and src != v: + self.cgraph[src].append(v) + self.cgraph[v].append(src) + + + def two_cliques(self): + self.make_complement() + return self.is_bipartite() + + +g = Graph(5) +g.add_edge(0, 3) +g.add_edge(3, 4) +g.add_edge(0, 1) +g.add_edge(1, 2) +g.add_edge(2, 0) +print(g.two_cliques()) \ No newline at end of file From 3e7c26038805dfca32a263b7ef2613fd0da72599 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Sun, 18 Apr 2021 14:33:28 +0530 Subject: [PATCH 228/302] Added kosaraju's algorithm --- data_structures/graphs/kosaraju_algorithm.py | 80 +++++++++++++------- 1 file changed, 52 insertions(+), 28 deletions(-) diff --git a/data_structures/graphs/kosaraju_algorithm.py b/data_structures/graphs/kosaraju_algorithm.py index cfc2a2b0..cd446c1a 100644 --- a/data_structures/graphs/kosaraju_algorithm.py +++ b/data_structures/graphs/kosaraju_algorithm.py @@ -1,7 +1,13 @@ -# Reference - https://www.geeksforgeeks.org/strongly-connected-components/ +""" +Reference - https://www.geeksforgeeks.org/strongly-connected-components/ -# This is used to find all the strongly connected components and does DFS -# 2 times. +Algorithm - https://youtu.be/RpgcYiky7uw + +This is used to find all the strongly connected components and does DFS +2 times. + +Note: A single vertex is also strongly connected +""" from collections import defaultdict @@ -9,7 +15,7 @@ class Graph: def __init__(self, vertices): - self.V = vertices + self.vertices = vertices self.graph = defaultdict(list) @@ -17,49 +23,67 @@ def add_edge(self, u, v): self.graph[u].append(v) - def dfs_util(self, v, visited): + def fill_time(self, v, visited, stack): visited[v] = True - print(v, end=' ') for i in self.graph[v]: if visited[i] == False: - self.dfs_util(i, visited) + self.fill_time(i, visited, stack) + stack = stack.append(v) - def fill_order(self, v, visited, stack): + + def dfs(self, v, visited): visited[v] = True + print(v, end=' ') + for i in self.graph[v]: if visited[i] == False: - self.fill_order(i, visited, stack) - stack.append(v) + self.dfs(i, visited) - - def get_transpose(self): - g = Graph(self.V) + + def create_tranpose(self): + tgraph = Graph(self.vertices) for i in self.graph: for j in self.graph[i]: - g.add_edge(j, i) - - return g + tgraph.add_edge(j, i) + return tgraph + def kosaraju(self): + visited = [False] * self.vertices stack = [] - visited = [False] * self.V - for i in range(self.V): - if visited[i] == False: - self.fill_order(i, visited, stack) + for v in range(self.vertices): + if visited[v] == False: + self.fill_time(v, visited, stack) - gr = self.get_transpose() + tgraph = self.create_tranpose() + visited = [False] * self.vertices - visited = [False] * self.V + print('stack - ', stack) while stack: - i = stack.pop() - if visited[i] == False: - gr.dfs_util(i, visited) - print() - - + s = stack.pop() + + if visited[s] == False: + tgraph.dfs(s, visited) + print() + + +g = Graph(11) +g.add_edge(0, 1) +g.add_edge(2, 0) +g.add_edge(1, 2) +g.add_edge(1, 3) +g.add_edge(3, 4) +g.add_edge(4, 5) +g.add_edge(5, 3) +g.add_edge(6, 5) +g.add_edge(6, 7) +g.add_edge(7, 8) +g.add_edge(8, 9) +g.add_edge(9, 10) +g.kosaraju() \ No newline at end of file From 8834704dbdf69e3ac322218e6df2ac1fa4008bac Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Sun, 18 Apr 2021 14:39:32 +0530 Subject: [PATCH 229/302] Add connected components undirected graph --- .../connected_components_undirected_graphs.py | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 data_structures/graphs/connected_components_undirected_graphs.py diff --git a/data_structures/graphs/connected_components_undirected_graphs.py b/data_structures/graphs/connected_components_undirected_graphs.py new file mode 100644 index 00000000..feb3dce4 --- /dev/null +++ b/data_structures/graphs/connected_components_undirected_graphs.py @@ -0,0 +1,46 @@ +from collections import defaultdict + + +class Graph: + + def __init__(self, vertices): + self.vertices = vertices + self.graph = defaultdict(list) + + + def add_edge(self, u, v): + self.graph[u].append(v) + self.graph[v].append(u) + + + def dfs(self, v, temp, visited): + visited[v] = True + temp.append(v) + + for i in self.graph[v]: + if visited[i] == False: + temp = self.dfs(i, temp, visited) + + return temp + + + def connected_components(self): + visited = [False] * self.vertices + cc = [] + + for i in range(self.vertices): + if visited[i] == False: + temp = [] + cc.append(self.dfs(i, temp, visited)) + + return cc + + +g = Graph(5) +g.add_edge(0, 1) +g.add_edge(1, 2) +g.add_edge(2, 0) +g.add_edge(0, 3) +g.add_edge(3, 4) + +print(g.connected_components()) \ No newline at end of file From 54cdebaf032197fb41396a841395f054a62c9f97 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 19 Apr 2021 17:23:23 +0530 Subject: [PATCH 230/302] Remove TODO from binary tree --- data_structures/binary_trees/TO_DO | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 data_structures/binary_trees/TO_DO diff --git a/data_structures/binary_trees/TO_DO b/data_structures/binary_trees/TO_DO deleted file mode 100644 index cb734cb7..00000000 --- a/data_structures/binary_trees/TO_DO +++ /dev/null @@ -1,2 +0,0 @@ -1. Max width of a binary tree -2. Total width of a binary tree From ec052e90f9a08da46935662ebac40fed91fef709 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 20 Apr 2021 14:09:51 +0530 Subject: [PATCH 231/302] Delete index --- data_structures/binary_trees/index.md | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 data_structures/binary_trees/index.md diff --git a/data_structures/binary_trees/index.md b/data_structures/binary_trees/index.md deleted file mode 100644 index 4f749eae..00000000 --- a/data_structures/binary_trees/index.md +++ /dev/null @@ -1,3 +0,0 @@ -# Index of binary_trees - -* [Symmetric Binary Tree](symmetric_binary_tree.py) From 505c3b41101d4149e9752c5a618a41f6cf703070 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 20 Apr 2021 16:07:39 +0530 Subject: [PATCH 232/302] boundary traversal --- .../binary_trees/boundary_traversal.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/data_structures/binary_trees/boundary_traversal.py b/data_structures/binary_trees/boundary_traversal.py index 760a6342..a4f08c00 100644 --- a/data_structures/binary_trees/boundary_traversal.py +++ b/data_structures/binary_trees/boundary_traversal.py @@ -15,8 +15,6 @@ def print_leaves(root): print_leaves(root.right) -# To ensure top down, print before calling for other -# To ensure bottom up, print after calling def print_left_boundary(root): if root: @@ -30,6 +28,11 @@ def print_left_boundary(root): def print_right_boundary(root): + """ + The traversal here will be from top to bottom because + this will be called after finishing the left side which is + top-to-bottom traversal + """ if root: if root.right: print_right_boundary(root.right) @@ -47,3 +50,14 @@ def print_boundary(root): print_leaves(root.left) print_leaves(root.right) print_right_boundary(root.right) + + +root = Node(20) +root.left = Node(8) +root.left.left = Node(4) +root.left.right = Node(12) +root.left.right.left = Node(10) +root.left.right.right = Node(14) +root.right = Node(22) +root.right.right = Node(25) +print_boundary(root) \ No newline at end of file From eaf5678fecdd14962bb0657c1c6d56323614abcd Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 21 Apr 2021 08:41:49 +0530 Subject: [PATCH 233/302] Add function call in check cousins --- data_structures/binary_trees/check_cousin.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/data_structures/binary_trees/check_cousin.py b/data_structures/binary_trees/check_cousin.py index 6453eed4..a65b95c8 100644 --- a/data_structures/binary_trees/check_cousin.py +++ b/data_structures/binary_trees/check_cousin.py @@ -34,3 +34,19 @@ def is_cousin(root, a, b): return True else: return False + + +root = Node(1) +root.left = Node(2) +root.right = Node(3) +root.left.left = Node(4) +root.left.right = Node(5) +root.left.right.right = Node(15) +root.right.left = Node(6) +root.right.right = Node(7) +root.right.left.right = Node(8) + +node1 = root.left.right +node2 = root.right.right + +print(is_cousin(root, node1, node2)) \ No newline at end of file From 6a0a08e919a77b7d7e50cbaa9a8df4c9b5434e2e Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 21 Apr 2021 09:49:23 +0530 Subject: [PATCH 234/302] Add implementation --- .../check_divide_in_two_halves.py | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/data_structures/binary_trees/check_divide_in_two_halves.py b/data_structures/binary_trees/check_divide_in_two_halves.py index df4f71b3..828138d2 100644 --- a/data_structures/binary_trees/check_divide_in_two_halves.py +++ b/data_structures/binary_trees/check_divide_in_two_halves.py @@ -1,8 +1,10 @@ -# Check if removing an edge of a binary tree can divide -# the tree in two equal halves +""" +Check if removing an edge of a binary tree can divide +the tree in two equal halves -# Count the number of nodes, say n. Then traverse the tree -# in bottom up manner and check if n - s = s +Solution - Count the number of nodes, say n. Then traverse the tree +in bottom up manner and find the size of every subtree (s). Check if n - s = s +""" class Node: @@ -31,5 +33,15 @@ def check_util(root, n): def check(root): - n = count(rot) + n = count(root) return check_util(root, n) + + +root = Node(5) +root.left = Node(1) +root.right = Node(6) +root.left.left = Node(3) +root.right.left = Node(7) +root.right.right = Node(4) + +print(check(root)) \ No newline at end of file From adddf51b3a076a3ebbecb5dd988406356a5196cb Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 22 Apr 2021 17:13:44 +0530 Subject: [PATCH 235/302] Add question --- data_structures/binary_trees/boundary_traversal.py | 8 +++++++- data_structures/binary_trees/check_if_graph_is_tree.py | 1 - 2 files changed, 7 insertions(+), 2 deletions(-) delete mode 100644 data_structures/binary_trees/check_if_graph_is_tree.py diff --git a/data_structures/binary_trees/boundary_traversal.py b/data_structures/binary_trees/boundary_traversal.py index a4f08c00..706970f1 100644 --- a/data_structures/binary_trees/boundary_traversal.py +++ b/data_structures/binary_trees/boundary_traversal.py @@ -1,3 +1,9 @@ +""" +Print the boundary traversal of a binary tree + +Boundary traversal - root, left (top-down), bottom, right (bottom-up) +""" + class Node: def __init__(self, val): @@ -21,7 +27,7 @@ def print_left_boundary(root): if root.left: print(root.val, end=' ') print_left_boundary(root.left) - + elif root.right: print(root.val, end=' ') print_left_boundary(root.right) diff --git a/data_structures/binary_trees/check_if_graph_is_tree.py b/data_structures/binary_trees/check_if_graph_is_tree.py deleted file mode 100644 index 8b137891..00000000 --- a/data_structures/binary_trees/check_if_graph_is_tree.py +++ /dev/null @@ -1 +0,0 @@ - From d59296d4ec3ce63969cfea2148ea2e3243d2fd29 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 22 Apr 2021 18:44:37 +0530 Subject: [PATCH 236/302] Modifications --- data_structures/binary_trees/check_cousin.py | 25 +++++++++++++------ .../binary_trees/check_full_binary_tree.py | 19 ++++++++++---- .../binary_trees/check_if_path_exists.py | 7 +++--- data_structures/binary_trees/traversals.py | 15 +++++++++++ 4 files changed, 50 insertions(+), 16 deletions(-) create mode 100644 data_structures/binary_trees/traversals.py diff --git a/data_structures/binary_trees/check_cousin.py b/data_structures/binary_trees/check_cousin.py index a65b95c8..c1f83d16 100644 --- a/data_structures/binary_trees/check_cousin.py +++ b/data_structures/binary_trees/check_cousin.py @@ -1,4 +1,11 @@ -# Check if two nodes are cousin or not +""" +Check if two nodes are cousin or not + +Condition for being cousin - +1. Level is same +2. They are not siblings + +""" class Node: @@ -11,22 +18,26 @@ def __init__(self, val): def level(root, node, lev): if not root: return 0 + if root == node: return lev - l = level(root.left, node, lev + 1) - + l = level(root.left, node, lev+1) + if not l == 0: return l - l = level(root.right, node, lev + 1) + l = level(root.right, node, lev+1) def is_sibling(root, a, b): - if root is None: - return 0 + if not root: + return False - return ( (root.left == a and root.right == b) or (root.left == b and root.right == a) or is_sibling(root.left, a, b) or is_sibling(root.right, a, b) ) + return (root.left == a and root.right == b) or \ + (root.right == b and root.left == a) or \ + is_sibling(root.left, a, b) or \ + is_sibling(root.right, a, b) def is_cousin(root, a, b): diff --git a/data_structures/binary_trees/check_full_binary_tree.py b/data_structures/binary_trees/check_full_binary_tree.py index 23c03f16..2498a4e6 100644 --- a/data_structures/binary_trees/check_full_binary_tree.py +++ b/data_structures/binary_trees/check_full_binary_tree.py @@ -1,4 +1,6 @@ -# A full binary tree is one which has 0 or 2 children only +""" +A full binary tree is a tree which has either 0 children or 2 children +""" class Node: @@ -9,14 +11,21 @@ def __init__(self, val): def check(root): - if root is None: + if not root: return True - if root.left is None and root.right is None: + if not root.left and not root.right: return True - if root.left is not None and root.right is not None: + if root.left and root.right: return check(root.left) and check(root.right) - return False +root = Node(0) +root.left = Node(1) +root.right = Node(2) + +if check(root): + print('True') +else: + print("False") \ No newline at end of file diff --git a/data_structures/binary_trees/check_if_path_exists.py b/data_structures/binary_trees/check_if_path_exists.py index be05f876..c6e33e5b 100644 --- a/data_structures/binary_trees/check_if_path_exists.py +++ b/data_structures/binary_trees/check_if_path_exists.py @@ -1,8 +1,7 @@ -# Check if a given path exists in a tree - -# Traverse the tree in preorder fashion and keep matching the node -# value to the index of the given path +""" +Given a path in an array form, check if this path leads to a leaf node +""" class Node: def __init__(self, val): diff --git a/data_structures/binary_trees/traversals.py b/data_structures/binary_trees/traversals.py new file mode 100644 index 00000000..5c26eb39 --- /dev/null +++ b/data_structures/binary_trees/traversals.py @@ -0,0 +1,15 @@ +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +class Tree: + + def __init__(self, root): + self.root = root + + + def inorder() From 015e49899c890710191ed61188fc4460203e190d Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 26 Apr 2021 10:52:47 +0530 Subject: [PATCH 237/302] Add height of tree --- .../binary_trees/height_of_tree.py | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 data_structures/binary_trees/height_of_tree.py diff --git a/data_structures/binary_trees/height_of_tree.py b/data_structures/binary_trees/height_of_tree.py new file mode 100644 index 00000000..cd082f1f --- /dev/null +++ b/data_structures/binary_trees/height_of_tree.py @@ -0,0 +1,35 @@ +""" +Find the height of a binary tree + +Height - (max of left height and right height) + 1 +""" + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def height(root): + if not root: + return 0 + + else: + lheight = height(root.left) + rheight = height(root.right) + + return 1 + max(lheight, rheight) + + +root = Node(1) +root.left = Node(2) +root.right = Node(3) +root.left.left = Node(7) +root.left.right = Node(6) +root.right.left = Node(5) +root.right.right = Node(4) +root.right.right.right = Node(40) + +print(height(root)) \ No newline at end of file From 397a53a5c0ddc84815007366b2cc3e8b96ad9aa1 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 26 Apr 2021 11:13:49 +0530 Subject: [PATCH 238/302] Add comments --- data_structures/binary_trees/diameter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data_structures/binary_trees/diameter.py b/data_structures/binary_trees/diameter.py index da1726b7..7c84ccd6 100644 --- a/data_structures/binary_trees/diameter.py +++ b/data_structures/binary_trees/diameter.py @@ -16,9 +16,9 @@ def height(root, ans): lheight = height(root.left, ans) rheight = height(root.right, ans) - ans[0] = max(ans[0], 1 + lheight + rheight) + ans[0] = max(ans[0], 1 + lheight + rheight) # This is for diameter - return 1 + max(lheight, rheight) + return 1 + max(lheight, rheight) # This is for height def diameter(root): From 253002b86bb2dfde0ab34be2158afb76a2b22162 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 26 Apr 2021 11:14:23 +0530 Subject: [PATCH 239/302] Add comments --- data_structures/binary_trees/longest_path_with_same_value.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/data_structures/binary_trees/longest_path_with_same_value.py b/data_structures/binary_trees/longest_path_with_same_value.py index 288bbf95..6c285fd7 100644 --- a/data_structures/binary_trees/longest_path_with_same_value.py +++ b/data_structures/binary_trees/longest_path_with_same_value.py @@ -1,3 +1,7 @@ +""" +Find the longest path in the tree with the same value +""" + class Node: def __init__(self, val): From 213e225e0235004ea8c41a8813b193ad2c5bf15b Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 26 Apr 2021 12:00:03 +0530 Subject: [PATCH 240/302] Add new questions --- .../binary_trees/print_path_to_a_node.py | 10 ++-- ...ree.py => print_spiral_tree_two_stacks.py} | 0 data_structures/binary_trees/spiral_tree.py | 56 +++++++++++++++++++ 3 files changed, 60 insertions(+), 6 deletions(-) rename data_structures/binary_trees/{print_spiral_tree.py => print_spiral_tree_two_stacks.py} (100%) create mode 100644 data_structures/binary_trees/spiral_tree.py diff --git a/data_structures/binary_trees/print_path_to_a_node.py b/data_structures/binary_trees/print_path_to_a_node.py index 3e1ece97..7202dbc6 100644 --- a/data_structures/binary_trees/print_path_to_a_node.py +++ b/data_structures/binary_trees/print_path_to_a_node.py @@ -6,21 +6,19 @@ def __init__(self, val): self.right = None -def has_path(root, arr, x): +def has_path(root, stack, x): if not root: return False - arr.append(root.val) + stack.append(root.val) if root.val == x: return True - if has_path(root.left, arr, x) or has_path(root.right, arr, x): + if has_path(root.left, stack, x) or has_path(root.right, stack, x): return True - # If the required node is not in the left or right subtree, remove - # the parent node from where the fork starts - arr.pop() + stack.pop() return False diff --git a/data_structures/binary_trees/print_spiral_tree.py b/data_structures/binary_trees/print_spiral_tree_two_stacks.py similarity index 100% rename from data_structures/binary_trees/print_spiral_tree.py rename to data_structures/binary_trees/print_spiral_tree_two_stacks.py diff --git a/data_structures/binary_trees/spiral_tree.py b/data_structures/binary_trees/spiral_tree.py new file mode 100644 index 00000000..e8505384 --- /dev/null +++ b/data_structures/binary_trees/spiral_tree.py @@ -0,0 +1,56 @@ +""" +Do level order traversal of a tree in spiral form +""" + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def height(root): + if not root: + return 0 + + lheight = height(root.left) + rheight = height(root.right) + + return 1 + max(lheight, rheight) + + +def print_spiral(root): + h = height(root) + + left_to_right = False + + for i in range(1, h+1): + print_level(root, i, left_to_right) + left_to_right = not left_to_right + + +def print_level(root, level, left_to_right): + if not root: + return + + if level == 1: + print(root.val, end=' ') + elif level > 1: + if left_to_right: + print_level(root.left, level-1, left_to_right) + print_level(root.right, level-1, left_to_right) + else: + print_level(root.right, level-1, left_to_right) + print_level(root.left, level-1, left_to_right) + + +root = Node(1) +root.left = Node(2) +root.right = Node(3) +root.left.left = Node(7) +root.left.right = Node(6) +root.right.left = Node(5) +root.right.right = Node(4) + +print_spiral(root) \ No newline at end of file From 8764dc8f5c3ded1b5f3eef583268b474ab529bfd Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 26 Apr 2021 12:39:00 +0530 Subject: [PATCH 241/302] Add perfect tree --- data_structures/binary_trees/perfect_tree.py | 47 ++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 data_structures/binary_trees/perfect_tree.py diff --git a/data_structures/binary_trees/perfect_tree.py b/data_structures/binary_trees/perfect_tree.py new file mode 100644 index 00000000..68c1dfe0 --- /dev/null +++ b/data_structures/binary_trees/perfect_tree.py @@ -0,0 +1,47 @@ +""" +Check if a given binary tree is perfect or not +""" + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def find_depth(node): + d = 0 + while node: + d += 1 + node = node.left + return d + + +def is_perfect_util(root, d, level=0): + if not root: + return True + + if not root.left and not root.right: + return d == level + 1 + + if not root.left or not root.right: + return False + + return is_perfect_util(root.left, d, level+1) and is_perfect_util(root.right, d, level+1) + + +def is_perfect(root): + depth = find_depth(root) + return is_perfect_util(root, depth) + + +root = Node(10) +root.left = Node(20) +root.right = Node(30) +root.left.left = Node(40) +root.left.right = Node(50) +root.right.left = Node(60) +root.right.right = Node(70) + +print(is_perfect(root)) \ No newline at end of file From 547a2a06d21ce26871f4a2003a4f0beb087a8d77 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 27 Apr 2021 13:00:28 +0530 Subject: [PATCH 242/302] Add views --- data_structures/binary_trees/left_view.py | 38 +++++++ data_structures/binary_trees/right_view.py | 42 ++++++++ data_structures/binary_trees/top_view.py | 52 +++++++++ .../binary_trees/vertical_traversal.py | 102 ++++++++++++++++++ 4 files changed, 234 insertions(+) create mode 100644 data_structures/binary_trees/left_view.py create mode 100644 data_structures/binary_trees/right_view.py create mode 100644 data_structures/binary_trees/top_view.py create mode 100644 data_structures/binary_trees/vertical_traversal.py diff --git a/data_structures/binary_trees/left_view.py b/data_structures/binary_trees/left_view.py new file mode 100644 index 00000000..63cdbf9d --- /dev/null +++ b/data_structures/binary_trees/left_view.py @@ -0,0 +1,38 @@ +""" +Print left view of a binary tree +""" + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def left_view_util(root, max_level, level): + if not root: + return + + if max_level[0] < level: + print(root.val) + max_level[0] = level + + left_view_util(root.left, max_level, level+1) + left_view_util(root.right, max_level, level+1) + + +def left_view(root): + max_level = [0] + left_view_util(root, max_level, 1) + + +root = Node(1) +root.left = Node(2) +root.right = Node(3) +root.left.left = Node(4) +root.left.left.left = Node(5) +root.left.left.left.left = Node(6) +root.right.right = Node(7) +root.right.right.right = Node(8) +left_view(root) \ No newline at end of file diff --git a/data_structures/binary_trees/right_view.py b/data_structures/binary_trees/right_view.py new file mode 100644 index 00000000..cc6aa796 --- /dev/null +++ b/data_structures/binary_trees/right_view.py @@ -0,0 +1,42 @@ +""" +Print right view of a binary tree + +The idea behind using max_level[0] is that - +1. Its value when changes will be reflected in every recursion call +2. We are visiting right side first. So this acts as a check that that level was done +""" + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def right_view_util(root, max_level, level): + if not root: + return + + if max_level[0] < level: + print(root.val) + max_level[0] = level + + right_view_util(root.right, max_level, level+1) + right_view_util(root.left, max_level, level+1) + + +def right_view(root): + max_level = [0] + right_view_util(root, max_level, 1) + + +root = Node(1) +root.left = Node(2) +root.right = Node(3) +root.left.left = Node(4) +root.left.right = Node(5) +root.right.left = Node(6) +root.right.right = Node(7) +root.right.left.right = Node(8) +right_view(root) \ No newline at end of file diff --git a/data_structures/binary_trees/top_view.py b/data_structures/binary_trees/top_view.py new file mode 100644 index 00000000..565e9e00 --- /dev/null +++ b/data_structures/binary_trees/top_view.py @@ -0,0 +1,52 @@ +""" +Print the top view of a binary tree + +Almost like vertical traversal +""" + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + self.col = None + + +def top_view(root): + if not root: + return + + queue = [] + col = 0 + d = {} + + queue.append(root) + root.col = col + + while queue: + root = queue.pop(0) + col = root.col + + if col not in d: + d[col] = root.val + + if root.left: + queue.append(root.left) + root.left.col = col - 1 + if root.right: + queue.append(root.right) + root.right.col = col + 1 + + for i in sorted(d): + print(d[i], end=" ") + + +root = Node(1) +root.left = Node(2) +root.right = Node(3) +root.left.right = Node(4) +root.left.right.right = Node(5) +root.left.right.right.right = Node(6) + +top_view(root) \ No newline at end of file diff --git a/data_structures/binary_trees/vertical_traversal.py b/data_structures/binary_trees/vertical_traversal.py new file mode 100644 index 00000000..344a546f --- /dev/null +++ b/data_structures/binary_trees/vertical_traversal.py @@ -0,0 +1,102 @@ +""" +Print vertical view of a binary tree + + 1 + / \ + 2 3 + / \ / \ + 4 5 6 7 + / \ + 8 9 + + +The output of print this tree vertically will be: +4 +2 +1 5 6 +3 8 +7 +9 + +source - https://www.geeksforgeeks.org/print-binary-tree-vertical-order-set-2/ +""" + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + self.col = None + + +def print_vertical_util(root, col, d): + if not root: + return + + if col in d: + d[col].append(root.val) + else: + d[col] = [root.val] + + print_vertical_util(root.left, col-1, d) + print_vertical_util(root.right, col+1, d) + + +def print_vertical(root): + d = {} + col = 0 + + print_vertical_util(root, col, d) + + for k, v in sorted(d.items()): + for i in v: + print(i, end=' ') + print() + + +def print_vertical_iterative(root): + queue = [] + col = 0 + d = {} + + queue.append(root) + root.col = col + + while queue: + root = queue.pop(0) + col = root.col + + if col not in d: + d[col] = [root.val] + else: + d[col].append(root.val) + + if root.left: + queue.append(root.left) + root.left.col = col - 1 + if root.right: + queue.append(root.right) + root.right.col = col + 1 + + for k, v in sorted(d.items()): + for i in v: + print(i, end=' ') + print() + + + +root = Node(1) +root.left = Node(2) +root.right = Node(3) +root.left.left = Node(4) +root.left.right = Node(5) +root.right.left = Node(6) +root.right.right = Node(7) +root.right.left.right = Node(8) +root.right.right.right = Node(9) + +print_vertical(root) + +print("Iterative solution - ") +print_vertical_iterative(root) \ No newline at end of file From b6d135f510e2cc772cdf34f8d8564744bb93aca7 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 28 Apr 2021 13:30:09 +0530 Subject: [PATCH 243/302] add comments --- data_structures/bst/second_largest_in_bst.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/data_structures/bst/second_largest_in_bst.py b/data_structures/bst/second_largest_in_bst.py index 598b36bb..334a3dd6 100644 --- a/data_structures/bst/second_largest_in_bst.py +++ b/data_structures/bst/second_largest_in_bst.py @@ -1,3 +1,14 @@ +""" +There can be two condition for finding the second largest element in a BST + +1. If right subtree does not exist, find the largest on the left side +Otherwise, +2. If right exists but right's left and right's right do not, that means +you are currently at the second largest element + +Move to right +""" + class Node: def __init__(self, val): From 0bfea10c8a919be75eca512345b2a89985cb486d Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 28 Apr 2021 20:14:38 +0530 Subject: [PATCH 244/302] Remove index --- data_structures/bst/index.md | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 data_structures/bst/index.md diff --git a/data_structures/bst/index.md b/data_structures/bst/index.md deleted file mode 100644 index 97a6320f..00000000 --- a/data_structures/bst/index.md +++ /dev/null @@ -1,31 +0,0 @@ -# Index of BST - -* [Deletion](deletion.py) -* [Sorted Array To BST](sorted_array_to_bst.py) -* [Print Left Node](print_left_node.py) -* [Diameter](diameter.py) -* [BFS](bfs.py) -* [Check if BT is BST](check_if_bt_if_bst.py) -* [Trim BST](trim_bst.py) -* [BT to BST](bt_to_bst.py) -* [Binary Search Tree](binary_search_tree.py) -* [Convert BST to Right Node Tree](convert_bst_to_right_node_tree.py) -* [kth largest in BST](kth_largest_in_bst.py) -* [Range Sum](range_sum.py) -* [DFS Iterative](dfs_iterative.py) -* [Print Ancestor](print_ancestor.py) -* [Min Max Value in BST](min_max_value_in_bst.py) -* [Check BT is Subtree of another BT](check_bt_is_subtree_of_another_bt.py) -* [Ceil](ceil.py) -* [Closest Element](closest_element.py) -* [kth smallest in BST](kth_smallest_in_bst.py) -* [Insertion Iterative](insertion_iterative.py) -* [Lowest Common Ancestor](lowest_common_ancestor.py) -* [DFS Recursion](dfs_recursion.py) -* [Search](search.py) -* [Insertion Recursive](insertion_recursive.py) -* [Duplicate Keys](duplicate_keys.py) -* [Merge Sum](merge_sum.py) -* [Linked List to BST](linked_list_to_bst.py) -* [Reverse Inorder Traversal](reverse_inorder_traversal.py) -* [Average of Levels](average_of_levels.py) From bf82d5cb426318a075654910fba9d81c18a570f4 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 29 Apr 2021 18:21:28 +0530 Subject: [PATCH 245/302] Add comments --- data_structures/bst/duplicate_keys.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/data_structures/bst/duplicate_keys.py b/data_structures/bst/duplicate_keys.py index 4e0e5cbf..ba8b6123 100644 --- a/data_structures/bst/duplicate_keys.py +++ b/data_structures/bst/duplicate_keys.py @@ -1,3 +1,11 @@ +""" +Create a BST such that it can have duplicate nodes. +Technically BST cannot have duplicate nodes. The work around is to +have a counter associated with every node. Increment its count whenever +there is a duplicate. If the count goes to zero, delete that node +""" + + class Node(): def __init__(self, val): From 09edf53c5f4676eb66c448b27f885e0600456350 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 29 Apr 2021 18:34:26 +0530 Subject: [PATCH 246/302] Complete duplicate keys by adding deletion --- data_structures/bst/duplicate_keys.py | 37 +++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/data_structures/bst/duplicate_keys.py b/data_structures/bst/duplicate_keys.py index ba8b6123..a09dc2c1 100644 --- a/data_structures/bst/duplicate_keys.py +++ b/data_structures/bst/duplicate_keys.py @@ -45,12 +45,41 @@ def insert(root, val): return root +def min_value_node(root): + curr = root + while curr: + curr = curr.left + return curr.val + + def delete(root, val): if not root: - return - if root.val == val: + return None + + if val < root.val: + root.left = delete(root.left, val) + elif val > root.val: + root.right = delete(root.right, val) + else: if root.count > 1: root.count -= 1 + else: + # check if left node is None + if not root.left: + temp = root.right + root = None + return temp + # chec if right node is None + if not root.right: + temp = root.left + root = None + return temp + + temp = min_value_node(root.right) + root.val = temp.val + root.right = delete(root.right, temp.val) + + return root root = Node(5) @@ -61,3 +90,7 @@ def delete(root, val): insert(root, 10) inorder(root) + +print("After deletion") +root = delete(root, 8) +inorder(root) \ No newline at end of file From 2fc7e45577c53d103e90e1fb5de631126e157445 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Fri, 30 Apr 2021 12:26:58 +0530 Subject: [PATCH 247/302] Add comments --- data_structures/bst/kth_largest_in_bst.py | 8 ++++++++ data_structures/bst/kth_smallest_in_bst.py | 8 ++++++++ data_structures/bst/print_ancestor.py | 3 --- data_structures/bst/trim_bst.py | 6 +++++- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/data_structures/bst/kth_largest_in_bst.py b/data_structures/bst/kth_largest_in_bst.py index 1a013baf..e96eb84c 100644 --- a/data_structures/bst/kth_largest_in_bst.py +++ b/data_structures/bst/kth_largest_in_bst.py @@ -1,3 +1,11 @@ +""" +Print the kth largest element in a BST + +The inorder traversal gives elements of BST in ascending order. Do reverse inorder +(Right-Node-Left) and print the kth element +""" + + class Node(): def __init__(self, val): diff --git a/data_structures/bst/kth_smallest_in_bst.py b/data_structures/bst/kth_smallest_in_bst.py index aefa1345..26131ee1 100644 --- a/data_structures/bst/kth_smallest_in_bst.py +++ b/data_structures/bst/kth_smallest_in_bst.py @@ -1,3 +1,11 @@ +""" +Print the kth smallest number in BST + +The inorder traversal of BST gives elements in ascending order. So do inorder, +keep count and return the kth value +""" + + class Node(): def __init__(self, val): diff --git a/data_structures/bst/print_ancestor.py b/data_structures/bst/print_ancestor.py index b443c559..b065efa0 100644 --- a/data_structures/bst/print_ancestor.py +++ b/data_structures/bst/print_ancestor.py @@ -14,6 +14,3 @@ def print_ancestor_recursive(root, key): if print_ancestor_recursive(root.left, key) or print_ancestor_recursive(root.right, key): return root.data return False - - - diff --git a/data_structures/bst/trim_bst.py b/data_structures/bst/trim_bst.py index 31a17422..1ba86545 100644 --- a/data_structures/bst/trim_bst.py +++ b/data_structures/bst/trim_bst.py @@ -1,3 +1,7 @@ +""" +Trim a BST so that all elements lie within a given high and low range +""" + class Node(): def __init__(self, val): @@ -12,7 +16,7 @@ def trim(root, L, R): if root.val > R: return trim(root.left, L, R) if root.val < L: - return trim(root. right, L, R) + return trim(root.right, L, R) root.left = trim(root.left, L, R) root.right = trim(root.right, L, R) return root From f454f57eeee84b7efefa973f35fb7a24d9cf6be5 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 6 May 2021 09:43:56 +0530 Subject: [PATCH 248/302] Add comments --- data_structures/graphs/print_all_paths_between_nodes.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data_structures/graphs/print_all_paths_between_nodes.py b/data_structures/graphs/print_all_paths_between_nodes.py index cbd04abf..0b370237 100644 --- a/data_structures/graphs/print_all_paths_between_nodes.py +++ b/data_structures/graphs/print_all_paths_between_nodes.py @@ -24,6 +24,8 @@ def print_path(self, s, d, visited, path): if visited[i] == False: self.print_path(i, d, visited, path) + # If path from this node does not lead to the destination, remove it + # from the path stack and mark it as not visited path.pop() visited[s] = False From 25e8966ea638866c13ca937c3e858fd28d067aab Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 6 May 2021 16:59:56 +0530 Subject: [PATCH 249/302] Add min degree --- .../graphs/min_nodes_to_reach_all_nodes.py | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 data_structures/graphs/min_nodes_to_reach_all_nodes.py diff --git a/data_structures/graphs/min_nodes_to_reach_all_nodes.py b/data_structures/graphs/min_nodes_to_reach_all_nodes.py new file mode 100644 index 00000000..d60f6f9b --- /dev/null +++ b/data_structures/graphs/min_nodes_to_reach_all_nodes.py @@ -0,0 +1,11 @@ +""" +We are given a DAG. Find the smallest set of vertices from which all +nodes in the graph are reachable. It's guaranteed that a unique solution exists. + +Solution - +The crux of the question is that - +1. If any node has an indegree > 1 (i.e it is reachable from any other node), then it means +in a connected graph it will be possible to reach here if its parent node also has an indegree +2. So the min will be the set of nodes with indegree = 0 +""" + From fafcfab9a6b528834fbfb74f7f3e4e4fa5cb0662 Mon Sep 17 00:00:00 2001 From: RK Date: Mon, 10 May 2021 10:36:45 +0530 Subject: [PATCH 250/302] fixed bug in line 20 and simplified code for creating graph --- data_structures/graphs/Adjacency_matrix.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/data_structures/graphs/Adjacency_matrix.py b/data_structures/graphs/Adjacency_matrix.py index 7895a279..f173bc37 100644 --- a/data_structures/graphs/Adjacency_matrix.py +++ b/data_structures/graphs/Adjacency_matrix.py @@ -4,10 +4,7 @@ def __init__(self, vertices, directed: bool): self.V = vertices self.e = 0 self.d = directed - self.graph = [] - for i in range(self.V): - lst = [0] * self.V - self.graph.append(lst) + self.graph = [[0 for i in range(vertices)] for j in range(vertices)] def add_edge(self, ver1, ver2): if self.d: @@ -17,7 +14,7 @@ def add_edge(self, ver1, ver2): self.graph[ver2][ver1] = 1 def remove_edge(self, ver1, ver2): - if self.d[ver1][ver2] == 0: + if self.graph[ver1][ver2] == 0: print("No edge between %d and %d" % (ver1, ver2)) return if self.d: @@ -30,6 +27,11 @@ def print_graph(self): for i in self.graph: print(i) - - +if __name__=="__main__": + g1 = Graph(3,0) + g1.add_edge(0,0) + g1.add_edge(1,1) + g1.add_edge(2,2) + g1.remove_edge(2,1) + g1.print_graph() From eb8ea1471c3f9473776ec6ba9bf95a52f3a36864 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 10 May 2021 18:02:12 +0530 Subject: [PATCH 251/302] New changes --- README.md | 4 ++++ data_structures/graphs/dijsktra_algorithm.py | 0 2 files changed, 4 insertions(+) create mode 100644 data_structures/graphs/dijsktra_algorithm.py diff --git a/README.md b/README.md index ec31aa8c..b5a68823 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,10 @@ No non-sense solutions to common Data Structure and Algorithm interview question ## Objective +There are a plenty of resources when it comes to interview preparations on the internet. What prompted me to create this project was the dissimilarity across different approaches and the infused complexity of the code. + +Feel free to contribute but please follow the Contributing Guidelines as I want to maintain the uniformity of the implementation of data structures and algorithms. Last time around, people bombarded with me with Pull Requests, Issues and Emails insisting me to merge their changes + The open source community has helped me a lot during my interview preparations and studies while I was in my undergrad. I always wanted to give something back to the community. In my endeavour to contribute something back, I will be uploading data structures and algorithms questions in Python in this repo. Feel free to contribute and get in touch! ## Structure of the repository diff --git a/data_structures/graphs/dijsktra_algorithm.py b/data_structures/graphs/dijsktra_algorithm.py new file mode 100644 index 00000000..e69de29b From cbe2097711a3fc34aad779a263d8ab8c26b33a53 Mon Sep 17 00:00:00 2001 From: Rohan Krishna Ullas <71774184+Kakarot-2000@users.noreply.github.com> Date: Tue, 18 May 2021 15:39:41 +0530 Subject: [PATCH 252/302] Updated balanced_expression.py to fix bugs --- data_structures/stack/balanced_expression.py | 26 ++++++++++++-------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/data_structures/stack/balanced_expression.py b/data_structures/stack/balanced_expression.py index 784666c0..60e3c506 100644 --- a/data_structures/stack/balanced_expression.py +++ b/data_structures/stack/balanced_expression.py @@ -1,24 +1,30 @@ -# simple program to check if an expression is balanced using stack stack = [] def checkBalanced(expr): for i in expr: if i == "{" or i == "[" or i == "(": stack.append(i) elif i == "}" or i == "]" or i == ")": - temp = stack.pop() - if i == "}" and temp != "{": + if not stack: return False - elif i == "]" and temp != "[": + top = stack.pop() + if i == "}" and top != "{": return False - elif i == ")" and temp != "(": + elif i == "]" and top != "[": return False + elif i == ")" and top != "(": + return False + else: + print("Invalid Expression") + return False - return True + if not len(stack): + return True + else: + return False # main function expr = input() -result = checkBalanced(expr) -if result: - print("Expression is balanced") +if not checkBalanced(expr): + print("Not Balanced") else: - print("Expression is not balanced") + print('Balanced') From a8954614d2128f40a50fb9e932be37a671b68d4e Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 2 Jun 2021 09:34:14 +0530 Subject: [PATCH 253/302] Add array to bt --- .../binary_trees/array_to_binary_tree.py | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 data_structures/binary_trees/array_to_binary_tree.py diff --git a/data_structures/binary_trees/array_to_binary_tree.py b/data_structures/binary_trees/array_to_binary_tree.py new file mode 100644 index 00000000..9057b163 --- /dev/null +++ b/data_structures/binary_trees/array_to_binary_tree.py @@ -0,0 +1,37 @@ +""" +Convert an array to a binary tree + +Sample input - +[1,2,3,4,5,null,6,7,null,null,null,null,8] + +Note - +if a tree has N nodes and is complete, then the no of internal +nodes can be (N-1) / 2 +""" + +class Node: + + def __init__(self, val): + self.val = val + self.left = None + self.right = None + + +def create_tree(arr): + curr_ptr = 0 + child_ptr = 0 + + root = Node(arr[0]) + curr_node = root + + while i < (len(arr) - 1)/2: + curr_ptr = arr[i] + child_ptr = i + 1 + + left_child = arr[child_ptr] + right_child = arr[child_ptr + 1] + + curr_node.left = Node(left_child) + curr_node.right = Node(right_child) + + From 9e8e9ca35ef876cf7543ef068f3dc9cca000a758 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Fri, 4 Jun 2021 18:52:03 +0530 Subject: [PATCH 254/302] Update first_repeating_char.py --- data_structures/array/first_repeating_char.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/array/first_repeating_char.py b/data_structures/array/first_repeating_char.py index 2ba272eb..89477411 100644 --- a/data_structures/array/first_repeating_char.py +++ b/data_structures/array/first_repeating_char.py @@ -1,4 +1,4 @@ -# Find the first character in a string without using extra space +# Find the first repeated character in a string without using extra space # With extra space its simple. Just check for the element in a hash map # If present, then it is the recurrent char From e522e65b070759ba0bb0f5672e6d3566dea77b63 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Fri, 4 Jun 2021 20:21:41 +0530 Subject: [PATCH 255/302] Update cycle_in_undirected_graph_iterative.py --- data_structures/graphs/cycle_in_undirected_graph_iterative.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data_structures/graphs/cycle_in_undirected_graph_iterative.py b/data_structures/graphs/cycle_in_undirected_graph_iterative.py index 53bca95d..565cedde 100644 --- a/data_structures/graphs/cycle_in_undirected_graph_iterative.py +++ b/data_structures/graphs/cycle_in_undirected_graph_iterative.py @@ -4,7 +4,7 @@ traverse but in undirected its possible that an edge (or a path) can be traversed infite number of times. -Instead check for parents (which means vertex fro which you reached the current vertex). +Instead check for parents (which means vertex from which you reached the current vertex). If a vertex is visited and you are not coming to this vertex from the current "source" vertex (source - vertex from which DFS has started), then it means that in the same DFS chain, there is another path to reach this vertex - hence a cycle @@ -57,4 +57,4 @@ def dfs(self): g.add_edge(2, 0) g.add_edge(0, 3) g.add_edge(3, 4) -print(g.dfs()) \ No newline at end of file +print(g.dfs()) From bca7a225fa8bb9f2fba312a4c27ac4e6b98eff65 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 7 Jun 2021 08:38:36 +0530 Subject: [PATCH 256/302] Update topics.md --- bookmarks/topics.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bookmarks/topics.md b/bookmarks/topics.md index bf8c7be2..d1d54010 100644 --- a/bookmarks/topics.md +++ b/bookmarks/topics.md @@ -14,4 +14,6 @@ This is a list of links to topics that may be helpful in learning or researching - https://stackoverflow.com/questions/40200413/sessions-vs-token-based-authentication -- https://stackoverflow.com/questions/15678406/when-to-use-myisam-and-innodb \ No newline at end of file +- https://stackoverflow.com/questions/15678406/when-to-use-myisam-and-innodb + +- https://www.bigocheatsheet.com/ From 40a29e79ce1b1fa78cb0a4b9995d4342bca642c4 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 7 Jun 2021 10:31:07 +0530 Subject: [PATCH 257/302] add heap --- data_structures/heap/max_heap.py | 152 +++++++++++++++++++++++++++++++ data_structures/heap/min_heap.py | 0 2 files changed, 152 insertions(+) create mode 100644 data_structures/heap/max_heap.py create mode 100644 data_structures/heap/min_heap.py diff --git a/data_structures/heap/max_heap.py b/data_structures/heap/max_heap.py new file mode 100644 index 00000000..3061e2d3 --- /dev/null +++ b/data_structures/heap/max_heap.py @@ -0,0 +1,152 @@ +""" +Thing to remember - +* index of parent = i / 2 +* index of left child = 2i + 1 +* index of right child = 2i + 2 +""" + +import sys + +class MaxHeap: + + def __init__(self, maxsize): + self.maxsize = maxsize + self.size = 0 # current number of elements in the heap + self.heap = [0] * self.maxsize + self.front = 0 + + + def parent(self, pos): + return pos // 2 + + + def left_child(self, pos): + return 2*pos + 1 + + + def right_child(self, pos): + return 2*pos + 2 + + + def mid_index(self): + return self.size // 2 + + + def last_index(self): + return self.size - 1 + + + def is_leaf(self, pos): + """ + Every node that is after the middle index of the heap + is a leaf node because their children cannot exist as the + index of children are twice their index as those indexes + do not exist in the heap + """ + if self.mid_index() <= pos <= self.last_index(): + return True + return False + + + def is_empty(self): + if self.size == 0 and not self.heap[0]: + return True + return False + + + def insert(self, value): + if self.is_empty(): # if the heap is empty + self.heap[self.front] = value + self.size += 1 + return + + if self.size >= self.maxsize: # if max size has been reached + return + + self.size += 1 + self.heap[self.last_index()] = value + + curr = self.last_index() + + # While inserting the element in the heap we have to + # make sure that the inserted element is always smaller + # than its parent. So basically here we are adjusting the + # position of the parent + while self.heap[curr] > self.heap[self.parent(curr)]: + self.swap(curr, self.parent(curr)) + curr = self.parent(curr) + + + def max_heapify(self, pos): + """ + This function will run whenever a node is non-leaf + node and smaller than its childen + """ + if not self.is_leaf(pos): + left = self.heap[self.left_child(pos)] + right = self.heap[self.right_child(pos)] + curr = self.heap[pos] + + if curr < left or curr < right: + + if left > right: + self.swap(pos, self.left_child(pos)) + self.max_heapify(self.left_child(pos)) + else: + self.swap(pos, self.right_child(pos)) + self.max_heapify(self.right_child(pos)) + + + def swap(self, x, y): + self.heap[x], self.heap[y] = self.heap[y], self.heap[x] + + + def pop_max(self): + max_element = self.heap[self.front] # max element is always at the front + self.heap[self.front] = self.heap[self.last_index()] # placing last element at the front + self.heap[self.last_index()] = 0 + self.size -= 1 # decrease size as one element has been popped + self.max_heapify(self.front) # heapify the heap again + return max_element + + + def print(self): + """ + Priting in inorder + """ + for i in range(0, self.mid_index() + 1): + parent = self.heap[i] + left = self.heap[self.left_child(i)] + right = self.heap[self.right_child(i)] + + print(f"Parent: {self.heap[i]}") + + if left: + print(f"Left child: {left}") + if right: + print(f"Right child: {right}") + + +if __name__ == '__main__': + max_heap = MaxHeap(15) + max_heap.insert(5) + max_heap.insert(3) + max_heap.insert(17) + max_heap.insert(10) + max_heap.insert(84) + max_heap.insert(19) + max_heap.insert(6) + max_heap.insert(22) + max_heap.insert(9) + + max_heap.print() + + print('Max element is - ', max_heap.pop_max()) + + + max_heap.print() + + print('Max element is - ', max_heap.pop_max()) + + + diff --git a/data_structures/heap/min_heap.py b/data_structures/heap/min_heap.py new file mode 100644 index 00000000..e69de29b From b76544e65806cb80ab6c3263651464d5a840e432 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 7 Jun 2021 17:42:26 +0530 Subject: [PATCH 258/302] Add code for min and max heap --- data_structures/heap/max_heap.py | 17 +---- data_structures/heap/min_heap.py | 122 +++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 13 deletions(-) diff --git a/data_structures/heap/max_heap.py b/data_structures/heap/max_heap.py index 3061e2d3..29fcef70 100644 --- a/data_structures/heap/max_heap.py +++ b/data_structures/heap/max_heap.py @@ -5,8 +5,6 @@ * index of right child = 2i + 2 """ -import sys - class MaxHeap: def __init__(self, maxsize): @@ -17,7 +15,7 @@ def __init__(self, maxsize): def parent(self, pos): - return pos // 2 + return (pos) // 2 def left_child(self, pos): @@ -49,7 +47,7 @@ def is_leaf(self, pos): def is_empty(self): - if self.size == 0 and not self.heap[0]: + if self.size == 0: return True return False @@ -88,7 +86,8 @@ def max_heapify(self, pos): curr = self.heap[pos] if curr < left or curr < right: - + + # This check is only to prevent out-of-index error if left > right: self.swap(pos, self.left_child(pos)) self.max_heapify(self.left_child(pos)) @@ -140,13 +139,5 @@ def print(self): max_heap.insert(9) max_heap.print() - print('Max element is - ', max_heap.pop_max()) - - max_heap.print() - - print('Max element is - ', max_heap.pop_max()) - - - diff --git a/data_structures/heap/min_heap.py b/data_structures/heap/min_heap.py index e69de29b..069524d4 100644 --- a/data_structures/heap/min_heap.py +++ b/data_structures/heap/min_heap.py @@ -0,0 +1,122 @@ +""" +See max_heap.py for more detailed comments +""" + +class MinHeap: + + + def __init__(self, maxsize): + self.maxsize = maxsize + self.size = 0 + self.first = 0 + self.heap = [0] * self.maxsize + + + def is_empty(self): + return self.size == 0 + + + def is_leaf(self, pos): + if self.mid_index() <= pos <= self.last_index(): + return True + return False + + + def parent(self, pos): + return pos // 2 + + + def left_child(self, pos): + return 2*pos + 1 + + + def right_child(self, pos): + return 2*pos + 2 + + + def last_index(self): + return self.size - 1 + + + def mid_index(self): + return self.size // 2 + + + def swap(self, x, y): + self.heap[x], self.heap[y] = self.heap[y], self.heap[x] + + + def pop_min(self): + min_element = self.heap[self.first] + self.heap[self.first] = self.heap[self.last_index()] + self.heap[self.last_index()] = 0 + self.size -= 1 + self.min_heapify(self.first) + return min_element + + + def min_heapify(self, pos): + if not self.is_leaf(pos): + left = self.heap[self.left_child(pos)] + right = self.heap[self.right_child(pos)] + curr = self.heap[pos] + + if curr > left or curr > right: + + if left > right: + self.swap(pos, self.left_child(pos)) + self.min_heapify(self.left_child(pos)) + else: + self.swap(pos, self.right_child(pos)) + self.min_heapify(self.right_child(pos)) + + + def insert(self, element): + if self.is_empty(): + self.heap[self.first] = element + self.size += 1 + return + + if self.size >= self.maxsize: + return + + self.size += 1 + self.heap[self.last_index()] = element + + curr = self.last_index() + + while self.heap[curr] < self.heap[self.parent(curr)]: + self.swap(curr, self.parent(curr)) + curr = self.parent(curr) + + + def print(self): + for i in range(0, self.mid_index() + 1): + parent = self.heap[i] + left = self.heap[self.left_child(i)] + right = self.heap[self.right_child(i)] + + print(f"Parent: {self.heap[i]}") + + if left: + print(f"Left child: {left}") + if right: + print(f"Right child: {right}") + + +if __name__ == '__main__': + min_heap = MinHeap(15) + min_heap.insert(5) + min_heap.insert(3) + min_heap.insert(17) + min_heap.insert(10) + min_heap.insert(84) + min_heap.insert(19) + min_heap.insert(6) + min_heap.insert(22) + min_heap.insert(9) + + min_heap.print() + print(min_heap.heap) + print('Min element is - ', min_heap.pop_min()) + min_heap.print() From 1dd751bc3e99148a82c9ca034f80985e6531a0ca Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 7 Jun 2021 17:47:21 +0530 Subject: [PATCH 259/302] add heap using library functions --- data_structures/heap/heap_using_heapq.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 data_structures/heap/heap_using_heapq.py diff --git a/data_structures/heap/heap_using_heapq.py b/data_structures/heap/heap_using_heapq.py new file mode 100644 index 00000000..0ee5410a --- /dev/null +++ b/data_structures/heap/heap_using_heapq.py @@ -0,0 +1,23 @@ +""" +Heap in python using heapq library function + +Note: by default, heapq creates a min-heap. To make it a +max-heap, add items after multiplying them by -1 +""" + +from heapq import heappop, heappush, heapify + +heap = [] +heapify(heap) + +heappush(heap, 10) +heappush(heap, 11) +heappush(heap, 2) +heappush(heap, 4) +heappush(heap, 14) +heappush(heap, 1) + +print('first element - ', heap[0]) +print('popping min element - ', heappop(heap)) +print('first element - ', heap[0]) + From 936d1734791ef509f4b807693e67f10c13e369d4 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 8 Jun 2021 06:33:10 +0530 Subject: [PATCH 260/302] Add array indexes --- data_structures/heap/heap_using_heapq.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/data_structures/heap/heap_using_heapq.py b/data_structures/heap/heap_using_heapq.py index 0ee5410a..7e28d109 100644 --- a/data_structures/heap/heap_using_heapq.py +++ b/data_structures/heap/heap_using_heapq.py @@ -21,3 +21,6 @@ print('popping min element - ', heappop(heap)) print('first element - ', heap[0]) +# Heap prints as an array and can be access using indexes +print(heap) +print(heap[2]) From 440cec21054a5a5e77c265882fd32fdfecaa12b4 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 8 Jun 2021 06:33:28 +0530 Subject: [PATCH 261/302] Add median of infinite stream --- .../heap/median_of_infinite_stream.py | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 data_structures/heap/median_of_infinite_stream.py diff --git a/data_structures/heap/median_of_infinite_stream.py b/data_structures/heap/median_of_infinite_stream.py new file mode 100644 index 00000000..9ce834a8 --- /dev/null +++ b/data_structures/heap/median_of_infinite_stream.py @@ -0,0 +1,95 @@ +""" +Awesome explanation - https://youtu.be/1LkOrc-Le-Y + +Median is the middle element in a sorted array. The stream of input +integers can be in any order and we will have to store the integers in +such a way that the stream is maintained in an increasing order. + +So the main idea is that take an array and divide it into two parts of +equal length and the median will be as follows - + +* if the total number of integers in the stream is even, then both part will +have the same length. Hence the median will be the average of last element of the first +part (i.e max element of the first part) and the first element of the second part (i.e +min element of the second part) + +* if total number of integers in the stream is odd, add the extra element in the first part. +In this case, the median will be the last element of the first part + +Now we just have to maintain the order of both the parts of the array. Since we want the max +element from the first part, we can use a max heap there. And we can use min heap for the second +part as we need the min element from the second part + +Time complexity: + if the size of stream is N, we will have to iterate N times. LogN because insertion in heap + takes this much time. O(1) for getting the max or min element + + N * LogN +""" + +from heapq import heappush, heappop, heapify + +class MedianStream: + + def __init__(self): + self.stream = [] + self.min_heap = [] + self.max_heap = [] + heapify(self.max_heap) + heapify(self.min_heap) + self.curr_median = None + + + def add_number(self, num): + """ + min heap length <= maxheap length <= min heap length + 1 + """ + self.stream.append(num) + + if len(self.max_heap) == len(self.min_heap) == 0: + self.curr_median = num + + if len(self.max_heap) > len(self.min_heap): + if num < self.curr_median: + max_popped = -1 * heappop(self.max_heap) + heappush(self.min_heap, max_popped) + heappush(self.max_heap, -1 * num) + self.find_median('avg') + else: + heappush(self.min_heap, num) + self.find_median('avg') + else: + if num > self.curr_median: + # num will go to the min heap and the min element + # of min heap will go the max heap + min_popped = heappop(self.min_heap) + heappush(self.max_heap, -1 * min_popped) + heappush(self.min_heap, num) + self.find_median('max') + + else: + # num will go to the max heap + heappush(self.max_heap, -1 * num) + self.find_median('max') + + + def find_median(self, how): + if how == 'max': + self.curr_median = -1 * self.max_heap[0] + elif how == 'avg': + self.curr_median = (self.min_heap[0] + (-1 * self.max_heap[0])) / 2 + + +x = MedianStream() + +num = input() + +while num != 'q': + if num == 's': + print('Stream of integers - ', x.stream) + else: + num = int(num) + x.add_number(num) + print('Median - ', x.curr_median) + + num = input() From b6bf29a82abbdda4c4cd1a62ec80cf147780f25c Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 8 Jun 2021 09:13:03 +0530 Subject: [PATCH 262/302] add heap questions --- .../heap/kth_largest_element_in_stream.py | 61 +++++++++++++++++++ data_structures/heap/sum_elements_range.py | 24 ++++++++ 2 files changed, 85 insertions(+) create mode 100644 data_structures/heap/kth_largest_element_in_stream.py create mode 100644 data_structures/heap/sum_elements_range.py diff --git a/data_structures/heap/kth_largest_element_in_stream.py b/data_structures/heap/kth_largest_element_in_stream.py new file mode 100644 index 00000000..dfc278e4 --- /dev/null +++ b/data_structures/heap/kth_largest_element_in_stream.py @@ -0,0 +1,61 @@ +""" +Use a priority queue - min heap + +as soon as the stream reaches a length of K, start finding the number + +Since we are using a priority queue (min heap), the minimum number will be +at the first index. O(1) time to extract it + +We have to make sure that the length of the stream does not go above K because +we to find the kth largest element which in terms of this heap means the smallest +element. For example lets say we have K = 4. So as soon as the stream reaches a +length of 4, we start to find the 4th largest number. Now as we are maintaining the +length of the array at 4, 4th largest number will mean the smallest number. Using this +we are designing the program. + +If the number entered in the stream is less than the current min, we dont take it as it +wont affect the result. +""" + +from heapq import heapify, heappop, heappush + +class Stream: + + def __init__(self, k): + self.heap = [] + self.stream = [] + self.k = k + self.curr_min = None + heapify(self.heap) + + + def insert(self, x): + self.stream.append(x) + + if len(self.heap) < self.k: # when the heap is empty or size is less than K + heappush(self.heap, x) + self.curr_min = self.heap[0] + else: + if x > self.curr_min: + heappop(self.heap) # remove the curr min element + heappush(self.heap, x) # insert x + self.curr_min = self.heap[0] + + + def find_kth_max(self): + if len(self.heap) == self.k: + print(f'{self.k}th max number - {self.heap[0]}') + +k = 3 +x = Stream(k) + +num = input() + +while num != 'q': + if num == 's': + print(f'Stream - {x.stream} | K - {k}') + else: + num = int(num) + x.insert(num) + x.find_kth_max() + num = input() diff --git a/data_structures/heap/sum_elements_range.py b/data_structures/heap/sum_elements_range.py new file mode 100644 index 00000000..4a3b6645 --- /dev/null +++ b/data_structures/heap/sum_elements_range.py @@ -0,0 +1,24 @@ +""" +Find the sum of elements between k1th and k2th smallest elements +""" + +from heapq import heappush, heapify, heappop + +heap = [20, 8, 22, 4, 12, 10, 14] +k1 = 3 +k2 = 6 + +heapify(heap) + +# extracting min k1 times + +for i in range(k1): + heappop(heap) + +# now do extract min k2 - (k1 + 1) times +s = 0 + +for i in range(k2 - k1 - 1): + s += heappop(heap) + +print(s) From 65e797eb93624988b9d58e74c5af0f11530d4389 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 8 Jun 2021 10:06:42 +0530 Subject: [PATCH 263/302] new question --- ...s_that_can_searched_using_binary_search.py | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 data_structures/array/number_of_elements_that_can_searched_using_binary_search.py diff --git a/data_structures/array/number_of_elements_that_can_searched_using_binary_search.py b/data_structures/array/number_of_elements_that_can_searched_using_binary_search.py new file mode 100644 index 00000000..b1889522 --- /dev/null +++ b/data_structures/array/number_of_elements_that_can_searched_using_binary_search.py @@ -0,0 +1,52 @@ +""" +In an input of unsorted integer array, find the number of elements +that can be searched using binary search + +The idea is the an element is binary searchable if the elements to the +left of it are smaller than it and the elements to the right of it +are bigger than it + +So maintain two arrays - left_max and right_min such that in i'th index - + +* left_max[i] contains the max element between 0 and i-1 (left to right movement) +* right_min[i] contains the min element between n-1 and i+1 (right to left movement) + +Now for every element in the array, if its index its i, then it is binary searchable +if left_max[i] < arr[i] < right_min[i] +""" +import sys + +def get_searchable_numbers(arr, n): + left_max = [None] * n + right_min = [None] * n + + left_max[0] = float('-inf') + right_min[n-1] = float('inf') + + for i in range(1, n): + left_max[i] = max(left_max[i-1], arr[i-1]) + + for i in range(len(arr) - 2, -1, -1): + right_min[i] = min(right_min[i+1], arr[i+1]) + + res = [] + count = 0 + + for i in range(0, n): + num = arr[i] + left = left_max[i] + right = right_min[i] + + if left < num < right: + res.append(num) + count += 1 + + return count, res + + +if __name__ == '__main__': + #arr = [5,1,4,3,6,8,10,7,9] + arr = [4,1,3,9,8,10,11] + count, res = get_searchable_numbers(arr, len(arr)) + + print(count, res) From 179ef490f8c233445a78b1d2de8a5c9d471b0055 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 9 Jun 2021 20:53:59 +0530 Subject: [PATCH 264/302] add hash --- .../longest_subarray_sum_divisible_by_k.py | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 data_structures/hash/longest_subarray_sum_divisible_by_k.py diff --git a/data_structures/hash/longest_subarray_sum_divisible_by_k.py b/data_structures/hash/longest_subarray_sum_divisible_by_k.py new file mode 100644 index 00000000..4d691f59 --- /dev/null +++ b/data_structures/hash/longest_subarray_sum_divisible_by_k.py @@ -0,0 +1,55 @@ +""" +Find the longest subarray in an array whose sum is ` +divisible by k + +source - https://www.geeksforgeeks.org/longest-subarray-sum-divisible-k/ + +The idea is that we create a new array mod_arr where we mod_arr[i] = +sum(arr[0]...arr[i]) % k. So basically this array tells us that upto this +point in the input array, if we take sum of numbers till index i, that sum will +be divisible by k + +We will be creating a hash table for this to store the mod results + +Now, lets say x = sum(arr[0]...arr[i]) % k = mod_arr[i]. If + +1. if we find x == 0, increment length by 1 +2. if x not in hash, create it and store (x, index of x) +3. if x in hash: + this tells us that upto this point, where the remainder of sum of numbers + till this point divided by k is x, that remainder we already saw before as it + exists in the hash. So if we ignore the first dont consider the first occurence of x + and remove that from the sum, then this sum will be divisible by k (because subtracting remainder + from a number makes it divisible). + Now find the max length of such case as + if length = max(length, (i - index(x)) +""" + +def find_length(arr, k): + hash_table = {} + mod_arr = [] + s = 0 + length = 0 + start, end = 0, 0 + + for i in range(0, len(arr)): + s += arr[i] + mod_arr.append(s % k) + + for i in range(0, len(mod_arr)): + if mod_arr[i] == 0: + length += 1 + else: + if mod_arr[i] not in hash_table: + hash_table[mod_arr[i]] = i + else: + if length < (i - mod_arr[i]): + length = i - mod_arr[i] + start = mod_arr[i] + end = i - 1 # i-1 because the current number is not to considered as it makes the sum not divisible by k + + return length, arr[start:end+1] + + +arr = [ 2, 7, 6, 1, 4, 5 ] +print(find_length(arr, 3)) From 45a32a8822c421cf58bb75fb6324da0fae69174c Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 10 Jun 2021 08:01:04 +0530 Subject: [PATCH 265/302] Add longest consecutuve subsequence --- .../hash/longest_consecutive_subsequence.py | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 data_structures/hash/longest_consecutive_subsequence.py diff --git a/data_structures/hash/longest_consecutive_subsequence.py b/data_structures/hash/longest_consecutive_subsequence.py new file mode 100644 index 00000000..742ef4b7 --- /dev/null +++ b/data_structures/hash/longest_consecutive_subsequence.py @@ -0,0 +1,45 @@ +""" +Given an array of integers, find the length of the longest sub-sequence +such that elements in the subsequence are consecutive integers, the +consecutive numbers can be in any order. + +The idea is to store all the elements in a set first. Then as we are iterating +over the array, we check two things - +1. a number x can be a starting number in a sequence if x-1 is not present in the +set. If this is the case, create a loop and check how many elements from x to x+j are +in the set +2. if x -1 is there in the set, do nothing as this number is not a starting element +and must have been considered in a different sequence +""" + +def find_seq(arr, n): + s = set() + + for num in arr: + s.add(num) + + ans = 0 + elements = [] + + for i in range(n): + temp = [] + + if arr[i] - 1 not in s: + j = arr[i] + + while j in s: + temp.append(j) + j += 1 + + if j - arr[i] > ans: + ans = j - arr[i] + elements = temp.copy() + + return ans, elements + + +arr = [36, 41, 56, 35, 44, 33, 34, 92, 43, 32, 42] + +ans, elements = find_seq(arr, len(arr)) +print('Length - ', ans) +print('Elements - ', elements) From e0cffcfdefa4af9ad4689d3bcd6972842f75ea7d Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 10 Jun 2021 09:18:16 +0530 Subject: [PATCH 266/302] moved code around --- .../longest_consecutive_subsequence.py | 0 ...gest_increasing_consecutive_subsequence.py | 26 +++++++++++++++++++ .../longest_subarray_sum_divisible_by_k.py | 0 data_structures/hash/hash_table.py | 0 4 files changed, 26 insertions(+) rename {data_structures/hash => algorithms/dynamic_programming}/longest_consecutive_subsequence.py (100%) create mode 100644 algorithms/dynamic_programming/longest_increasing_consecutive_subsequence.py rename {data_structures/hash => algorithms/dynamic_programming}/longest_subarray_sum_divisible_by_k.py (100%) create mode 100644 data_structures/hash/hash_table.py diff --git a/data_structures/hash/longest_consecutive_subsequence.py b/algorithms/dynamic_programming/longest_consecutive_subsequence.py similarity index 100% rename from data_structures/hash/longest_consecutive_subsequence.py rename to algorithms/dynamic_programming/longest_consecutive_subsequence.py diff --git a/algorithms/dynamic_programming/longest_increasing_consecutive_subsequence.py b/algorithms/dynamic_programming/longest_increasing_consecutive_subsequence.py new file mode 100644 index 00000000..c272820c --- /dev/null +++ b/algorithms/dynamic_programming/longest_increasing_consecutive_subsequence.py @@ -0,0 +1,26 @@ +""" +Find the longest increasing consecutive subsequence in an array + +Idea - + +create a dictionary 'seq' and start iterating over the array + +1. if arr[i] - 1 exists in the array, length = length + seq[arr[i] - 1] +2. else, seq[i] = 1 +""" + +def find_seq(arr): + seq = {} + count = 0 + + for num in arr: + if num - 1 in seq: + seq[num] = seq[num - 1] + 1 + count = max(count, seq[num]) + else: + seq[num] = 1 + + return count + +arr = [6, 7, 8, 3, 4, 5, 9, 10] +print(find_seq(arr)) diff --git a/data_structures/hash/longest_subarray_sum_divisible_by_k.py b/algorithms/dynamic_programming/longest_subarray_sum_divisible_by_k.py similarity index 100% rename from data_structures/hash/longest_subarray_sum_divisible_by_k.py rename to algorithms/dynamic_programming/longest_subarray_sum_divisible_by_k.py diff --git a/data_structures/hash/hash_table.py b/data_structures/hash/hash_table.py new file mode 100644 index 00000000..e69de29b From 246f5272eddfe72317dcbfe4fb031654b59ca2c0 Mon Sep 17 00:00:00 2001 From: pratikscfr Date: Thu, 10 Jun 2021 11:50:34 +0530 Subject: [PATCH 267/302] Added Partition Sum Problem --- .../dynamic_programming/partition_sum.py | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 algorithms/dynamic_programming/partition_sum.py diff --git a/algorithms/dynamic_programming/partition_sum.py b/algorithms/dynamic_programming/partition_sum.py new file mode 100644 index 00000000..ff8cddcf --- /dev/null +++ b/algorithms/dynamic_programming/partition_sum.py @@ -0,0 +1,46 @@ +# A Dynamic Programming based +# Python3 program to partition problem + +# Returns true if arr[] can be partitioned +# in two subsets of equal sum, otherwise false +def findPartiion(arr, n) : + Sum = 0 + + # Calculate sum of all elements + for i in range(n) : + Sum += arr[i] + if (Sum % 2 != 0) : + return 0 + part = [0] * ((Sum // 2) + 1) + + # Initialize the part array as 0 + for i in range((Sum // 2) + 1) : + part[i] = 0 + + # Fill the partition table in bottom up manner + for i in range(n) : + + # the element to be included + # in the sum cannot be + # greater than the sum + for j in range(Sum // 2, arr[i] - 1, -1) : + + # check if sum - arr[i] + # could be formed + # from a subset + # using elements + # before index i + if (part[j - arr[i]] == 1 or j == arr[i]) : + part[j] = 1 + + return part[Sum // 2] + +# Drive code +arr = [ 1, 3, 3, 2, 3, 2 ] +n = len(arr) + +# Function call +if (findPartiion(arr, n) == 1) : + print("Can be divided into two subsets of equal sum") +else : + print("Can not be divided into two subsets of equal sum") From 2c7103f5170e7139f1ae59023d190d04ec09fa72 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 10 Jun 2021 18:00:57 +0530 Subject: [PATCH 268/302] Add file for hash table --- data_structures/hash/hash_table.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/data_structures/hash/hash_table.py b/data_structures/hash/hash_table.py index e69de29b..c1c05ced 100644 --- a/data_structures/hash/hash_table.py +++ b/data_structures/hash/hash_table.py @@ -0,0 +1,29 @@ +""" +Create a hash table from scratch. Use chaining for hash collision +""" + +class HashTable: + + + def __init__(self): + self.hash_table = + + + def check_collision(self): + pass + + + def add_to_linked_list(self): + pass + + + def insert(self): + pass + + + def delete(self): + pass + + + def get(self): + pass From 800eb1d1c48c9d71164bcbb0875d36ff6d81e516 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Fri, 11 Jun 2021 09:28:28 +0530 Subject: [PATCH 269/302] Fix issues and bugs and add comments --- .../graphs/all_paths_between_two_vertices.py | 2 +- data_structures/graphs/bellman_ford.py | 12 ++-- ...n_directed_graph_using_colors_recursive.py | 58 +++++++++++++++++ data_structures/graphs/kosaraju_algorithm.py | 3 +- .../max_edges_that_can_be_added_to_dag.py | 4 +- data_structures/graphs/mother_vertex.py | 10 +-- .../graphs/root_which_gives_min_height.py | 12 ++-- data_structures/graphs/same_path.py | 14 ++-- data_structures/graphs/same_path_recursive.py | 65 +++++++++++++++++++ 9 files changed, 155 insertions(+), 25 deletions(-) create mode 100644 data_structures/graphs/cycle_in_directed_graph_using_colors_recursive.py create mode 100644 data_structures/graphs/same_path_recursive.py diff --git a/data_structures/graphs/all_paths_between_two_vertices.py b/data_structures/graphs/all_paths_between_two_vertices.py index 958a2b82..3632d36e 100644 --- a/data_structures/graphs/all_paths_between_two_vertices.py +++ b/data_structures/graphs/all_paths_between_two_vertices.py @@ -1,5 +1,5 @@ # Use backtracking -# The only with this approach is that if there is a cycle, then +# The only poroblem with this approach is that if there is a cycle, then # it can show infinitely many paths # Reference - https://www.geeksforgeeks.org/count-possible-paths-two-vertices/ diff --git a/data_structures/graphs/bellman_ford.py b/data_structures/graphs/bellman_ford.py index 35c6522d..2901613e 100644 --- a/data_structures/graphs/bellman_ford.py +++ b/data_structures/graphs/bellman_ford.py @@ -55,12 +55,14 @@ def bellman_ford(self, source, destination): parent[source] = source distance[source] = source - for (u, v) in self.edges: - wt = self.edges[(u, v)].weight + for i in range(self.vertices - 1): # Doing V - 1 times to find shortest distance - if distance[v] > distance[u] + wt: - distance[v] = distance[u] + wt - parent[v] = u + for (u, v) in self.edges: + wt = self.edges[(u, v)].weight + + if distance[v] > distance[u] + wt: + distance[v] = distance[u] + wt + parent[v] = u # Now for the Vth iteration, check for the negative cycle diff --git a/data_structures/graphs/cycle_in_directed_graph_using_colors_recursive.py b/data_structures/graphs/cycle_in_directed_graph_using_colors_recursive.py new file mode 100644 index 00000000..c4a687ed --- /dev/null +++ b/data_structures/graphs/cycle_in_directed_graph_using_colors_recursive.py @@ -0,0 +1,58 @@ +""" +Using three colors - white, gray and black +White - vertices that are not processed (inital state of all vertices) +Gray - vertices that are in DFS +Black - fully traversed vertices (i.e its progenies are also done) + +If while traversing any adjacent node is colored Gray, that means cycle exists +""" + +from collections import defaultdict + +class Graph: + + + def __init__(self, vertices): + self.graph = defaultdict(list) + self.vertices = vertices + + + def add_edge(self, u, v): + self.graph[u].append(v) + + + def dfs(self, vertex, colors): + colors[vertex] = 'Gray' + + for v in self.graph[vertex]: + + if colors[v] == 'Gray': + return True + + elif colors[v] == 'White' and self.dfs(v, colors) == True: + return True + + colors[vertex] = 'Black' + return False + + + def is_cyclic(self): + colors = ['White'] * self.vertices + + for vertex in self.graph.keys(): + if colors[vertex] == 'White': + if self.dfs(vertex, colors) == True: + return True + + return False + + +g = Graph(4) +g.add_edge(0, 1) +g.add_edge(0, 2) +g.add_edge(1, 2) +g.add_edge(2, 0) +g.add_edge(2, 3) +g.add_edge(3, 3) + +print(g.is_cyclic()) \ No newline at end of file diff --git a/data_structures/graphs/kosaraju_algorithm.py b/data_structures/graphs/kosaraju_algorithm.py index cd446c1a..99277672 100644 --- a/data_structures/graphs/kosaraju_algorithm.py +++ b/data_structures/graphs/kosaraju_algorithm.py @@ -14,6 +14,7 @@ class Graph: + def __init__(self, vertices): self.vertices = vertices self.graph = defaultdict(list) @@ -63,8 +64,6 @@ def kosaraju(self): tgraph = self.create_tranpose() visited = [False] * self.vertices - print('stack - ', stack) - while stack: s = stack.pop() diff --git a/data_structures/graphs/max_edges_that_can_be_added_to_dag.py b/data_structures/graphs/max_edges_that_can_be_added_to_dag.py index acad5380..f4ba0900 100644 --- a/data_structures/graphs/max_edges_that_can_be_added_to_dag.py +++ b/data_structures/graphs/max_edges_that_can_be_added_to_dag.py @@ -11,6 +11,8 @@ 2. If edge is not there left to right, create the edge 3. Count the number of edges added +source - https://www.geeksforgeeks.org/maximum-edges-can-added-dag-remains-dag/ + """ from collections import defaultdict @@ -53,7 +55,7 @@ def max_edges(self): visited = [False] * self.vertices count = 0 - for i in topo: + for i in range(len(topo)): vertex = topo[i] # Mark the connected vertices visited for j in self.graph[vertex]: diff --git a/data_structures/graphs/mother_vertex.py b/data_structures/graphs/mother_vertex.py index 40f8ac10..794c88ee 100644 --- a/data_structures/graphs/mother_vertex.py +++ b/data_structures/graphs/mother_vertex.py @@ -1,9 +1,11 @@ -# A mother vertex is a vertex such that all other vertices -# can be reached by a path from this vertex +""" +A mother vertex is a vertex such that all other vertices +can be reached by a path from this vertex -# Reference - https://www.geeksforgeeks.org/find-a-mother-vertex-in-a-graph/ +Reference - https://www.geeksforgeeks.org/find-a-mother-vertex-in-a-graph/ -# Time complexity - 2 * O(V + E) = O(V + E) +Time complexity - 2 * O(V + E) = O(V + E) +""" from collections import defaultdict diff --git a/data_structures/graphs/root_which_gives_min_height.py b/data_structures/graphs/root_which_gives_min_height.py index 77a738a9..7a079196 100644 --- a/data_structures/graphs/root_which_gives_min_height.py +++ b/data_structures/graphs/root_which_gives_min_height.py @@ -1,4 +1,7 @@ -# Reference - https://www.geeksforgeeks.org/roots-tree-gives-minimum-height/ +""" +Find the node in an undirected graph which gives the minimum height +Reference - https://www.geeksforgeeks.org/roots-tree-gives-minimum-height/ +""" from collections import defaultdict from queue import Queue @@ -22,10 +25,10 @@ def root_min_height(self): q = Queue() for i in range(self.V): - if self.degree[i] == 1: + if self.degree[i] == 1: # To identify leaf nodes q.put(i) - - + + # now move inwards from the leaf node while self.V > 2: for i in range(q.qsize()): t = q.get() @@ -38,7 +41,6 @@ def root_min_height(self): if self.degree[j] == 1: q.put(j) - res = list() while q.qsize() > 0: res.append(q.get()) diff --git a/data_structures/graphs/same_path.py b/data_structures/graphs/same_path.py index 127c1b86..82219691 100644 --- a/data_structures/graphs/same_path.py +++ b/data_structures/graphs/same_path.py @@ -1,8 +1,10 @@ -# Check if two nodes are on the same path in a tree. Use DFS and the concept of intime and outtime. -# Intime - time when a node is visited for the first time -# Outtime - time when a node is visited for the second time after all its children have been visited -# For any pair of node if they are on the same path - -# intime[u] < intime[v] and outtime[u] > outtime[v] +""" +Check if two nodes are on the same path in a tree. Use DFS and the concept of intime and outtime. +Intime - time when a node is visited for the first time +Outtime - time when a node is visited for the second time after all its children have been visited +For any pair of node if they are on the same path - +intime[u] < intime[v] and outtime[u] > outtime[v] +""" from collections import defaultdict @@ -40,8 +42,6 @@ def dfs(self): timer += 1 intime[s] = timer - print(s) - for i in self.graph[s]: if visited[i] == False: stack.append(i) diff --git a/data_structures/graphs/same_path_recursive.py b/data_structures/graphs/same_path_recursive.py new file mode 100644 index 00000000..3b2087aa --- /dev/null +++ b/data_structures/graphs/same_path_recursive.py @@ -0,0 +1,65 @@ +""" +Check if two nodes are on the same path in a undirected graph. Use DFS and the concept of intime and outtime. +Intime - time when a node is visited for the first time +Outtime - time when a node is visited for the second time after all its children have been visited +For any pair of node if they are on the same path - +intime[u] < intime[v] and outtime[u] > outtime[v] +""" + +from collections import defaultdict + +class Graph: + + def __init__(self, vertices): + self.graph = defaultdict(list) + self.vertices = vertices + + + def add_edge(self, u, v): + self.graph[u].append(v) + self.graph[v].append(u) + + + def dfs(self, vertex, intime, outtime, timer, visited): + visited[vertex] = True + timer += 1 + intime[vertex] = timer + + for v in self.graph[vertex]: + if visited[v] == False: + self.dfs(v, intime, outtime, timer, visited) + + timer += 1 + outtime[vertex] = timer + + + def on_same_path(self, u, v): + intime = [-1] * self.vertices + outtime = [-1] * self.vertices + timer = 0 + visited = [False] * self.vertices + + for vertex in self.graph: + if visited[vertex] == False: + self.dfs(vertex, intime, outtime, timer, visited) + + + if (intime[u] < intime[v] and outtime[u] > outtime[v]) \ + or (intime[v] < intime[u] and outtime[v] > outtime[u]): + return True + return False + + +g = Graph(9) +g.add_edge(0, 1) +g.add_edge(0, 2) +g.add_edge(2, 5) +g.add_edge(1, 3) +g.add_edge(1, 4) +g.add_edge(4, 6) +g.add_edge(4, 7) +g.add_edge(4, 8) + +print(g.on_same_path(0, 4)) +print(g.on_same_path(1, 8)) +print(g.on_same_path(1, 5)) \ No newline at end of file From e05e57e703bd0df915f72a6d8d51842950d7a5ae Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Sat, 12 Jun 2021 15:59:12 +0530 Subject: [PATCH 270/302] added new question --- ...subarray_with_no_pairsum_divisible_by_k.py | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 algorithms/dynamic_programming/longest_subarray_with_no_pairsum_divisible_by_k.py diff --git a/algorithms/dynamic_programming/longest_subarray_with_no_pairsum_divisible_by_k.py b/algorithms/dynamic_programming/longest_subarray_with_no_pairsum_divisible_by_k.py new file mode 100644 index 00000000..844b5611 --- /dev/null +++ b/algorithms/dynamic_programming/longest_subarray_with_no_pairsum_divisible_by_k.py @@ -0,0 +1,54 @@ +""" +Find the longest subarray in the input array such that the pairwise sum of +the elements of this subarray is not divisible by K + +The idea is - +How can we tell that two numbers x and y will make a pairsum that will be +divisible by K just by looking at their remainders? There can be two conditions + +1. It will be only possible if the sum of the remainders when x and y are +divided by K is equal to K. As the sum of the remainders cannot exceed K +so if it reaches K then it means that the sum of those numbers will also be +divisible by K +0 < (X%K) + (Y%K) <= K + +2. If arr[i] % k == 0 and there is also an element j such that arr[j] % k == 0 +and 0 exists in the hash (i.e hash[j] = True) +""" + +def find_subarray(arr, k): + """ + True means divisible by k + """ + start, end = 0, 0 + max_start, max_end = 0, 0 + + n = len(arr) + mod_arr = [0] * n + + mod_arr[arr[0] % k] = mod_arr[arr[0] % k] + 1 + + for i in range(1, n): + mod = arr[i] % k + + while (mod_arr[k - mod] != 0) or (mod == 0 and mod_arr[mod] != 0): + mod_arr[arr[start] % k] = mod_arr[arr[start] % k] - 1 + start += 1 + + mod_arr[mod] = mod_arr[mod] + 1 + end += 1 + + if (end - start) > (max_end - max_start): + max_end = end + max_start = start + + print(f'Max size is {max_end - max_start}') + + for i in (max_start, max_end + 1): + print(arr[i], end=" ") + + +arr = [3, 7, 1, 9, 2] +k = 3 +find_subarray(arr, k) + From a5b56bbf76075c6b4fd19becaefe4c978d84e5d9 Mon Sep 17 00:00:00 2001 From: pratikscfr Date: Sun, 13 Jun 2021 21:04:08 +0530 Subject: [PATCH 271/302] changed casing --- .../dynamic_programming/partition_sum.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/algorithms/dynamic_programming/partition_sum.py b/algorithms/dynamic_programming/partition_sum.py index ff8cddcf..c07b79f6 100644 --- a/algorithms/dynamic_programming/partition_sum.py +++ b/algorithms/dynamic_programming/partition_sum.py @@ -3,18 +3,18 @@ # Returns true if arr[] can be partitioned # in two subsets of equal sum, otherwise false -def findPartiion(arr, n) : - Sum = 0 +def find_partiion(arr, n) : + sum = 0 # Calculate sum of all elements for i in range(n) : - Sum += arr[i] - if (Sum % 2 != 0) : + sum += arr[i] + if (sum % 2 != 0) : return 0 - part = [0] * ((Sum // 2) + 1) + part = [0] * ((sum // 2) + 1) # Initialize the part array as 0 - for i in range((Sum // 2) + 1) : + for i in range((sum // 2) + 1) : part[i] = 0 # Fill the partition table in bottom up manner @@ -23,7 +23,7 @@ def findPartiion(arr, n) : # the element to be included # in the sum cannot be # greater than the sum - for j in range(Sum // 2, arr[i] - 1, -1) : + for j in range(sum // 2, arr[i] - 1, -1) : # check if sum - arr[i] # could be formed @@ -33,14 +33,14 @@ def findPartiion(arr, n) : if (part[j - arr[i]] == 1 or j == arr[i]) : part[j] = 1 - return part[Sum // 2] + return part[sum // 2] # Drive code arr = [ 1, 3, 3, 2, 3, 2 ] n = len(arr) # Function call -if (findPartiion(arr, n) == 1) : +if (find_partiion(arr, n) == 1) : print("Can be divided into two subsets of equal sum") else : print("Can not be divided into two subsets of equal sum") From 13621d82012fcbdea4420eea1945ce35e65984fb Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 15 Jun 2021 08:48:22 +0530 Subject: [PATCH 272/302] Cleaned code --- algorithms/greedy/__init__.py | 1 - algorithms/greedy/activity_selection.py | 31 ++++++++++++++++++------- algorithms/greedy/index.md | 1 - 3 files changed, 23 insertions(+), 10 deletions(-) delete mode 100644 algorithms/greedy/__init__.py delete mode 100644 algorithms/greedy/index.md diff --git a/algorithms/greedy/__init__.py b/algorithms/greedy/__init__.py deleted file mode 100644 index 8b137891..00000000 --- a/algorithms/greedy/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/algorithms/greedy/activity_selection.py b/algorithms/greedy/activity_selection.py index 8dbd822f..374ad563 100644 --- a/algorithms/greedy/activity_selection.py +++ b/algorithms/greedy/activity_selection.py @@ -4,15 +4,30 @@ #s[]--> An array that contains start time of all activities #f[] --> An array that contains finish time of all activities -def print_max_activities(s, f): - n = len(f) - # the first activity is always selected +def find_activities(arr): + n = len(arr) + selected = [] + + arr.sort(key = lambda x: x[1]) + i = 0 - print(i, end=' ') - # for the rest - for j in range(n): - if s[j] >= f[i]: - print(j, end=' ') + # since it is a greedy algorithm, the first acitivity is always + # selected because it is the most optimal choice at that point + selected.append(arr[i]) + + for j in range(1, n): + start_time_next_activity = arr[j][0] + end_time_prev_activity = arr[i][1] + + if start_time_next_activity >= end_time_prev_activity: + selected.append(arr[j]) i = j + + return selected + + +arr = [[5, 9], [1, 2], [3, 4], [0, 6],[5, 7], [8, 9]] +print(find_activities(arr)) + diff --git a/algorithms/greedy/index.md b/algorithms/greedy/index.md deleted file mode 100644 index d9b79484..00000000 --- a/algorithms/greedy/index.md +++ /dev/null @@ -1 +0,0 @@ -# Index of Greedy \ No newline at end of file From ede7c4dd1babe732e8dac3c5121e2c60b28d28a8 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 15 Jun 2021 10:20:48 +0530 Subject: [PATCH 273/302] Add questions --- algorithms/dynamic_programming/coin_change.py | 39 +++++++++++++------ algorithms/greedy/min_platforms.py | 37 ++++++++++++++++++ 2 files changed, 65 insertions(+), 11 deletions(-) create mode 100644 algorithms/greedy/min_platforms.py diff --git a/algorithms/dynamic_programming/coin_change.py b/algorithms/dynamic_programming/coin_change.py index 96b57648..7b9cbe26 100644 --- a/algorithms/dynamic_programming/coin_change.py +++ b/algorithms/dynamic_programming/coin_change.py @@ -1,16 +1,33 @@ -# Concept is almost same as 01 Knapsack Problem -def min_coin(coins, total): +def min_coins(coins, total): cols = total + 1 - rows = len(coins) - t = [[[0] if col == 0 else float('inf') for col in range(cols)] for i in range(rows)] + min_coins = [float('inf')] * (total + 1) + coins_used = [-1] * (total + 1) - for i in range(rows): - for j in range(1, cols): - if j < coins[i]: - t[i][j] = t[i-1][j] - else: - t[i][j] = min(t[i-1][j], 1 + t[i][j-coins[i]]) + min_coins[0] = 0 # to form 0, we need 0 coins - return t[rows-1][cols-1] + for i in range(0, len(coins)): + for j in range(1, len(min_coins)): + if coins[i] > j: # if the coin value is more than j (curr total), ignore it + continue + + if (1 + min_coins[j - coins[i]]) < min_coins[j]: + min_coins[j] = 1 + min_coins[j - coins[i]] + coins_used[j] = i + + # finding which coins were used + picked_coins = [] + while total > 0: + index_of_coin_used = coins_used[total] + coin = coins[index_of_coin_used] + picked_coins.append(coin) + total -= coin + + print('Min coins needed - ', min_coins[-1]) + print('Coins used - ', picked_coins) + +total = 11 +coins = [9, 6, 5, 1] + +min_coins(coins, total) diff --git a/algorithms/greedy/min_platforms.py b/algorithms/greedy/min_platforms.py new file mode 100644 index 00000000..fd372f0a --- /dev/null +++ b/algorithms/greedy/min_platforms.py @@ -0,0 +1,37 @@ +""" +Given the arrival and departure times of buses at a station +find the min number of platforms that must be there +""" + + +def find_platforms(arrival, departure): + n = len(arrival) + + arrival.sort() + departure.sort() + + i = 1 + j = 0 + + ans = 1 # atleast one platform is required + plat = 1 + + while i < n and j < n: + if arrival[i] <= departure[j]: + plat += 1 + i += 1 + + elif arrival[i] > departure[j]: + plat -= 1 + j += 1 + + ans = max(ans, plat) + + + return ans + + +arr = [900, 940, 950, 1100, 1500, 1800] +dep = [910, 1200, 1120, 1130, 1900, 2000] + +print(find_platforms(arr, dep)) From 3c2597ffa0113acb5877d77baab21b8f0a2c3d3a Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 16 Jun 2021 08:40:40 +0530 Subject: [PATCH 274/302] Added cost of tiling --- algorithms/greedy/cost_of_tiles.py | 45 ++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 algorithms/greedy/cost_of_tiles.py diff --git a/algorithms/greedy/cost_of_tiles.py b/algorithms/greedy/cost_of_tiles.py new file mode 100644 index 00000000..05fde8da --- /dev/null +++ b/algorithms/greedy/cost_of_tiles.py @@ -0,0 +1,45 @@ +""" +Find the min cost of tiles to cover a floor. +Floor is represented by 2D array where - +* = tile already placed +. = no tile + +tiles available are 1*1 and 1*2 and their costs +are A and B + +Source - https://www.geeksforgeeks.org/minimize-cost-to-cover-floor-using-tiles-of-dimensions-11-and-12/ +""" + +def cost(arr, A, B): + n = len(arr) + m = len(arr[0]) + + ans = 0 + + for i in range(n): + j = 0 + + while j < m: + if arr[i][j] == '*': # tile is already there + j += 1 + continue + + if j == m - 1: # if j is pointing to last tile, you can use only 1*1 tile + ans += A + else: + if arr[i][j+1] == '.': + ans += min(2 * A, B) + j += 1 + else: + ans += A + + j += 1 + + print('Cost of tiling is - ', ans) + +arr = [ [ '.', '.', '*' ], + [ '.', '*', '*' ] ] + +A, B = 2, 10 + +cost(arr, A, B) From 1342be014357df0816f9e3b105ebadeff5d94323 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Sun, 20 Jun 2021 15:48:33 +0530 Subject: [PATCH 275/302] Remove graph --- algorithms/graph/bfs.py | 49 ---------------- algorithms/graph/dfs.py | 46 --------------- algorithms/graph/dijkstra.py | 55 ------------------ algorithms/graph/find_all_paths.py | 32 ----------- algorithms/graph/index.md | 4 -- algorithms/graph/mst.py | 83 ---------------------------- algorithms/graph/topological_sort.py | 33 ----------- 7 files changed, 302 deletions(-) delete mode 100644 algorithms/graph/bfs.py delete mode 100644 algorithms/graph/dfs.py delete mode 100644 algorithms/graph/dijkstra.py delete mode 100644 algorithms/graph/find_all_paths.py delete mode 100644 algorithms/graph/index.md delete mode 100644 algorithms/graph/mst.py delete mode 100644 algorithms/graph/topological_sort.py diff --git a/algorithms/graph/bfs.py b/algorithms/graph/bfs.py deleted file mode 100644 index 6c64f75f..00000000 --- a/algorithms/graph/bfs.py +++ /dev/null @@ -1,49 +0,0 @@ -# Python3 Program to print BFS traversal -# from a given source vertex. BFS(int s) -# traverses vertices reachable from s. -from collections import defaultdict - -# This class represents a directed graph -# using adjacency list representation -class Graph: - - # Constructor - def __init__(self): - - # default dictionary to store graph - self.graph = defaultdict(list) - - # function to add an edge to graph - def addEdge(self,u,v): - self.graph[u].append(v) - - # Function to print a BFS of graph - def BFS(self, s): - - # Mark all the vertices as not visited - visited = [False] * (len(self.graph)) - - # Create a queue for BFS - queue = [] - - # Mark the source node as - # visited and enqueue it - queue.append(s) - visited[s] = True - - while queue: - - # Dequeue a vertex from - # queue and print it - s = queue.pop(0) - print (s, end = " ") - - # Get all adjacent vertices of the - # dequeued vertex s. If a adjacent - # has not been visited, then mark it - # visited and enqueue it - for i in self.graph[s]: - if visited[i] == False: - queue.append(i) - visited[i] = True - \ No newline at end of file diff --git a/algorithms/graph/dfs.py b/algorithms/graph/dfs.py deleted file mode 100644 index 4a452536..00000000 --- a/algorithms/graph/dfs.py +++ /dev/null @@ -1,46 +0,0 @@ -# Python program to print DFS traversal for complete graph -from __future__ import print_function -from collections import defaultdict - -# This class represents a directed graph using adjacency -# list representation -class Graph: - - # Constructor - def __init__(self): - - # default dictionary to store graph - self.graph = defaultdict(list) - - # function to add an edge to graph - def addEdge(self,u,v): - self.graph[u].append(v) - - # A function used by DFS - def DFSUtil(self, v, visited): - - # Mark the current node as visited and print it - visited[v]= True - print(v, end=" ") - - # Recur for all the vertices adjacent to - # this vertex - for i in self.graph[v]: - if visited[i] == False: - self.DFSUtil(i, visited) - - - # The function to do DFS traversal. It uses - # recursive DFSUtil() - def DFS(self): - V = len(self.graph) #total vertices - - # Mark all the vertices as not visited - visited =[False]*(V) - - # Call the recursive helper function to print - # DFS traversal starting from all vertices one - # by one - for i in range(V): - if visited[i] == False: - self.DFSUtil(i, visited) diff --git a/algorithms/graph/dijkstra.py b/algorithms/graph/dijkstra.py deleted file mode 100644 index 91dbe362..00000000 --- a/algorithms/graph/dijkstra.py +++ /dev/null @@ -1,55 +0,0 @@ -# i checked your other py files and decided that i would go for default dict -# i used same structure as needed for this repository. -from collections import defaultdict -import sys -r = range -# min weight goes for 0 in this case -max_weight = sys.maxsize - - -class Graph: - # Class initializer - def __init__(self, vertices): - # num of vertices and our starting graph - self.vertices = vertices - - # Values will be [[]] two deminsial array with - # columns for start going to rows. - self.graph = [[0] * self.vertices for _ in r(self.vertices)] - self.visited = [0] * self.vertices # to control visited vertices - # for our distances to minimaze them. - self.distances = [max_weight] * self.vertices - - # Add edge to graph start --> end point with specific weight! - def add_edge(self, start, end, weight): - self.graph[start][end] = weight - - def print_dist(self, dist): - for _ in r(self.vertices): - print("vert ", _, "\tdist ", self.distances[_]) - - def dijkstra(self, end_point): - self.distances[end_point] = 0 - - for vert in r(self.vertices): - - # we need to check for minimum but not visited!! - my_min, min_index = max_weight, 0 - for _ in r(self.vertices): - if not self.visited[_]: - if my_min > self.distances[_]: - my_min = self.distances[_] - min_index = _ - - # check the flag for visited - self.visited[min_index] = 1 - - # # iterate and update if needed - for adj in r(self.vertices): - # check for edge and visited - val = self.graph[min_index][adj] - if not self.visited[adj] and val != 0: - # check if needed update - if self.distances[adj] > self.distances[min_index] + val: - self.distances[adj] = self.distances[min_index] + val - self.print_dist(self.distances) diff --git a/algorithms/graph/find_all_paths.py b/algorithms/graph/find_all_paths.py deleted file mode 100644 index 9152bf2a..00000000 --- a/algorithms/graph/find_all_paths.py +++ /dev/null @@ -1,32 +0,0 @@ -''' -find all the possible paths in a directed cyclic graph from -a start point to a end point. -''' - - - - -def find_all_paths(graph, start, end, path=[]): - path = path + [start] - if start == end: - return [path] - if start not in graph.keys(): - return [] - paths = [] - for node in graph[start]: - if node not in path: #to prevent cyclic rotations - newpaths = find_all_paths(graph, node, end, path) - #print(newpaths) - for newpath in newpaths: - paths.append(newpath) - return paths - - -graph={1:[2,4], - 2:[3], - 4:[5], - 3:[5] - } - -for i in graph.keys(): - print(i,'to 5',find_all_paths(graph,i,5)) diff --git a/algorithms/graph/index.md b/algorithms/graph/index.md deleted file mode 100644 index e5197adc..00000000 --- a/algorithms/graph/index.md +++ /dev/null @@ -1,4 +0,0 @@ -# Index of graph - -* dfs.py -* bfs.py diff --git a/algorithms/graph/mst.py b/algorithms/graph/mst.py deleted file mode 100644 index 930a2211..00000000 --- a/algorithms/graph/mst.py +++ /dev/null @@ -1,83 +0,0 @@ -# i checked your other py files and decided that i would go for default dict -# i used same structure as needed for this repository. -from collections import defaultdict -r = range - - -class Graph: - # Class initializer - def __init__(self, vertices): - # num of vertices and our starting graph - - self.vertices = vertices - # Values will be [start_point, end_point, weight] - self.graph = [] - - # Add edge to graph - def add_edge(self, start, end, weight): - value = [start, end, weight] - self.graph.append(value) - - # Simple search alghoritm - def search(self, parent_ranks, index): - if parent_ranks[index] != index: - return self.search(parent_ranks, parent_ranks[index]) - return index - - def union(self, ranks, parent_ranks, fir, sec): - fir, sec = self.search(parent_ranks, fir), self.search( - parent_ranks, sec) - - # 3 steps. ranks lower, higher, same - - if (ranks[fir] > ranks[sec]): - parent_ranks[sec] = fir - - elif (ranks[fir] < ranks[sec]): - parent_ranks[fir] = sec - - elif (ranks[fir] == ranks[sec]): - parent_ranks[sec] = fir - ranks[fir] += 1 - - # run mst alghoritm main part. - - def run_mst(self, ranks, parent_ranks, answer): - edge, index = 0, 0 - - while True: - if ((self.vertices - 1) <= edge): - break - - # Take value - value = self.graph[index] - - # check cycle - fir, sec = self.search(parent_ranks, value[0]), self.search( - parent_ranks, value[1]) - - if fir != sec: - edge += 1 # increase edge - - # append and union - answer.append(value) - self.union(ranks, parent_ranks, fir, sec) - - index += 1 - - def print_graph(self, answer): - for start, end, weight in answer: - print(f"{start} - {end} --> {weight}") - - # Main function for mst alghoritm - def MST(self): - # sort the graph - self.graph = sorted(self.graph, key=lambda item: item[2]) - - # For this alghoritm we need two array. - ranks = [0] * self.vertices - parent_ranks = [_ for _ in r(self.vertices)] - answer = [] - - self.run_mst(ranks, parent_ranks, answer) - self.print_graph(answer) diff --git a/algorithms/graph/topological_sort.py b/algorithms/graph/topological_sort.py deleted file mode 100644 index ea214d0d..00000000 --- a/algorithms/graph/topological_sort.py +++ /dev/null @@ -1,33 +0,0 @@ -from collections import defaultdict - - -def topological_sort(graph: dict) -> list: - """Provides the topologically sorted nodes of a graph in a list. Takes input as a dictionary, - where the key is a node and the value is a list of the nodes that the key is a source node for.""" - - # Keeps track of the "degree" of a node; once this reaches 0, we push it onto the output. - leading_in = defaultdict(lambda: 0) - - for key, values in graph.items(): - if key not in leading_in.keys(): - leading_in[key] = 0 - for node in values: - leading_in[node] += 1 - - queue = [] - output = [] - - for node, degree in leading_in.items(): - if degree == 0: - queue.append(node) - output.append(node) - - while queue: - node = queue.pop(0) - for destination in graph.get(node, []): - leading_in[destination] -= 1 - if leading_in[destination] == 0: - queue.append(destination) - output.append(destination) - - return output From c68b97f6e3622ecffa2806a4fde99c82f9cd079a Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 23 Jun 2021 08:14:30 +0530 Subject: [PATCH 276/302] Remove index files --- data_structures/circular_linked_list/index.md | 5 ----- data_structures/queue/index.md | 3 --- 2 files changed, 8 deletions(-) delete mode 100644 data_structures/circular_linked_list/index.md delete mode 100644 data_structures/queue/index.md diff --git a/data_structures/circular_linked_list/index.md b/data_structures/circular_linked_list/index.md deleted file mode 100644 index a14e9993..00000000 --- a/data_structures/circular_linked_list/index.md +++ /dev/null @@ -1,5 +0,0 @@ -# Index of circular linked list - -* [Check Circular Linked List](check_circular_linked_list.py) -* [Delete](delete.py) -* [Traversal](traversal.py) diff --git a/data_structures/queue/index.md b/data_structures/queue/index.md deleted file mode 100644 index 8506ea63..00000000 --- a/data_structures/queue/index.md +++ /dev/null @@ -1,3 +0,0 @@ -# Index of Queue - -[Queue](queue.py) \ No newline at end of file From 6e222610c8537c476c61566d79ce945c3cda639e Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 24 Jun 2021 09:29:58 +0530 Subject: [PATCH 277/302] Remove index from graphs --- data_structures/graphs/index.md | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 data_structures/graphs/index.md diff --git a/data_structures/graphs/index.md b/data_structures/graphs/index.md deleted file mode 100644 index 7baba1cf..00000000 --- a/data_structures/graphs/index.md +++ /dev/null @@ -1,3 +0,0 @@ -# Index of graphs - -* [Adjacency List](adjacency_list.py) From 4dc760fd8d07df815c17b96a89372ef1909e7eea Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 1 Jul 2021 18:47:50 +0530 Subject: [PATCH 278/302] Add docstring --- data_structures/binary_trees/check_perfect_binary_tree.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/data_structures/binary_trees/check_perfect_binary_tree.py b/data_structures/binary_trees/check_perfect_binary_tree.py index c3f76281..5768717b 100644 --- a/data_structures/binary_trees/check_perfect_binary_tree.py +++ b/data_structures/binary_trees/check_perfect_binary_tree.py @@ -1,5 +1,7 @@ -# A binary tree is perfect if all the internal nodes have 2 children and -# all the leaves are at the same level +""" +A binary tree is perfect if all the internal nodes have 2 children and +all the leaves are at the same level +""" class Node: From 3322d66c59220c17ecf9f456fc49ae09e30f8133 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 1 Jul 2021 19:11:16 +0530 Subject: [PATCH 279/302] Bug fix --- data_structures/binary_trees/identical_trees.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/binary_trees/identical_trees.py b/data_structures/binary_trees/identical_trees.py index 1d81cef3..bacc0614 100644 --- a/data_structures/binary_trees/identical_trees.py +++ b/data_structures/binary_trees/identical_trees.py @@ -13,6 +13,6 @@ def identical(root1, root2): return True if root1 is not None and root2 is not None: - return root1.val == root2. val and identical(root1.left, root2.left) and identical(root1.right, root2.right) + return root1.val == root2.val and identical(root1.left, root2.left) and identical(root1.right, root2.right) return False From d9da92f29bd23163c069a58f4126d90e5bb2d0d7 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Fri, 2 Jul 2021 08:31:44 +0530 Subject: [PATCH 280/302] Remove print statement --- data_structures/graphs/bellman_ford.py | 1 - 1 file changed, 1 deletion(-) diff --git a/data_structures/graphs/bellman_ford.py b/data_structures/graphs/bellman_ford.py index 2901613e..49aabe8a 100644 --- a/data_structures/graphs/bellman_ford.py +++ b/data_structures/graphs/bellman_ford.py @@ -71,7 +71,6 @@ def bellman_ford(self, source, destination): for (u, v) in self.edges: wt = self.edges[(u, v)].weight if distance[v] > distance[u] + wt: - print('h - ', u, v) negative_cycle_present = True break From d414f3498e93cdbb51ab685a0f98b8d4ea9767fc Mon Sep 17 00:00:00 2001 From: "A.H" <73077907+ahcodes@users.noreply.github.com> Date: Fri, 2 Jul 2021 21:15:34 +0530 Subject: [PATCH 281/302] Minor alteration of a sentence. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b5a68823..1286c6c4 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Contains all data structure questions categorised into sub-directories like stac ### Algorithms -This directory contains various types of algorithm questions like Dynamic Programming, Sorting, Greedy, etc. The current structure of this directory is like - +This directory contains various types of algorithm questions like Dynamic Programming, Sorting, Greedy, etc. The current structure of this directory is as follows: 1. [Dynamic Programming](algorithms/dynamic_programming) 2. [Graphs](algorithms/graph) From 27b802be136a035acc9ec4f3663d52cebe407e3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tadej=20Glin=C5=A1ek?= Date: Mon, 19 Jul 2021 16:51:25 +0200 Subject: [PATCH 282/302] Fixed a bug in permutations_of_word.py --- data_structures/array/permutations_of_word.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/array/permutations_of_word.py b/data_structures/array/permutations_of_word.py index c0085b54..e5eb8998 100644 --- a/data_structures/array/permutations_of_word.py +++ b/data_structures/array/permutations_of_word.py @@ -6,7 +6,7 @@ def permutation(lst): l = [] for i in range(len(lst)): m = lst[i] - rem_lst = lst[:i] + lst[i+i:] + rem_lst = lst[:i] + lst[i+1:] for p in permutation(rem_lst): l.append([m] + p) return l From 70d2852bd4a2f752b2b9f2b7475fb8b7206450a7 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Wed, 25 Aug 2021 10:10:00 +0530 Subject: [PATCH 283/302] Add comments for Kadane's algorithm --- data_structures/array/kadane_algorithm.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/data_structures/array/kadane_algorithm.py b/data_structures/array/kadane_algorithm.py index f2fee2d3..19824af5 100644 --- a/data_structures/array/kadane_algorithm.py +++ b/data_structures/array/kadane_algorithm.py @@ -1,3 +1,12 @@ +""" +Kadane's algorithm is used to find the maximum contiguous sum in an array. +The logic is simple. Take the first element in the sum and then find current max num. +Curr max = max(arr[i], curr_max + arr[i]) - we add this number if it increases the sum, +otherwise we take the number if it is more than the sum + +Then keep track of max of this value +""" + def max_sum(arr): max_so_far = arr[0] curr_max = arr[0] From 9220f3ec5739e70ca3ae38cfa2e5d1d366338a9d Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 26 Aug 2021 16:34:01 +0530 Subject: [PATCH 284/302] add comments --- data_structures/array/number_of_1_in_sorted_array.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/data_structures/array/number_of_1_in_sorted_array.py b/data_structures/array/number_of_1_in_sorted_array.py index 79689872..bfcfda50 100644 --- a/data_structures/array/number_of_1_in_sorted_array.py +++ b/data_structures/array/number_of_1_in_sorted_array.py @@ -1,4 +1,8 @@ -# The array is sorted in decreasing order +""" +Count the number of 1s in a sorted array +Instead of linearly searching the array to find the first occurence, +do a binary search to find the first 0 +""" def count(arr): start = 0 From 7bb1eb02fa933d8508594df1a20a0e1794317768 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 26 Aug 2021 16:35:49 +0530 Subject: [PATCH 285/302] Correct the logic --- .../number_of_elements_that_can_searched_using_binary_search.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/array/number_of_elements_that_can_searched_using_binary_search.py b/data_structures/array/number_of_elements_that_can_searched_using_binary_search.py index b1889522..9137db3c 100644 --- a/data_structures/array/number_of_elements_that_can_searched_using_binary_search.py +++ b/data_structures/array/number_of_elements_that_can_searched_using_binary_search.py @@ -9,7 +9,7 @@ So maintain two arrays - left_max and right_min such that in i'th index - * left_max[i] contains the max element between 0 and i-1 (left to right movement) -* right_min[i] contains the min element between n-1 and i+1 (right to left movement) +* right_min[i] contains the min element between i+1 and n-1 (right to left movement) Now for every element in the array, if its index its i, then it is binary searchable if left_max[i] < arr[i] < right_min[i] From f6beedd2f3cbc116b7b07a05a261faf6846d9e5f Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Fri, 27 Aug 2021 12:04:29 +0530 Subject: [PATCH 286/302] adjust formatting --- .../largest_rectangle_area_in_histogram.py | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/data_structures/stack/largest_rectangle_area_in_histogram.py b/data_structures/stack/largest_rectangle_area_in_histogram.py index bee42b5b..86ac073d 100644 --- a/data_structures/stack/largest_rectangle_area_in_histogram.py +++ b/data_structures/stack/largest_rectangle_area_in_histogram.py @@ -1,8 +1,7 @@ ''' Largest rectangle area in a histogram:: -Find the largest rectangular area possible in a given histogram where the largest rectangle can be made of a number of contiguous bars. For simplicity, assume that all bars have same width and the width is 1 unit. - - +Find the largest rectangular area possible in a given histogram where the largest rectangle can be made of a number of contiguous bars. +For simplicity, assume that all bars have same width and the width is 1 unit. ''' def max_area_histogram(histogram): @@ -12,36 +11,30 @@ def max_area_histogram(histogram): max_area = 0 # Initialize max area index = 0 - while index < len(histogram): - + + while index < len(histogram): if (not stack) or (histogram[stack[-1]] <= histogram[index]): stack.append(index) index += 1 - - else: - top_of_stack = stack.pop() - area = (histogram[top_of_stack] * ((index - stack[-1] - 1) if stack else index)) - max_area = max(max_area, area) while stack: - top_of_stack = stack.pop() - area = (histogram[top_of_stack] * ((index - stack[-1] - 1) if stack else index)) max_area = max(max_area, area) - return max_area + + hist = [4, 7, 1, 8, 4, 9, 5] print("Maximum area is", - max_area_histogram(hist)) +max_area_histogram(hist)) From f81517515b5f6911c2fecd7abd7f062141d982a2 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Sat, 4 Sep 2021 18:40:47 +0530 Subject: [PATCH 287/302] refactored --- .../stack/largest_rectangle_area_in_histogram.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/data_structures/stack/largest_rectangle_area_in_histogram.py b/data_structures/stack/largest_rectangle_area_in_histogram.py index 86ac073d..6aa55947 100644 --- a/data_structures/stack/largest_rectangle_area_in_histogram.py +++ b/data_structures/stack/largest_rectangle_area_in_histogram.py @@ -19,16 +19,12 @@ def max_area_histogram(histogram): index += 1 else: top_of_stack = stack.pop() - area = (histogram[top_of_stack] * - ((index - stack[-1] - 1) - if stack else index)) + area = (histogram[top_of_stack] * ((index - stack[-1] - 1) if stack else index)) max_area = max(max_area, area) while stack: top_of_stack = stack.pop() - area = (histogram[top_of_stack] * - ((index - stack[-1] - 1) - if stack else index)) + area = (histogram[top_of_stack] * ((index - stack[-1] - 1) if stack else index)) max_area = max(max_area, area) From 2cfccd1a7e8476f8f1eb30ca17d9f83036929756 Mon Sep 17 00:00:00 2001 From: sterben04 Date: Mon, 4 Oct 2021 21:02:55 +0530 Subject: [PATCH 288/302] Added unique-char-check --- data_structures/strings/unique_char_check.py | 24 ++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 data_structures/strings/unique_char_check.py diff --git a/data_structures/strings/unique_char_check.py b/data_structures/strings/unique_char_check.py new file mode 100644 index 00000000..3af3083c --- /dev/null +++ b/data_structures/strings/unique_char_check.py @@ -0,0 +1,24 @@ +""" +Question +You are given a string S, check if all characters are unique. + +SAMPLE INPUT 1 +abcd +SAMPLE OUTPUT 1 +True + +SAMPLE INPUT 2 +aabc +SAMPLE OUTPUT 2 +False +""" +from collections import Counter +def unique_char_check(S): + character_count = Counter(S) + + if len(character_count) == len(S): + return True + return False + +S = input() +print(unique_char_check(S)) \ No newline at end of file From 565278fc4a63213684c73bef2b99feeccd69f09e Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Fri, 15 Oct 2021 12:10:50 +0530 Subject: [PATCH 289/302] Remove init from data structures --- data_structures/__init__.py | 1 - 1 file changed, 1 deletion(-) delete mode 100644 data_structures/__init__.py diff --git a/data_structures/__init__.py b/data_structures/__init__.py deleted file mode 100644 index 8b137891..00000000 --- a/data_structures/__init__.py +++ /dev/null @@ -1 +0,0 @@ - From dde44bc8d0e740a83a3b08f754d3ae86dff9ea3b Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Fri, 15 Oct 2021 12:13:44 +0530 Subject: [PATCH 290/302] remove init from algorithms dir --- algorithms/__init__.py | 1 - 1 file changed, 1 deletion(-) delete mode 100644 algorithms/__init__.py diff --git a/algorithms/__init__.py b/algorithms/__init__.py deleted file mode 100644 index 8b137891..00000000 --- a/algorithms/__init__.py +++ /dev/null @@ -1 +0,0 @@ - From f4b55227e97e4a8dacd43e4694099d57995d0424 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Sun, 24 Oct 2021 08:48:28 +0530 Subject: [PATCH 291/302] Update License full name --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1286c6c4..fc10b02b 100644 --- a/README.md +++ b/README.md @@ -69,4 +69,4 @@ To follow the guidelines, refer to [Contributing.md](CONTRIBUTING.md) ## License -[MIT](LICENSE) +[MIT License](LICENSE) From 99dfc16d82aea6bdfdc1aff4d77cc52664912d56 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Sun, 24 Oct 2021 08:50:24 +0530 Subject: [PATCH 292/302] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fc10b02b..7c05260f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Python Data Structures and Algorithms -No non-sense solutions to common Data Structure and Algorithm interview questions in Python. +No non-sense solutions to common Data Structure and Algorithm interview questions in Python. Follows a consistent approach throughout problems. ## Objective From 6b7ad5611109697873e5b6000b907f9cd8c01c5c Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Thu, 7 Apr 2022 09:52:48 +0530 Subject: [PATCH 293/302] Add WebSockets vs XMPP --- bookmarks/articles.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bookmarks/articles.md b/bookmarks/articles.md index 81c00863..ccdd64e2 100644 --- a/bookmarks/articles.md +++ b/bookmarks/articles.md @@ -57,3 +57,5 @@ This is a list of articles that may be useful for algorithms and data structures - https://jwt.io/introduction/ - https://khashtamov.com/en/how-to-become-a-data-engineer/ + +- https://blog.mirrorfly.com/xmpp-vs-websockets-instant-messaging-protocol-comparison/ From 6d7079c5d922d905ca1c0f8bc9a4ca366e7dd1d2 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 4 Oct 2022 06:57:20 +0530 Subject: [PATCH 294/302] Added comments --- data_structures/bst/average_of_levels.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/data_structures/bst/average_of_levels.py b/data_structures/bst/average_of_levels.py index 5028cf58..273c18d6 100644 --- a/data_structures/bst/average_of_levels.py +++ b/data_structures/bst/average_of_levels.py @@ -1,3 +1,7 @@ +""" +Find the mathematical average of all levels of a BST +""" + import collections class Node(): From b971f2a931ed4850727c1441353fe1294cecd1ac Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 4 Oct 2022 06:58:19 +0530 Subject: [PATCH 295/302] Update check_circular_linked_list.py --- .../circular_linked_list/check_circular_linked_list.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/data_structures/circular_linked_list/check_circular_linked_list.py b/data_structures/circular_linked_list/check_circular_linked_list.py index 6a72e6e7..4da76507 100644 --- a/data_structures/circular_linked_list/check_circular_linked_list.py +++ b/data_structures/circular_linked_list/check_circular_linked_list.py @@ -1,3 +1,7 @@ +""" +Check if a linked list is a circular linked list +""" + class Node(): def __init__(self, val): From f835c9a71361d5cbba995df926b08ae980cb52c5 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 4 Oct 2022 06:58:41 +0530 Subject: [PATCH 296/302] Delete index.md --- data_structures/doubly_linked_list/index.md | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 data_structures/doubly_linked_list/index.md diff --git a/data_structures/doubly_linked_list/index.md b/data_structures/doubly_linked_list/index.md deleted file mode 100644 index 0a7d6f6d..00000000 --- a/data_structures/doubly_linked_list/index.md +++ /dev/null @@ -1,3 +0,0 @@ -# Index of doubly_linked_list - -* [Doubly Linked List](doubly_linked_list.py) From a21f390fc06b0432bda509b5199335075a593723 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 4 Oct 2022 06:59:30 +0530 Subject: [PATCH 297/302] Rename Adjacency_matrix.py to adjacency_matrix.py --- .../graphs/{Adjacency_matrix.py => adjacency_matrix.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename data_structures/graphs/{Adjacency_matrix.py => adjacency_matrix.py} (100%) diff --git a/data_structures/graphs/Adjacency_matrix.py b/data_structures/graphs/adjacency_matrix.py similarity index 100% rename from data_structures/graphs/Adjacency_matrix.py rename to data_structures/graphs/adjacency_matrix.py From f3305bc4c55f02c69e1d03f50be0472bb30f6d89 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Mon, 1 Apr 2024 19:33:02 +0530 Subject: [PATCH 298/302] Fix infinite array search --- data_structures/array/binary_search_infinite_array.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_structures/array/binary_search_infinite_array.py b/data_structures/array/binary_search_infinite_array.py index 6eff9207..1db83e07 100644 --- a/data_structures/array/binary_search_infinite_array.py +++ b/data_structures/array/binary_search_infinite_array.py @@ -23,7 +23,7 @@ def search(arr, val): high = 1 while temp < val: - low = 0 + low = high high = 2 * high temp = arr[high] From f17ce1b59f23feb58778491151b095c4c52e6013 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 2 Apr 2024 11:06:54 +0530 Subject: [PATCH 299/302] Some fixes --- data_structures/array/duplicate.py | 12 ++++++------ data_structures/array/find_given_sum_in_array.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/data_structures/array/duplicate.py b/data_structures/array/duplicate.py index 1e4f6291..4838b1aa 100644 --- a/data_structures/array/duplicate.py +++ b/data_structures/array/duplicate.py @@ -17,13 +17,13 @@ def duplicate(arr): if tortoise == hare: break - ptr1 = arr[0] - ptr2 = tortoise - while ptr1 != ptr2: - ptr1 = arr[ptr1] - ptr2 = arr[ptr2] + tortoise = arr[0] + + while tortoise != hare: + tortoise = arr[tortoise] + hare = arr[hare] - return ptr1 + return hare arr = [3,5,1,2,4,5] diff --git a/data_structures/array/find_given_sum_in_array.py b/data_structures/array/find_given_sum_in_array.py index 0aacc5b4..e3adcfcb 100644 --- a/data_structures/array/find_given_sum_in_array.py +++ b/data_structures/array/find_given_sum_in_array.py @@ -24,4 +24,4 @@ def find_sum(arr, s): arr = [15, 2, 4, 8, 9, 5, 10, 23] -print(find_sum(arr, 6)) +print(find_sum(arr, 6)) \ No newline at end of file From ef23195057a1721eea41d39e0bdbd4c52b5640ea Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Tue, 2 Apr 2024 15:49:12 +0530 Subject: [PATCH 300/302] Small fixes --- data_structures/array/peak_element.py | 3 +-- data_structures/array/square_of_sorted_array.py | 5 +++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/data_structures/array/peak_element.py b/data_structures/array/peak_element.py index 29d8b1f2..ded661b0 100644 --- a/data_structures/array/peak_element.py +++ b/data_structures/array/peak_element.py @@ -6,8 +6,7 @@ def peak(arr, low, high): n = len(arr) while low <= high: - mid = low + (high - low) / 2 - mid = int(mid) + mid = (high - low) // 2 if (mid == 0 or arr[mid-1] <= arr[mid]) and (mid == n-1 or arr[mid+1] <= arr[mid]): return(arr[mid]) diff --git a/data_structures/array/square_of_sorted_array.py b/data_structures/array/square_of_sorted_array.py index 1bebb758..68f196b9 100644 --- a/data_structures/array/square_of_sorted_array.py +++ b/data_structures/array/square_of_sorted_array.py @@ -1,3 +1,8 @@ +""" +Find the square of all the numbers of a sorted array such that after finding the square of the sorted array, the +resultant array containing the squared numbers remains sorted +""" + def square(arr): n = len(arr) j = 0 From 27124b9b77a18a2d3e89c262311286a1d9c2910c Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Fri, 5 Apr 2024 15:51:52 +0530 Subject: [PATCH 301/302] Convert camelCase to snake_case --- data_structures/deque/deque.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data_structures/deque/deque.py b/data_structures/deque/deque.py index d578c8e2..85c7dd2c 100644 --- a/data_structures/deque/deque.py +++ b/data_structures/deque/deque.py @@ -47,7 +47,7 @@ def get_last(self): def size(self): return len(self.data) - def isEmpty(self): + def is_empty(self): if len(self.data) == 0: return True return False @@ -59,7 +59,7 @@ def contains(self, elem): return False - def printElems(self): + def print_elements(self): result = "" for i in self.data: From 35d3556a992ceccc5b925afa892fae3ba01a0e81 Mon Sep 17 00:00:00 2001 From: Prabhu Pant Date: Sat, 6 Apr 2024 13:13:16 +0530 Subject: [PATCH 302/302] Add comments --- data_structures/linked_list/delete_last_occurrence.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/data_structures/linked_list/delete_last_occurrence.py b/data_structures/linked_list/delete_last_occurrence.py index e76f1d9a..80951ab0 100644 --- a/data_structures/linked_list/delete_last_occurrence.py +++ b/data_structures/linked_list/delete_last_occurrence.py @@ -1,3 +1,7 @@ +""" +Delete last occurence of a number in linked list. +""" + class Node(): def __init__(self, val):