├── .gitignore ├── Bit_Manipulation ├── Check_Pow_2.cpp ├── Check_Pow_2.py ├── Count_Bits_Flip_A_B.cpp ├── Count_Bits_Flip_A_B.py ├── Find_Non_Repeating.cpp ├── Find_Non_Repeating.py ├── Next_Number.cpp └── Next_Number.py ├── DynamicProgramming ├── 01_KnapsackProblem.py ├── CuttingRod.py ├── EditDistance.py ├── LargestSquareInMatrix.py ├── LongestCommonSubsequence.py ├── LongestIncreasingSubsequence.py ├── MinCostPath.py ├── MinUmbrellaNeeded.cpp ├── MinUmbrellaNeeded.py ├── MinimumPartition.py ├── SubsetSum.py ├── TheMaximumSubarray.py └── WaysToCoverDistance.py ├── Graph ├── Boggle.py ├── BreadthFirstTraversal.py ├── DepthFirstTraversal.py ├── DetectCycleDirected.py ├── DetectCycleUndirected.py ├── DijkstraShortestPath.py ├── FloydWarshall_AllPairsShortestPath.py ├── Graph.py ├── KruskalMST.py └── TopologicalSort.py ├── Heaps ├── HeapSort.py ├── MaxHeap.py ├── MinHeap.py └── RunningMedian.py ├── LICENSE ├── LinkedList ├── CloneRandomPointerList.py ├── LineRemoveMiddlePoints.py ├── MaxSumLinkedList.py ├── MergeAlt.py ├── MergeSort.py ├── MiddleNode.cpp ├── MiddleNode.py ├── NextHigerValueNode.py ├── NullOrCycle.py ├── Random_Node.py ├── RemoveCycle.cpp ├── RemoveCycle.py ├── ReverseKNodes.cpp ├── ReverseKNodes.py ├── ReverseSLL.cpp ├── ReverseSLL.py ├── Reverse_Alt_K_Nodes.cpp ├── Reverse_Alt_K_Nodes.py ├── SegregateEvenOdd.py ├── SinglyLinkedList.cpp ├── SinglyLinkedList.py ├── SkipMDeleteN.cpp └── SkipMDeleteN.py ├── Mathematics ├── Factorial_Trailing_Zeros.cpp ├── Factorial_Trailing_Zeros.py ├── GCD.py ├── Prime_factors.py └── Sieve_of_Eratosthenes.py ├── Matrix ├── CheckQueenThreatsKing.py ├── SearchRowColumnSorted.py └── SpiralPrint.py ├── Misc └── Flatten_Dictionary.py ├── README.md ├── String_or_Array ├── KMP_StringMatching.py ├── K_Unique_Substring.py ├── Kth_Smallest.py ├── PairSum_is_X.py ├── ParenthesesCombinations.py ├── Searching │ ├── Binary_Search.py │ ├── Interpolation_Search.py │ └── Linear_Search.py ├── Sentence_Reverse.py ├── Shifted_Array_Search.py ├── Sorting │ ├── Bubble_Sort.py │ ├── Counting_Sort.py │ ├── Insertion_Sort.py │ ├── K_Messed_Sort.py │ ├── Merge_Sort.py │ ├── Quick_Sort.py │ └── Selection_Sort.py └── StringPermutations.py └── Tree ├── BinarySearchTree ├── BST.py ├── Check_Correct_Preorder.py ├── InOrder_Ancestor.py ├── Lowest_Common_Ancestor.py └── Minimal_Tree.py ├── BinaryTree ├── Bottom_View.py ├── Check_Balanced.py ├── Check_Full_BinaryTree.py ├── Is_SubTree.py ├── List_Of_Depths.py ├── Lowest_Common_Ancestor.py ├── Max_Path_Sum.py ├── Minimum_height.py ├── Remove_Path_Less_Than_K.py ├── Reverse_Alternate_Levels_PBT.py └── Top_View.py └── Trie └── Trie.py /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | **.pyc 3 | 4 | **.out 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /Bit_Manipulation/Check_Pow_2.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Check whether a given number n is a power of 2 3 | */ 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | bool check_pow_2(int num) { 10 | // num is a power of 2 only if its binary representation has one bit as 1. 11 | if ((num & (num-1)) == 0) 12 | return true; 13 | return false; 14 | } 15 | 16 | int main() { 17 | int num = 2; 18 | 19 | check_pow_2(num) ? cout << num << " is a Power of 2" : cout << num << " is not a power of 2"; 20 | cout << endl; 21 | 22 | num = 5; 23 | check_pow_2(num) ? cout << num << " is a Power of 2" : cout << num << " is not a power of 2"; 24 | cout << endl; 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /Bit_Manipulation/Check_Pow_2.py: -------------------------------------------------------------------------------- 1 | # Check whether a given number n is a power of 2 or 0 2 | 3 | 4 | def check_pow_2(num): 5 | if num == 0: 6 | return 0 7 | 8 | if num & (num - 1) == 0: 9 | return 1 10 | 11 | return -1 12 | 13 | 14 | switch = { 15 | 0: "Number is 0", 16 | 1: "Number is a power of 2", 17 | -1: "Number is neither a power of 2 nor 0" 18 | } 19 | case = check_pow_2(16) 20 | 21 | print(switch[case]) 22 | -------------------------------------------------------------------------------- /Bit_Manipulation/Count_Bits_Flip_A_B.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Count number of bits needed to be flipped to convert from A to B. 3 | */ 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | int count_bits_flip(int a, int b){ 10 | // Perform a xor b 11 | int c = a ^ b; 12 | 13 | int count = 0; 14 | 15 | // count number of 1s in c 16 | while (c != 0){ 17 | c &= (c-1); 18 | count += 1; 19 | } 20 | 21 | return count; 22 | } 23 | 24 | int main(){ 25 | int a = 15; // 15 = (1111) 26 | int b = 2; // 2 = (0010) 27 | cout << "Number of bits needed to be flipped to convert from " << a << 28 | " to " << b << " = " << count_bits_flip(a, b) << endl; 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /Bit_Manipulation/Count_Bits_Flip_A_B.py: -------------------------------------------------------------------------------- 1 | # Count number of bits needed to be flipped to convert A to B 2 | 3 | 4 | def count_bits_flip(a, b): 5 | # XOR a and b to get 1 on opposite value bit position 6 | c = a ^ b 7 | 8 | # initialise the counter for 1 9 | count = 0 10 | 11 | # count the number of 1s while there is 1 in a ^ b 12 | while c != 0: 13 | count += 1 14 | c &= (c-1) 15 | 16 | # return the count of 1s 17 | return count 18 | 19 | 20 | # 2 = 0010 21 | # 8 = 1000 22 | print(count_bits_flip(2, 8)) 23 | -------------------------------------------------------------------------------- /Bit_Manipulation/Find_Non_Repeating.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Find the two non-repeating elements in an array of repeating elements 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | pair< int, int > find_non_repeating_numbers(vector &arr) { 12 | pair< int, int > result = {0,0}; 13 | 14 | if (arr.size() == 0) 15 | return result; 16 | 17 | int xor_all = 0; 18 | 19 | // if non repeating elements are 'a' and 'b' ;xor_all = a^b 20 | for (auto element : arr) { 21 | xor_all ^= element; 22 | } 23 | 24 | // number with one set bit of xor_all 25 | int right_set_bit = xor_all & ~(xor_all - 1); 26 | 27 | for (auto element : arr) { 28 | if (element & right_set_bit) 29 | result.first ^= element; 30 | else 31 | result.second ^= element; 32 | } 33 | 34 | return result; 35 | } 36 | 37 | int main() { 38 | 39 | vector arr = {2, 3, 7, 9, 11, 2, 3, 11}; 40 | 41 | pair result = find_non_repeating_numbers(arr); 42 | 43 | cout << result.first << " " << result.second << endl; 44 | 45 | return 0; 46 | } -------------------------------------------------------------------------------- /Bit_Manipulation/Find_Non_Repeating.py: -------------------------------------------------------------------------------- 1 | # Find the two non-repeating elements in an array of repeating elements 2 | 3 | 4 | def find_non_repeating_numbers(arr): 5 | xor = arr[0] 6 | 7 | for i in range(1, len(arr)): 8 | xor ^= arr[i] 9 | 10 | right_set_bit = xor & ~(xor-1) 11 | first = 0 12 | second = 0 13 | for i in arr: 14 | if i & right_set_bit: 15 | first ^= i 16 | else: 17 | second ^= i 18 | 19 | return first, second 20 | 21 | 22 | arr = [2, 3, 7, 9, 11, 2, 3, 11] 23 | print(find_non_repeating_numbers(arr)) 24 | -------------------------------------------------------------------------------- /Bit_Manipulation/Next_Number.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Find the next greater and next smaller number with same number of set bits 3 | */ 4 | #include 5 | 6 | using namespace std; 7 | 8 | // Ex. num = 6 bin = 110 9 | int next_greater(int num) { 10 | 11 | int res = num; 12 | 13 | // at least one set bit 14 | if (num != 0) { 15 | // Find the right most 1 pos 16 | // Ex. right_one = 2 bin = 10 17 | int right_one = num & -num; 18 | 19 | int left_pattern = num + right_one; 20 | 21 | int right_pattern = (num ^ left_pattern) >> (right_one + 1); 22 | 23 | res = left_pattern | right_pattern; 24 | } 25 | 26 | return res; 27 | } 28 | 29 | int previous_smaller(int num) { 30 | return ~next_greater(~num); 31 | } 32 | int main() { 33 | 34 | cout << next_greater(6) << endl; 35 | cout << previous_smaller(6) << endl; 36 | 37 | return 0; 38 | } -------------------------------------------------------------------------------- /Bit_Manipulation/Next_Number.py: -------------------------------------------------------------------------------- 1 | # Find the next greater and next smaller number with same number of set bits 2 | 3 | # Ex. num = 6 bin = 110 4 | def next_greater(num): 5 | res = num 6 | if num != 0: 7 | # Find the right most 1 position 8 | # Ex. right_one = 2 bin = 10 9 | right_one = num & -num 10 | 11 | # get the left pattern to merge 12 | # Ex. left_pattern = 8 bin = 1000 13 | left_pattern = num + right_one 14 | 15 | # get the right patten to merge 16 | # Ex. right_pattern = 1 bin = 0001 17 | right_pattern = (num ^ left_pattern) >> (right_one + 1) 18 | 19 | # OR both the patterns 20 | # Ex. res = 9 bin = 1001 21 | res = left_pattern | right_pattern 22 | 23 | return res 24 | 25 | 26 | def next_smaller(num): 27 | return ~next_greater(~num) 28 | 29 | 30 | print(next_greater(6)) 31 | print(next_smaller(6)) 32 | -------------------------------------------------------------------------------- /DynamicProgramming/01_KnapsackProblem.py: -------------------------------------------------------------------------------- 1 | """Given weights and values of n items, put these items in a knapsack of capacity W to get 2 | the maximum total value in the knapsack. In other words, given two integer arrays val[0..n-1] 3 | and wt[0..n-1] which represent values and weights associated with n items respectively. Also 4 | given an integer W which represents knapsack capacity, find out the maximum value subset of val[] 5 | such that sum of the weights of this subset is smaller than or equal to W. You cannot break an item, 6 | either pick the complete item, or don’t pick it (0-1 property).""" 7 | 8 | 9 | def knapSack(W, wt, val, size): 10 | k = [[0 for i in range(W+1)] for i in range(size+1)] 11 | for i in range(size+1): 12 | for w in range(W+1): 13 | if i == 0 or w == 0: 14 | k[i][w] = 0 15 | elif wt[i-1] <= w: 16 | k[i][w] = max(val[i-1] + k[i-1][w-wt[i-1]], k[i-1][w]) 17 | else: 18 | k[i][w] = k[i-1][w] 19 | 20 | for w in k: 21 | print(w) 22 | 23 | return k 24 | 25 | 26 | # def findElementsInSack(W, matrix, wt, val, size): 27 | # i = size 28 | # row = W 29 | # arr = [] 30 | # while i > 0: 31 | # print(matrix[i][row] - matrix[i-1][row - wt[i-1]] ) 32 | # print(val[i-1]) 33 | # if matrix[i][row] - matrix[i-1][row - wt[i-1]] == val[i-1]: 34 | # arr.append(val[i-1]) 35 | # i -= 1 36 | # row -= wt[i-1] 37 | # else: 38 | # i -= 1 39 | # 40 | # return arr 41 | 42 | price = [60, 100, 120] 43 | wt = [1, 2, 3] 44 | W = 5 45 | n = len(price) 46 | k = knapSack(W, wt, price, n) 47 | print(k[n][W]) 48 | # print(findElementsInSack(W, k, wt, price, n)) 49 | -------------------------------------------------------------------------------- /DynamicProgramming/CuttingRod.py: -------------------------------------------------------------------------------- 1 | """Given a rod of length n inches and an array of prices that contains prices of all pieces of size smaller than n. 2 | Determine the maximum value obtainable by cutting up the rod and selling the pieces.""" 3 | 4 | 5 | def cutting_rod(prices, n): 6 | dp = [0 for i in range(n+1)] 7 | dp[0] = 0 8 | 9 | for i in range(1, n+1): 10 | max_val = -float('inf') 11 | for j in range(i): 12 | max_val = max(max_val, prices[j] + dp[i-j-1]) 13 | dp[i] = max_val 14 | 15 | return dp[n] 16 | 17 | 18 | if __name__ == '__main__': 19 | arr = [1, 5, 8, 9, 10, 17, 17, 20] 20 | size = len(arr) 21 | print("Maximum Obtainable Value is " + str(cutting_rod(arr, size))) 22 | -------------------------------------------------------------------------------- /DynamicProgramming/EditDistance.py: -------------------------------------------------------------------------------- 1 | """Given two strings str1 and str2 and below operations that can performed on str1. Find minimum number of edits (operations) required 2 | to convert ‘str1’ into ‘str2’. 3 | 4 | Insert 5 | Remove 6 | Replace 7 | All of the above operations are of equal cost. 8 | Example: 9 | Input: str1 = "sunday", str2 = "saturday" 10 | Output: 3 11 | Last three and first characters are same. We basically 12 | need to convert "un" to "atur". This can be done using 13 | below three operations. 14 | Replace 'n' with 'r', insert t, insert a""" 15 | 16 | 17 | def edit_distance(str1, str2, m, n): 18 | matrix = [[0 for i in range(n+1)] for i in range(m+1)] 19 | 20 | for i in range(m+1): 21 | for j in range(n+1): 22 | 23 | if i == 0: 24 | matrix[i][j] = j 25 | 26 | elif j == 0: 27 | matrix[i][j] = i 28 | 29 | elif str1[i-1] == str2[j-1]: 30 | matrix[i][j] = matrix[i-1][j-1] 31 | 32 | else: 33 | matrix[i][j] = 1 + min(matrix[i][j-1], # insert 34 | matrix[i-1][j], # remove 35 | matrix[i-1][j-1]) # replace 36 | 37 | return matrix[m][n] 38 | 39 | 40 | if __name__ == '__main__': 41 | str1 = 'sunday' 42 | str2 = 'saturday' 43 | 44 | print(edit_distance(str1, str2, len(str1), len(str2))) -------------------------------------------------------------------------------- /DynamicProgramming/LargestSquareInMatrix.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a 2-D matrix of 0s and 1s, find the Largest Square which contains all 1s in itself. 3 | """ 4 | 5 | 6 | def find_largest_square(matrix): 7 | n = len(matrix) 8 | 9 | # make a matrix for storing the solutions 10 | cache = [[0] * n for _ in range(n)] 11 | # size of square and its bottom-right indexes 12 | size = 0 13 | right_indx = -1 14 | bottom_indx = -1 15 | 16 | for i in range(n): 17 | for j in range(n): 18 | 19 | # if the value is 0 simply move forward as it cannot form a square of 1s 20 | if matrix[i][j] == 0: 21 | continue 22 | 23 | # if it is first row or column, copy the matrix values as it is 24 | elif i == 0 or j == 0: 25 | cache[i][j] = matrix[i][j] 26 | 27 | # Otherwise, check in the up, left, and diagonally top-left direction for minimum size of square 28 | # if all are 1s at these positions in matrix, only then min value will be greater than 1 29 | # hence add the previous square size to the cache + 1 30 | else: 31 | cache[i][j] = 1 + min(cache[i - 1][j], cache[i][j - 1], cache[i - 1][j - 1]) 32 | 33 | # check if the current square size found is larger than the previously found size, if so, update it 34 | if cache[i][j] > size: 35 | size = cache[i][j] 36 | bottom_indx, right_indx = i, j 37 | 38 | return size, bottom_indx, right_indx 39 | 40 | 41 | mat = [[1, 1, 0, 1, 0], 42 | [0, 1, 1, 1, 0], 43 | [1, 1, 1, 1, 0], 44 | [0, 1, 1, 1, 1]] 45 | size, bottom, right = find_largest_square(mat) 46 | 47 | if size > 0: 48 | print("Size of the square:", size) 49 | print("Top-left Co-ordinates:", bottom-size+1, ",", right-size+1) 50 | print("Bottom-right Co-ordinates:", bottom, ",", right) 51 | else: 52 | print("No square of 1s found") 53 | -------------------------------------------------------------------------------- /DynamicProgramming/LongestCommonSubsequence.py: -------------------------------------------------------------------------------- 1 | """find the length of longest subsequence present in both of them. 2 | A subsequence is a sequence that appears in the same relative order, but not necessarily contiguous. 3 | Examples: 4 | LCS for input Sequences “ABCDGH” and “AEDFHR” is “ADH” of length 3. 5 | LCS for input Sequences “AGGTAB” and “GXTXAYB” is “GTAB” of length 4.""" 6 | 7 | 8 | def lcs(str1, str2): 9 | m = len(str1) 10 | n = len(str2) 11 | 12 | matrix = [[0 for i in range(n+1)] for i in range(m+1)] 13 | 14 | for i in range(1, m+1): 15 | for j in range(1, n+1): 16 | 17 | if i == 0 or j == 0: 18 | matrix[i][j] = 0 19 | 20 | elif str1[i-1] == str2[j-1]: 21 | matrix[i][j] = 1 + matrix[i-1][j-1] 22 | 23 | else: 24 | matrix[i][j] = max(matrix[i-1][j], matrix[i][j-1]) 25 | 26 | index = matrix[m][n] 27 | 28 | res = [""] * index 29 | i = m 30 | j = n 31 | 32 | while i > 0 and j > 0: 33 | if str1[i-1] == str2[j-1]: 34 | res[index-1] = str1[i-1] 35 | i -= 1 36 | j -= 1 37 | index -= 1 38 | 39 | elif matrix[i-1][j] > matrix[i][j-1]: 40 | i -= 1 41 | else: 42 | j -= 1 43 | 44 | return res 45 | 46 | 47 | if __name__ == '__main__': 48 | X = "AGGTAB" 49 | Y = "GXTXAYB" 50 | 51 | str = ''.join(lcs(X, Y)) 52 | 53 | print("Length of longest common subsequence is:", len(str),"\nAnd the subsequence is:", str) -------------------------------------------------------------------------------- /DynamicProgramming/LongestIncreasingSubsequence.py: -------------------------------------------------------------------------------- 1 | """ 2 | Find the length of the longest subsequence of a given sequence such that all elements of the subsequence are sorted 3 | in increasing order. 4 | For example, the length of LIS for {10, 22, 9, 33, 21, 50, 41, 60, 80} is 6 and LIS is {10, 22, 33, 50, 60, 80}. 5 | """ 6 | 7 | 8 | def lis(arr): 9 | n = len(arr) 10 | dp = [1] * n 11 | 12 | for i in range(n): 13 | for j in range(i): 14 | if arr[j] < arr[i] and dp[j] + 1 > dp[i]: 15 | dp[i] = 1 + dp[j] 16 | 17 | return max(dp) 18 | 19 | 20 | arr = [10, 22, 9, 33, 21, 50, 41, 60, 80] 21 | print(lis(arr)) 22 | -------------------------------------------------------------------------------- /DynamicProgramming/MinCostPath.py: -------------------------------------------------------------------------------- 1 | """Given a cost matrix cost[][] and a position (m, n) in cost[][], 2 | write a function that returns cost of minimum cost path to reach (m, n) from (0, 0). 3 | Total cost of a path to reach (m, n) is sum of all the costs on that path (including both source and destination). 4 | You can only traverse down, right and diagonally lower cells from a given cell""" 5 | 6 | 7 | def min_cost(cost, m, n): 8 | dp = [[0 for i in range(n+1)] for i in range(m+1)] 9 | 10 | dp[0][0] = cost[0][0] 11 | 12 | for i in range(1, m+1): 13 | dp[i][0] = dp[i-1][0] + cost[i][0] 14 | 15 | for j in range(1, n+1): 16 | dp[0][j] = dp[0][j-1] + cost[0][j] 17 | 18 | for i in range(1, m+1): 19 | for j in range(1, n+1): 20 | dp[i][j] = cost[i][j] + min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) 21 | 22 | return dp[m][n] 23 | 24 | 25 | if __name__ == '__main__': 26 | cost = [[1, 2, 3], 27 | [4, 8, 2], 28 | [1, 5, 3]] 29 | m = 2 30 | n = 2 31 | print("Minimum cost from (0, 0) to ({}, {}) is:".format(m, n), min_cost(cost, m, n)) 32 | -------------------------------------------------------------------------------- /DynamicProgramming/MinUmbrellaNeeded.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Given N number of people and M different types of unlimited umbrellas. 3 | Each mi in M denotes the exact number of people (mi), the ith umbrella type can accomodate. 4 | Find out the minimum number of umbrellas needed to accomodate all the N people. 5 | if such a case is not possible then return -1. 6 | 7 | Each umbrella has to fill exactly the number of people it can accomodate. 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | int min_umbrellas_needed_util(int n, vector umbrellas, vector dp, int count){ 16 | // if dp has already stored the solution for n people, return 17 | if(n == 0 || dp[n] != 0) return dp[n]; 18 | 19 | int min_count = INT_MAX, curr_count; 20 | 21 | // Iterate over all the umbrella sizes 22 | for(auto i = umbrellas.begin(); i != umbrellas.end(); i++){ 23 | 24 | // if umbrella can be accommodated fully 25 | if(n - *i > 0) 26 | curr_count = min_umbrellas_needed_util(n-*i, umbrellas, dp, count+1); 27 | 28 | // if all people are accommodated 29 | else if(n - *i == 0) 30 | curr_count = count+1; 31 | 32 | // if the umbrella cannot get exact number of people to fit 33 | else 34 | curr_count = INT_MAX; 35 | 36 | if(curr_count < min_count) 37 | min_count = curr_count; 38 | } 39 | 40 | // memoize result 41 | dp[n] = min_count; 42 | 43 | return min_count; 44 | } 45 | 46 | int min_umbrellas_needed(int n, vector umbrellas){ 47 | // initialize a dp table for memoization 48 | vector dp(n+1, 0); 49 | 50 | int count = min_umbrellas_needed_util(n, umbrellas, dp, 0); 51 | 52 | if(count == INT_MAX) return -1; 53 | return count; 54 | } 55 | 56 | int main() { 57 | vector umbrellas{5,4,2,1}; 58 | int n = 8; 59 | 60 | cout <<"Number of umbrellas needed to accomodate " << n << " people: " << min_umbrellas_needed(n, umbrellas) << endl; 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /DynamicProgramming/MinUmbrellaNeeded.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given N number of people and M different types of unlimited umbrellas. 3 | Each mi in M denotes the exact number of people (mi), the ith umbrella type can accomodate. 4 | Find out the minimum number of umbrellas needed to accomodate all the N people. 5 | if such a case is not possible then return -1. 6 | 7 | Each umbrella has to fill exactly the number of people it can accomodate. 8 | """ 9 | 10 | def min_umbrellas_needed_util(n, umbrellas, dp, count): 11 | # if dp has already stored the solution for n people, return 12 | if n == 0 or dp[n] != 0: 13 | return dp[n] 14 | 15 | min_count = float('inf') 16 | curr_count = None 17 | 18 | # Iterate over all the umbrella sizes 19 | for m in umbrellas: 20 | # if umbrella can be accomodated fully 21 | if n - m > 0: 22 | curr_count = min_umbrellas_needed_util(n-m, umbrellas, dp, count+1) 23 | 24 | # if all people are accomodated 25 | elif n - m == 0: 26 | curr_count = count+1 27 | 28 | # if the umbrella cannot get exact number of people to fit 29 | else: 30 | curr_count = float('inf') 31 | 32 | if curr_count < min_count: 33 | min_count = curr_count 34 | 35 | # memoize result 36 | dp[n] = min_count 37 | 38 | return min_count 39 | 40 | 41 | def min_umbrellas_needed(n, umbrellas): 42 | # initialize a dp table for memoization 43 | dp = [0] * (n+1) 44 | 45 | count = min_umbrellas_needed_util(n, umbrellas, dp, 0) 46 | 47 | if count == float('inf'): 48 | return -1 49 | 50 | return count 51 | 52 | umbrellas = [5,4,2,1] 53 | n = 8 54 | 55 | print(f"Number of umbrellas needed to accomodate {n} people: {min_umbrellas_needed(n, umbrellas)}") 56 | 57 | -------------------------------------------------------------------------------- /DynamicProgramming/MinimumPartition.py: -------------------------------------------------------------------------------- 1 | # Partition a set into two subsets such that the difference of subset sums is minimum 2 | 3 | 4 | def find_min(arr): 5 | sum_of_arr = sum(arr) 6 | n = len(arr) 7 | dp = [[False for i in range(sum_of_arr+1)] for i in range(n+1)] 8 | 9 | for i in range(n+1): 10 | dp[i][0] = True 11 | 12 | for i in range(1, sum_of_arr+1): 13 | dp[0][i] = False 14 | 15 | for i in range(1, n+1): 16 | for j in range(1, sum_of_arr+1): 17 | dp[i][j] = dp[i-1][j] 18 | 19 | if arr[i-1] <= j: 20 | dp[i][j] |= dp[i-1][j - arr[i-1]] 21 | 22 | diff = float('inf') 23 | 24 | for j in range(int(sum_of_arr/2), -1, -1): 25 | if dp[n][j] is True: 26 | diff = sum_of_arr - 2 * j 27 | break 28 | 29 | return diff 30 | 31 | 32 | if __name__ == '__main__': 33 | arr = [3, 1, 4, 2, 2, 1] 34 | print("Minimum difference is:", find_min(arr)) -------------------------------------------------------------------------------- /DynamicProgramming/SubsetSum.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a set of non-negative integers, and a value sum, 3 | determine if there is a subset of the given set with sum equal to given sum. 4 | """ 5 | 6 | 7 | def isSubsetSum(arr, check_sum): 8 | n = len(arr) 9 | possible_sum = [[False] * (n + 1) for _ in range(check_sum + 1)] 10 | 11 | for i in range(n+1): 12 | possible_sum[0][i] = True 13 | 14 | for i in range(1, check_sum + 1): 15 | for j in range(1, n + 1): 16 | if i < arr[j - 1]: 17 | possible_sum[i][j] = possible_sum[i][j-1] 18 | elif i >= arr[j - 1]: 19 | possible_sum[i][j] = possible_sum[i][j-1] or possible_sum[i - arr[j - 1]][j-1] 20 | 21 | return possible_sum[check_sum][n] 22 | 23 | 24 | arr = [3, 34, 4, 12, 5, 2] 25 | check_sum = 9 26 | 27 | if isSubsetSum(arr, check_sum): 28 | print("Found a subset with sum =", check_sum) 29 | else: 30 | print("Subset with sum =", check_sum, "Not Found") 31 | 32 | 33 | -------------------------------------------------------------------------------- /DynamicProgramming/TheMaximumSubarray.py: -------------------------------------------------------------------------------- 1 | # HackerRank problem Algorithms DP 2 | 3 | 4 | def maxSubArray(a, size): 5 | currMax = a[0] 6 | maxSoFar = a[0] 7 | 8 | for i in range(1, size): 9 | currMax = max(a[i], currMax + a[i]) 10 | maxSoFar = max(currMax, maxSoFar) 11 | 12 | return maxSoFar 13 | 14 | 15 | testcases = int(input()) 16 | 17 | for t in range(testcases): 18 | n = int(input()) 19 | arr = list(map(int, input().split())) 20 | tempList = list(filter(lambda x: x > 0, arr)) 21 | if len(tempList) != 0: 22 | maximumSum = sum(tempList) 23 | else: 24 | maximumSum = max(arr) 25 | print(maxSubArray(arr, n), maximumSum) 26 | -------------------------------------------------------------------------------- /DynamicProgramming/WaysToCoverDistance.py: -------------------------------------------------------------------------------- 1 | """Given a distance ‘dist, count total number of ways to cover the distance with 1, 2 and 3 steps 2 | Input: n = 3 3 | Output: 4 4 | Below are the four ways 5 | 1 step + 1 step + 1 step 6 | 1 step + 2 step 7 | 2 step + 1 step 8 | 3 step""" 9 | 10 | 11 | def count_ways(n): 12 | count = [0] * (n+1) 13 | count[0] = 1 14 | count[1] = 1 15 | count[2] = 2 16 | 17 | for i in range(3, n+1): 18 | count[i] = count[i-1] + count[i-2] + count[i-3] 19 | 20 | return count[n] 21 | 22 | 23 | if __name__ == '__main__': 24 | print(count_ways(4)) 25 | -------------------------------------------------------------------------------- /Graph/Boggle.py: -------------------------------------------------------------------------------- 1 | # Find all possible words in a board of characters 2 | """Input: dictionary[] = {"GEEKS", "FOR", "QUIZ", "GO"}; 3 | boggle[][] = {{'G','I','Z'}, 4 | {'U','E','K'}, 5 | {'Q','S','E'}}; 6 | Output: Following words of dictionary are present 7 | GEEKS 8 | QUIZ 9 | """ 10 | 11 | 12 | def findWordsUtil(words, boggle, visited, found, r, c, str): 13 | rows = len(boggle) 14 | cols = len(boggle[0]) 15 | 16 | # set the position of character as traversed 17 | visited[r][c] = True 18 | 19 | # add the character to string 20 | str += boggle[r][c] 21 | 22 | # if the string is in dictionary add it to the set of found words 23 | if str in words: 24 | found.add(str) 25 | 26 | # traverse all the nearby 8 adjacent cells 27 | for i in range(r-1, r+2): 28 | for j in range(c-1, c+2): 29 | if i >= rows or i < 0 or j >= cols or j < 0 or visited[i][j]: 30 | continue 31 | findWordsUtil(words, boggle, visited, found, i, j, str) 32 | 33 | # backtrack and set the status of current character as not traversed 34 | visited[r][c] = False 35 | 36 | 37 | def findWords(words, boggle): 38 | rows = len(boggle) 39 | cols = len(boggle[0]) 40 | 41 | # initialize a matrix for DFS Traversal 42 | visited = [[False for i in range(cols)] for j in range(rows)] 43 | 44 | # set to store the unique found words 45 | found = set({}) 46 | str = "" 47 | 48 | # traverse each character in the boggle and do DFS from there 49 | for r in range(rows): 50 | for c in range(cols): 51 | findWordsUtil(words, boggle, visited, found, r, c, str) 52 | 53 | # return the set of found words 54 | return found 55 | 56 | if __name__ == '__main__': 57 | words = {"GEEKS", "FOR", "QUIZ", "GO", "SEEK"} 58 | boggle = [['G', 'I', 'Z'], 59 | ['U', 'E', 'K'], 60 | ['Q', 'S', 'E']] 61 | 62 | found = findWords(words, boggle) 63 | 64 | print("Words found in the boggle from the dictionary are:") 65 | for word in found: 66 | print(word) 67 | -------------------------------------------------------------------------------- /Graph/BreadthFirstTraversal.py: -------------------------------------------------------------------------------- 1 | # Program to perform breadth first traversal in a graph 2 | from collections import defaultdict, deque 3 | 4 | 5 | class Graph: 6 | def __init__(self, directed=False): 7 | self.graph = defaultdict(list) 8 | self.directed = directed 9 | 10 | def addEdge(self, frm, to): 11 | self.graph[frm].append(to) 12 | 13 | if self.directed is False: 14 | self.graph[to].append(frm) 15 | else: 16 | self.graph[to] = self.graph[to] 17 | 18 | def bfsUtil(self, s, visited): 19 | queue = deque([]) 20 | queue.append(s) 21 | visited[s] = True 22 | 23 | while queue: 24 | vertex = queue.popleft() 25 | print(vertex, end=' ') 26 | 27 | # traverse vertices adjacent to vertex 28 | for i in self.graph[vertex]: 29 | if not visited[i]: 30 | visited[i] = True 31 | queue.append(i) 32 | print() 33 | 34 | def bfs(self, s=None): 35 | visited = {i: False for i in self.graph} 36 | 37 | # do bfs from the node specified 38 | if s is not None: 39 | self.bfsUtil(s, visited) 40 | # traverse for all the vertices in other components of graph 41 | for v in self.graph: 42 | if not visited[v]: 43 | self.bfsUtil(v, visited) 44 | 45 | 46 | 47 | if __name__ == '__main__': 48 | graph = Graph() 49 | 50 | # component 1 of the graph 51 | graph.addEdge(0, 1) 52 | graph.addEdge(0, 2) 53 | graph.addEdge(1, 2) 54 | graph.addEdge(2, 3) 55 | graph.addEdge(3, 3) 56 | graph.addEdge(1, 4) 57 | graph.addEdge(1, 5) 58 | graph.addEdge(3, 6) 59 | 60 | # component 2 of the graph 61 | graph.addEdge(7, 8) 62 | graph.addEdge(8, 9) 63 | graph.addEdge(7, 10) 64 | 65 | # call bfs from 2 vertex 66 | print("Breadth First Traversal:") 67 | graph.bfs(2) 68 | 69 | -------------------------------------------------------------------------------- /Graph/DepthFirstTraversal.py: -------------------------------------------------------------------------------- 1 | # Program to perform depth first traversal in a graph 2 | from collections import defaultdict 3 | 4 | 5 | class Graph: 6 | def __init__(self, directed=False): 7 | self.graph = defaultdict(list) 8 | self.directed = directed 9 | 10 | def addEdge(self, frm, to): 11 | self.graph[frm].append(to) 12 | 13 | if self.directed is False: 14 | self.graph[to].append(frm) 15 | else: 16 | self.graph[to] = self.graph[to] 17 | 18 | def dfsUtil(self, s, visited): 19 | stack = [] 20 | stack.append(s) 21 | visited[s] = True 22 | 23 | while stack: 24 | vertex = stack.pop() 25 | print(vertex, end=' ') 26 | 27 | # traverse vertices adjacent to vertex 28 | for i in self.graph[vertex]: 29 | if not visited[i]: 30 | visited[i] = True 31 | stack.append(i) 32 | print() 33 | 34 | def dfs(self, s=None): 35 | visited = {i: False for i in self.graph} 36 | 37 | # traverse specified vertex 38 | if s is not None: 39 | self.dfsUtil(s, visited) 40 | 41 | # traverse for all the vertices in other components of graph 42 | for v in self.graph: 43 | if not visited[v]: 44 | self.dfsUtil(v, visited) 45 | 46 | 47 | if __name__ == '__main__': 48 | # make an undirected graph 49 | graph = Graph() 50 | 51 | # component 1 of the graph 52 | graph.addEdge(0, 1) 53 | graph.addEdge(0, 2) 54 | graph.addEdge(1, 2) 55 | graph.addEdge(2, 3) 56 | graph.addEdge(3, 3) 57 | graph.addEdge(1, 4) 58 | graph.addEdge(1, 5) 59 | graph.addEdge(3, 6) 60 | 61 | # component 2 of the graph 62 | graph.addEdge(7, 8) 63 | graph.addEdge(8, 9) 64 | graph.addEdge(7, 10) 65 | 66 | # call dfs from 2 vertex 67 | print("Depth First Traversal:") 68 | graph.dfs(2) 69 | 70 | -------------------------------------------------------------------------------- /Graph/DetectCycleDirected.py: -------------------------------------------------------------------------------- 1 | # Program to detect cycle or loop in a directed graph 2 | from collections import defaultdict 3 | 4 | 5 | class Graph: 6 | def __init__(self, directed=False): 7 | self.graph = defaultdict(list) 8 | self.directed = directed 9 | 10 | def addEdge(self, frm, to): 11 | self.graph[frm].append(to) 12 | 13 | if self.directed is False: 14 | self.graph[to].append(frm) 15 | else: 16 | self.graph[to] = self.graph[to] 17 | 18 | def isCyclicUtil(self, s, visited, recurStack): 19 | 20 | if visited[s] is False: 21 | recurStack[s] = True 22 | visited[s] = True 23 | 24 | # traverse vertices adjacent to vertex 25 | for i in self.graph[s]: 26 | if (not visited[i]) and self.isCyclicUtil(i, visited, recurStack): 27 | return True 28 | elif recurStack[i]: 29 | return True 30 | recurStack[s] = False 31 | return False 32 | 33 | def isCyclic(self): 34 | visited = {i: False for i in self.graph} 35 | recurStack = {i: False for i in self.graph} 36 | 37 | # traverse for all the vertices of graph 38 | for v in self.graph: 39 | if self.isCyclicUtil(v, visited, recurStack): 40 | return True 41 | return False 42 | 43 | 44 | if __name__ == '__main__': 45 | # make a directed graph 46 | graph = Graph(True) 47 | 48 | graph.addEdge(0, 1) 49 | graph.addEdge(0, 2) 50 | graph.addEdge(1, 2) 51 | graph.addEdge(2, 0) 52 | graph.addEdge(2, 3) 53 | graph.addEdge(3, 3) 54 | 55 | if graph.isCyclic(): 56 | print("Cycle exists") 57 | else: 58 | print("No cycle in the graph") 59 | 60 | -------------------------------------------------------------------------------- /Graph/DetectCycleUndirected.py: -------------------------------------------------------------------------------- 1 | # Program to detect cycle or loop in a graph 2 | from collections import defaultdict 3 | 4 | 5 | class Graph: 6 | def __init__(self, directed=False): 7 | self.graph = defaultdict(list) 8 | self.directed = directed 9 | 10 | def addEdge(self, frm, to): 11 | # True if edge has been traversed or seen once 12 | self.graph[frm].append([to, False]) 13 | 14 | if self.directed is False: 15 | self.graph[to].append([frm, False]) 16 | else: 17 | self.graph[to] = self.graph[to] 18 | 19 | def findParent(self, sets, v): 20 | if sets[v] == -1: 21 | return v 22 | else: 23 | return self.findParent(sets, sets[v]) 24 | 25 | def union(self, sets, x, y): 26 | x_set = self.findParent(sets, x) 27 | y_set = self.findParent(sets, y) 28 | sets[x_set] = y_set 29 | 30 | def isCyclic(self): 31 | # sets that show combined vertices or not 32 | sets = {i: -1 for i in self.graph} 33 | 34 | for v in self.graph: 35 | for e in self.graph[v]: 36 | # if an edge is traversed once skip it 37 | if e[1] is True: 38 | continue 39 | 40 | # set True for traversing the edge and making union in both adjacency lists 41 | e[1] = True 42 | 43 | for i in self.graph[e[0]]: 44 | if i[0] == v: 45 | i[1] = True 46 | break 47 | 48 | # find parents of both vertices of the edge 49 | x = self.findParent(sets, v) 50 | y = self.findParent(sets, e[0]) 51 | 52 | # if they share a common parent loop found 53 | if x == y: 54 | return True 55 | # union the two vertices in the same set 56 | self.union(sets, x, y) 57 | 58 | # if no loop or cycle found return false 59 | return False 60 | 61 | 62 | if __name__ == '__main__': 63 | # make a graph 64 | graph = Graph() 65 | graph.addEdge(0, 1) 66 | graph.addEdge(1, 2) 67 | graph.addEdge(2, 0) 68 | 69 | if graph.isCyclic(): 70 | print("Cycle exists in the graph") 71 | else: 72 | print("No cycle in the graph") 73 | 74 | -------------------------------------------------------------------------------- /Graph/DijkstraShortestPath.py: -------------------------------------------------------------------------------- 1 | # Given a graph and a source vertex in graph, find shortest paths from source to all vertices in the given graph 2 | from collections import defaultdict 3 | 4 | 5 | class Graph: 6 | def __init__(self, directed=False): 7 | self.graph = defaultdict(list) 8 | self.directed = directed 9 | 10 | def addEdge(self, frm, to, weight): 11 | self.graph[frm].append([to, weight]) 12 | 13 | if self.directed is False: 14 | self.graph[to].append([frm, weight]) 15 | else: 16 | self.graph[to] = self.graph[to] 17 | 18 | def find_min(self, dist, visited): 19 | minimum = float('inf') 20 | index = -1 21 | for v in self.graph.keys(): 22 | if visited[v] is False and dist[v] < minimum: 23 | minimum = dist[v] 24 | index = v 25 | 26 | return index 27 | 28 | def dijkstra(self, src): 29 | visited = {i: False for i in self.graph} 30 | dist = {i: float('inf') for i in self.graph} 31 | parent = {i: None for i in self.graph} 32 | 33 | # set distance of src vertex from itself 0 34 | dist[src] = 0 35 | 36 | # find shortest path for all vertices 37 | for i in range(len(self.graph)-1): 38 | # find minimum distance vertex from source 39 | # initially src itself as dist[src] = 0 40 | u = self.find_min(dist, visited) 41 | 42 | # mark the node as visited 43 | visited[u] = True 44 | # check if the distance through current edge is less than previously known distance to v 45 | for v, w in self.graph[u]: 46 | 47 | if visited[v] is False and dist[u] + w < dist[v]: 48 | dist[v] = dist[u] + w 49 | parent[v] = u 50 | # return parent list and distance to each node from source 51 | return parent, dist 52 | 53 | def printPath(self, parent, v): 54 | if parent[v] is None: 55 | return 56 | self.printPath(parent, parent[v]) 57 | print(v, end=' ') 58 | 59 | def printSolution(self, dist, parent, src): 60 | print('{}\t{}\t{}'.format('Vertex', 'Distance', 'Path')) 61 | 62 | for i in self.graph.keys(): 63 | if i == src: 64 | continue 65 | print('{} -> {}\t\t{}\t\t{}'.format(src, i, dist[i], src), end=' ') 66 | self.printPath(parent, i) 67 | print() 68 | 69 | if __name__ == '__main__': 70 | # make an undirected graph 71 | graph = Graph() 72 | 73 | graph.addEdge(0, 1, 4) 74 | graph.addEdge(0, 7, 8) 75 | graph.addEdge(1, 2, 8) 76 | graph.addEdge(1, 7, 11) 77 | graph.addEdge(7, 6, 1) 78 | graph.addEdge(7, 8, 7) 79 | graph.addEdge(6, 8, 6) 80 | graph.addEdge(6, 5, 2) 81 | graph.addEdge(8, 2, 2) 82 | graph.addEdge(2, 3, 7) 83 | graph.addEdge(2, 5, 4) 84 | graph.addEdge(3, 4, 9) 85 | graph.addEdge(3, 5, 14) 86 | graph.addEdge(5, 4, 10) 87 | 88 | parent, dist = graph.dijkstra(0) 89 | 90 | graph.printSolution(dist, parent, 0) 91 | 92 | 93 | -------------------------------------------------------------------------------- /Graph/FloydWarshall_AllPairsShortestPath.py: -------------------------------------------------------------------------------- 1 | # Find shortest distances between every pair of vertices in a given edge weighted directed Graph 2 | """ 3 | 10 4 | (0)------->(3) 5 | | /|\ 6 | 5 | | 7 | | | 1 8 | \|/ | 9 | (1)------->(2) 10 | 3 11 | """ 12 | 13 | 14 | def floyd_warshall(graph): 15 | shortest_dist = [] 16 | 17 | # copy matrix for storing resultant shortest distances 18 | for i in graph: 19 | shortest_dist.append(i) 20 | 21 | # Number of vertices in graph 22 | V = len(graph) - 1 23 | 24 | # k is intermediate vertex 25 | for k in range(V+1): 26 | # i is source 27 | for i in range(V+1): 28 | # j is destination 29 | for j in range(V+1): 30 | # store the path which is shorter i.e. min(i->j, i->k->j) 31 | shortest_dist[i][j] = min(shortest_dist[i][j], shortest_dist[i][k] + shortest_dist[k][j]) 32 | # return the resultant matrix 33 | return shortest_dist 34 | 35 | if __name__ == '__main__': 36 | INF = float('inf') 37 | graph = [[0, 5, INF, 10], 38 | [INF, 0, 3, INF], 39 | [INF, INF, 0, 1], 40 | [INF, INF, INF, 0]] 41 | 42 | shortest_dist_matrix = floyd_warshall(graph) 43 | 44 | for i in shortest_dist_matrix: 45 | for j in i: 46 | if j != float('inf'): 47 | print(j, '\t', end='') 48 | else: 49 | print(j, end=' ') 50 | print() 51 | -------------------------------------------------------------------------------- /Graph/Graph.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | class Vertex: 4 | def __init__(self, key): 5 | self.key = key 6 | self.adjacent = {} 7 | self.visited = False 8 | 9 | def setKey(self, key): 10 | self.key = key 11 | 12 | def getKey(self): 13 | return self.key 14 | 15 | def getVisited(self): 16 | return self.visited 17 | 18 | def setVisited(self, val=True): 19 | self.visited = val 20 | 21 | def addNeighbour(self, neighbour, weight=0): 22 | self.adjacent[neighbour] = weight 23 | 24 | def getNeighbours(self): 25 | return self.adjacent.keys() 26 | 27 | def getWeight(self, neighbour): 28 | return self.adjacent[neighbour] 29 | 30 | 31 | class Graph: 32 | 33 | # Graph is undirected by default 34 | def __init__(self, directed=False): 35 | self.vertices = {} 36 | self.numberOfVertices = 0 37 | self.directed = directed 38 | 39 | def addVertex(self, key): 40 | node = Vertex(key) 41 | self.vertices[key] = node 42 | self.numberOfVertices += 1 43 | return node 44 | 45 | def addEdge(self, frm, to, weight=0): 46 | if frm not in self.vertices: 47 | self.addVertex(frm) 48 | 49 | if to not in self.vertices: 50 | self.addVertex(to) 51 | 52 | self.vertices[frm].addNeighbour(self.vertices[to], weight) 53 | 54 | if not self.directed: 55 | self.vertices[to].addNeighbour(self.vertices[frm], weight) 56 | 57 | def getVertex(self, key): 58 | if key in self.vertices: 59 | return self.vertices[key] 60 | else: 61 | return None 62 | 63 | def getVertices(self): 64 | return self.vertices.keys() 65 | 66 | def getEdges(self): 67 | edges = [] 68 | for v in self.vertices: 69 | edgesFromVertex = [] 70 | 71 | for w in self.vertices[v].getNeighbours(): 72 | frm = self.vertices[v].getKey() 73 | to = w.getKey() 74 | weight = self.vertices[v].getWeight(w) 75 | edgesFromVertex.append((frm, to, weight)) 76 | 77 | if len(edgesFromVertex) != 0: 78 | edges.append(edgesFromVertex) 79 | 80 | return edges 81 | 82 | 83 | if __name__ == '__main__': 84 | g = Graph(directed=False) 85 | g.addVertex('a') 86 | g.addVertex('b') 87 | g.addVertex('c') 88 | g.addVertex('d') 89 | g.addVertex('e') 90 | g.addVertex('f') 91 | g.addEdge('a', 'b', 3) 92 | g.addEdge('b', 'c', 2) 93 | g.addEdge('c', 'd', 1) 94 | g.addEdge('d', 'e', 5) 95 | g.addEdge('d', 'a', 5) 96 | g.addEdge('d', 'a', 2) 97 | g.addEdge('e', 'f', 3) 98 | g.addEdge('f', 'a', 6) 99 | g.addEdge('f', 'b', 6) 100 | g.addEdge('f', 'c', 6) 101 | 102 | for edgeSet in g.getEdges(): 103 | print('edges from', edgeSet[0][0] + ': ', end='') 104 | print(edgeSet) -------------------------------------------------------------------------------- /Graph/KruskalMST.py: -------------------------------------------------------------------------------- 1 | # Kruskal’s Minimum Spanning Tree Algorithm 2 | 3 | 4 | class Graph: 5 | def __init__(self, directed=False): 6 | self.edges = [] 7 | self.vertices = set({}) 8 | self.directed = directed 9 | 10 | def addEdge(self, frm, to, weight): 11 | self.edges.append([frm, to, weight]) 12 | self.vertices.add(frm) 13 | self.vertices.add(to) 14 | 15 | def removeEdge(self, frm, to, weight): 16 | self.edges.remove([frm, to, weight]) 17 | flag1 = 0 18 | flag2 = 0 19 | for f, t, w in self.edges: 20 | if frm == f or frm == t: 21 | flag1 = 1 22 | if to == f or to == t: 23 | flag2 = 1 24 | if flag1 == 1 and flag2 == 1: 25 | break 26 | 27 | if flag1 != 1: 28 | self.vertices.remove(frm) 29 | 30 | if flag2 != 1: 31 | self.vertices.remove(to) 32 | 33 | def findParent(self, sets, v): 34 | if sets[v] == -1: 35 | return v 36 | else: 37 | return self.findParent(sets, sets[v]) 38 | 39 | def union(self, sets, x, y): 40 | x_set = self.findParent(sets, x) 41 | y_set = self.findParent(sets, y) 42 | sets[x_set] = y_set 43 | 44 | def isCyclic(self): 45 | # sets that show combined vertices or not 46 | sets = {i: -1 for i in self.vertices} 47 | for v1, v2, w in self.edges: 48 | # find parents of both vertices of the edge 49 | x = self.findParent(sets, v1) 50 | y = self.findParent(sets, v2) 51 | 52 | # if they share a common parent loop found 53 | if x == y: 54 | return True 55 | # union the two vertices in the same set 56 | self.union(sets, x, y) 57 | 58 | # if no loop or cycle found return false 59 | return False 60 | 61 | def kruskalMST(self): 62 | g = Graph() 63 | 64 | self.edges = sorted(self.edges, key=lambda x: x[2]) 65 | 66 | for frm, to, w in self.edges: 67 | if len(g.edges) == len(graph.vertices)-1: 68 | break 69 | g.addEdge(frm, to, w) 70 | if g.isCyclic(): 71 | g.removeEdge(frm, to, w) 72 | return g 73 | 74 | 75 | if __name__ == '__main__': 76 | # make an undirected graph 77 | graph = Graph() 78 | 79 | graph.addEdge(0, 1, 10) 80 | graph.addEdge(0, 2, 6) 81 | graph.addEdge(0, 3, 5) 82 | graph.addEdge(1, 3, 15) 83 | graph.addEdge(2, 3, 4) 84 | 85 | new_graph = graph.kruskalMST() 86 | 87 | for f, t, w in new_graph.edges: 88 | print(f, "--", t, "=", w) 89 | -------------------------------------------------------------------------------- /Graph/TopologicalSort.py: -------------------------------------------------------------------------------- 1 | # Program to perform topological sort in a graph 2 | 3 | from collections import defaultdict 4 | 5 | 6 | class Graph: 7 | def __init__(self, directed=False): 8 | self.graph = defaultdict(list) 9 | self.directed = directed 10 | 11 | def addEdge(self, frm, to): 12 | self.graph[frm].append(to) 13 | 14 | if self.directed is False: 15 | self.graph[to].append(frm) 16 | else: 17 | self.graph[to] = self.graph[to] 18 | 19 | def topoSortUtil(self, s, visited, sortList): 20 | visited[s] = True 21 | 22 | for i in self.graph[s]: 23 | if not visited[i]: 24 | self.topoSortUtil(i, visited, sortList) 25 | 26 | sortList.insert(0, s) 27 | 28 | def topologicalSort(self): 29 | visited = {i: False for i in self.graph} 30 | 31 | sortList = [] 32 | # traverse for all the vertices in other components of graph 33 | for v in self.graph: 34 | if not visited[v]: 35 | self.topoSortUtil(v, visited, sortList) 36 | 37 | print(sortList) 38 | 39 | 40 | if __name__ == '__main__': 41 | # make an directed graph 42 | g = Graph(directed=True) 43 | 44 | g.addEdge(5, 2) 45 | g.addEdge(5, 0) 46 | g.addEdge(4, 0) 47 | g.addEdge(4, 1) 48 | g.addEdge(2, 3) 49 | g.addEdge(3, 1) 50 | 51 | # call topologicalSort() 52 | print("Topological Sort:") 53 | g.topologicalSort() 54 | 55 | -------------------------------------------------------------------------------- /Heaps/HeapSort.py: -------------------------------------------------------------------------------- 1 | """Perform Sorting using a max heap in: 2 | O(n log n) time complexity 3 | O(1) space complexity""" 4 | 5 | 6 | def max_heapify(indx, arr, size): 7 | """ 8 | Assuming sub trees are already max heaps, converts tree rooted at current indx into a max heap. 9 | :param indx: Index to check for max heap 10 | :param arr: array of elements 11 | :param size: size of the array 12 | """ 13 | 14 | # Get index of left and right child of indx node 15 | left_child = indx * 2 + 1 16 | right_child = indx * 2 + 2 17 | 18 | largest = indx 19 | 20 | # check what is the largest value node in indx, left child and right child 21 | if left_child < size: 22 | if arr[left_child] > arr[largest]: 23 | largest = left_child 24 | if right_child < size: 25 | if arr[right_child] > arr[largest]: 26 | largest = right_child 27 | 28 | # if indx node is not the largest value, swap with the largest child 29 | # and recursively call max_heapify on the respective child swapped with 30 | if largest != indx: 31 | arr[indx], arr[largest] = arr[largest], arr[indx] 32 | max_heapify(largest, arr, size) 33 | 34 | 35 | def create_max_heap(arr): 36 | """ 37 | Converts a given array into a max heap 38 | :param arr: input array of numbers 39 | :return: output max heap 40 | """ 41 | n = len(arr) 42 | 43 | # last n/2 elements will be leaf nodes (CBT property) hence already max heaps 44 | # loop from n/2 to 0 index and convert each index node into max heap 45 | for i in range(int(n/2), -1, -1): 46 | max_heapify(i, arr, n) 47 | 48 | 49 | def heap_sort(arr): 50 | """ 51 | Sorts the given array using heap sort 52 | :param arr: input array to sort 53 | """ 54 | 55 | create_max_heap(arr) 56 | heap_size = len(arr) 57 | 58 | # Swap the max value in heap with the end of the array and decrease the size of the heap by 1 59 | # call max heapify on the 0th index of the array 60 | while heap_size > 1: 61 | arr[heap_size-1], arr[0] = arr[0], arr[heap_size-1] 62 | heap_size -= 1 63 | max_heapify(0, arr, heap_size) 64 | 65 | 66 | heap = [5, 10, 4, 8, 3, 0, 9, 11] 67 | heap_sort(heap) 68 | print(*heap) 69 | -------------------------------------------------------------------------------- /Heaps/MaxHeap.py: -------------------------------------------------------------------------------- 1 | """A max heap is a complete binary tree [CBT] (implemented using array) 2 | in which each node has a value larger than its sub-trees""" 3 | 4 | from math import ceil 5 | 6 | 7 | class MaxHeap: 8 | def __init__(self, arr=None): 9 | self.heap = [] 10 | self.heap_size = 0 11 | if arr is not None: 12 | self.create_max_heap(arr) 13 | self.heap = arr 14 | self.heap_size = len(arr) 15 | 16 | def create_max_heap(self, arr): 17 | """ 18 | Converts a given array into a max heap 19 | :param arr: input array of numbers 20 | """ 21 | n = len(arr) 22 | 23 | # last n/2 elements will be leaf nodes (CBT property) hence already max heaps 24 | # loop from n/2 to 0 index and convert each index node into max heap 25 | for i in range(int(n / 2), -1, -1): 26 | self.max_heapify(i, arr, n) 27 | 28 | def max_heapify(self, indx, arr, size): 29 | """ 30 | Assuming sub trees are already max heaps, converts tree rooted at current indx into a max heap. 31 | :param indx: Index to check for max heap 32 | """ 33 | 34 | # Get index of left and right child of indx node 35 | left_child = indx * 2 + 1 36 | right_child = indx * 2 + 2 37 | 38 | largest = indx 39 | 40 | # check what is the largest value node in indx, left child and right child 41 | if left_child < size: 42 | if arr[left_child] > arr[largest]: 43 | largest = left_child 44 | if right_child < size: 45 | if arr[right_child] > arr[largest]: 46 | largest = right_child 47 | 48 | # if indx node is not the largest value, swap with the largest child 49 | # and recursively call min_heapify on the respective child swapped with 50 | if largest != indx: 51 | arr[indx], arr[largest] = arr[largest], arr[indx] 52 | self.max_heapify(largest, arr, size) 53 | 54 | def insert(self, value): 55 | """ 56 | Inserts an element in the max heap 57 | :param value: value to be inserted in the heap 58 | """ 59 | self.heap.append(value) 60 | self.heap_size += 1 61 | 62 | indx = self.heap_size - 1 63 | 64 | # Get parent index of the current node 65 | parent = int(ceil(indx / 2 - 1)) 66 | 67 | # Check if the parent value is smaller than the newly inserted value 68 | # if so, then replace the value with the parent value and check with the new parent 69 | while parent >= 0 and self.heap[indx] > self.heap[parent]: 70 | self.heap[indx], self.heap[parent] = self.heap[parent], self.heap[indx] 71 | indx = parent 72 | parent = int(ceil(indx / 2 - 1)) 73 | 74 | def delete(self, indx): 75 | """ 76 | Deletes the value on the specified index node 77 | :param indx: index whose node is to be removed 78 | :return: Value of the node deleted from the heap 79 | """ 80 | if self.heap_size == 0: 81 | print("Heap Underflow!!") 82 | return 83 | 84 | self.heap[-1], self.heap[indx] = self.heap[indx], self.heap[-1] 85 | self.heap_size -= 1 86 | 87 | self.max_heapify(indx, self.heap, self.heap_size) 88 | 89 | return self.heap.pop() 90 | 91 | def extract_max(self): 92 | """ 93 | Extracts the maximum value from the heap 94 | :return: extracted max value 95 | """ 96 | return self.delete(0) 97 | 98 | def print(self): 99 | print(*self.heap) 100 | 101 | heap = MaxHeap([5, 10, 4, 8, 3, 0, 9, 11]) 102 | 103 | heap.insert(15) 104 | print(heap.delete(2)) 105 | print(heap.extract_max()) 106 | heap.print() 107 | -------------------------------------------------------------------------------- /Heaps/MinHeap.py: -------------------------------------------------------------------------------- 1 | """A Min heap is a complete binary tree [CBT] (implemented using array) 2 | in which each node has a value smaller than its sub-trees""" 3 | 4 | from math import ceil 5 | 6 | 7 | class MinHeap: 8 | def __init__(self, arr=None): 9 | self.heap = [] 10 | self.heap_size = 0 11 | if arr is not None: 12 | self.create_min_heap(arr) 13 | self.heap = arr 14 | self.heap_size = len(arr) 15 | 16 | def create_min_heap(self, arr): 17 | """ 18 | Converts a given array into a min heap 19 | :param arr: input array of numbers 20 | """ 21 | n = len(arr) 22 | 23 | # last n/2 elements will be leaf nodes (CBT property) hence already min heaps 24 | # loop from n/2 to 0 index and convert each index node into min heap 25 | for i in range(int(n / 2), -1, -1): 26 | self.min_heapify(i, arr, n) 27 | 28 | def min_heapify(self, indx, arr, size): 29 | """ 30 | Assuming sub trees are already min heaps, converts tree rooted at current indx into a min heap. 31 | :param indx: Index to check for min heap 32 | """ 33 | # Get index of left and right child of indx node 34 | left_child = indx * 2 + 1 35 | right_child = indx * 2 + 2 36 | 37 | smallest = indx 38 | 39 | # check what is the smallest value node in indx, left child and right child 40 | if left_child < size: 41 | if arr[left_child] < arr[smallest]: 42 | smallest = left_child 43 | if right_child < size: 44 | if arr[right_child] < arr[smallest]: 45 | smallest = right_child 46 | 47 | # if indx node is not the smallest value, swap with the smallest child 48 | # and recursively call min_heapify on the respective child swapped with 49 | if smallest != indx: 50 | arr[indx], arr[smallest] = arr[smallest], arr[indx] 51 | self.min_heapify(smallest, arr, size) 52 | 53 | def insert(self, value): 54 | """ 55 | Inserts an element in the min heap 56 | :param value: value to be inserted in the heap 57 | """ 58 | self.heap.append(value) 59 | self.heap_size += 1 60 | 61 | indx = self.heap_size - 1 62 | 63 | # Get parent index of the current node 64 | parent = int(ceil(indx / 2 - 1)) 65 | 66 | # Check if the parent value is smaller than the newly inserted value 67 | # if so, then replace the value with the parent value and check with the new parent 68 | while parent >= 0 and self.heap[indx] < self.heap[parent]: 69 | self.heap[indx], self.heap[parent] = self.heap[parent], self.heap[indx] 70 | indx = parent 71 | parent = int(ceil(indx / 2 - 1)) 72 | 73 | def delete(self, indx): 74 | """ 75 | Deletes the value on the specified index node 76 | :param indx: index whose node is to be removed 77 | :return: Value of the node deleted from the heap 78 | """ 79 | if self.heap_size == 0: 80 | print("Heap Underflow!!") 81 | return 82 | 83 | self.heap[-1], self.heap[indx] = self.heap[indx], self.heap[-1] 84 | self.heap_size -= 1 85 | 86 | self.min_heapify(indx, self.heap, self.heap_size) 87 | 88 | return self.heap.pop() 89 | 90 | def extract_min(self): 91 | """ 92 | Extracts the minimum value from the heap 93 | :return: extracted min value 94 | """ 95 | return self.delete(0) 96 | 97 | def print(self): 98 | print(*self.heap) 99 | 100 | 101 | heap = MinHeap([5, 10, 4, 8, 3, 0, 9, 11]) 102 | 103 | heap.insert(15) 104 | print(heap.delete(2)) 105 | print(heap.extract_min()) 106 | heap.print() 107 | -------------------------------------------------------------------------------- /Heaps/RunningMedian.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an input stream of integers, you must perform the following task for each i-th integer: 3 | 4 | 1. Add the i-th integer to a running list of integers. 5 | 2. Find the median of the updated list (i.e., for the first element through the i-th element). 6 | 3. Print the list's updated median on a new line. 7 | 8 | *) Input Format 9 | The first line contains a single integer, n, denoting the number of integers in the data stream. 10 | Each line i of the n subsequent lines contains an integer, ai, to be added to your list. 11 | *) Output Format 12 | After each new integer is added to the list, print the list's updated median on a new line. 13 | Example: 14 | Input: 15 | 6 16 | 12 17 | 4 18 | 5 19 | 3 20 | 8 21 | 7 22 | Output: 23 | 12.0 24 | 8.0 25 | 5.0 26 | 4.5 27 | 5.0 28 | 6.0 29 | Problem Link: https://www.hackerrank.com/challenges/ctci-find-the-running-median/problem 30 | """ 31 | 32 | """A max heap is a complete binary tree [CBT] (implemented using array) 33 | in which each node has a value larger than its sub-trees""" 34 | 35 | from math import ceil 36 | 37 | 38 | class MaxHeap: 39 | def __init__(self, arr=None): 40 | self.heap = [] 41 | self.heap_size = 0 42 | if arr is not None: 43 | self.create_max_heap(arr) 44 | self.heap = arr 45 | self.heap_size = len(arr) 46 | 47 | def create_max_heap(self, arr): 48 | """ 49 | Converts a given array into a max heap 50 | :param arr: input array of numbers 51 | """ 52 | n = len(arr) 53 | 54 | # last n/2 elements will be leaf nodes (CBT property) hence already max heaps 55 | # loop from n/2 to 0 index and convert each index node into max heap 56 | for i in range(int(n / 2), -1, -1): 57 | self.max_heapify(i, arr, n) 58 | 59 | def max_heapify(self, indx, arr, size): 60 | """ 61 | Assuming sub trees are already max heaps, converts tree rooted at current indx into a max heap. 62 | :param indx: Index to check for max heap 63 | """ 64 | 65 | # Get index of left and right child of indx node 66 | left_child = indx * 2 + 1 67 | right_child = indx * 2 + 2 68 | 69 | largest = indx 70 | 71 | # check what is the largest value node in indx, left child and right child 72 | if left_child < size: 73 | if arr[left_child] > arr[largest]: 74 | largest = left_child 75 | if right_child < size: 76 | if arr[right_child] > arr[largest]: 77 | largest = right_child 78 | 79 | # if indx node is not the largest value, swap with the largest child 80 | # and recursively call min_heapify on the respective child swapped with 81 | if largest != indx: 82 | arr[indx], arr[largest] = arr[largest], arr[indx] 83 | self.max_heapify(largest, arr, size) 84 | 85 | def insert(self, value): 86 | """ 87 | Inserts an element in the max heap 88 | :param value: value to be inserted in the heap 89 | """ 90 | self.heap.append(value) 91 | self.heap_size += 1 92 | 93 | indx = self.heap_size - 1 94 | 95 | # Get parent index of the current node 96 | parent = int(ceil(indx / 2 - 1)) 97 | 98 | # Check if the parent value is smaller than the newly inserted value 99 | # if so, then replace the value with the parent value and check with the new parent 100 | while parent >= 0 and self.heap[indx] > self.heap[parent]: 101 | self.heap[indx], self.heap[parent] = self.heap[parent], self.heap[indx] 102 | indx = parent 103 | parent = int(ceil(indx / 2 - 1)) 104 | 105 | def delete(self, indx): 106 | """ 107 | Deletes the value on the specified index node 108 | :param indx: index whose node is to be removed 109 | :return: Value of the node deleted from the heap 110 | """ 111 | if self.heap_size == 0: 112 | print("Heap Underflow!!") 113 | return 114 | 115 | self.heap[-1], self.heap[indx] = self.heap[indx], self.heap[-1] 116 | self.heap_size -= 1 117 | 118 | self.max_heapify(indx, self.heap, self.heap_size) 119 | 120 | return self.heap.pop() 121 | 122 | def extract_max(self): 123 | """ 124 | Extracts the maximum value from the heap 125 | :return: extracted max value 126 | """ 127 | return self.delete(0) 128 | 129 | def max(self): 130 | return self.heap[0] 131 | 132 | 133 | class MinHeap: 134 | def __init__(self, arr=None): 135 | self.heap = [] 136 | self.heap_size = 0 137 | if arr is not None: 138 | self.create_min_heap(arr) 139 | self.heap = arr 140 | self.heap_size = len(arr) 141 | 142 | def create_min_heap(self, arr): 143 | """ 144 | Converts a given array into a min heap 145 | :param arr: input array of numbers 146 | """ 147 | n = len(arr) 148 | 149 | # last n/2 elements will be leaf nodes (CBT property) hence already min heaps 150 | # loop from n/2 to 0 index and convert each index node into min heap 151 | for i in range(int(n / 2), -1, -1): 152 | self.min_heapify(i, arr, n) 153 | 154 | def min_heapify(self, indx, arr, size): 155 | """ 156 | Assuming sub trees are already min heaps, converts tree rooted at current indx into a min heap. 157 | :param indx: Index to check for min heap 158 | """ 159 | # Get index of left and right child of indx node 160 | left_child = indx * 2 + 1 161 | right_child = indx * 2 + 2 162 | 163 | smallest = indx 164 | 165 | # check what is the smallest value node in indx, left child and right child 166 | if left_child < size: 167 | if arr[left_child] < arr[smallest]: 168 | smallest = left_child 169 | if right_child < size: 170 | if arr[right_child] < arr[smallest]: 171 | smallest = right_child 172 | 173 | # if indx node is not the smallest value, swap with the smallest child 174 | # and recursively call min_heapify on the respective child swapped with 175 | if smallest != indx: 176 | arr[indx], arr[smallest] = arr[smallest], arr[indx] 177 | self.min_heapify(smallest, arr, size) 178 | 179 | def insert(self, value): 180 | """ 181 | Inserts an element in the min heap 182 | :param value: value to be inserted in the heap 183 | """ 184 | self.heap.append(value) 185 | self.heap_size += 1 186 | 187 | indx = self.heap_size - 1 188 | 189 | # Get parent index of the current node 190 | parent = int(ceil(indx / 2 - 1)) 191 | 192 | # Check if the parent value is smaller than the newly inserted value 193 | # if so, then replace the value with the parent value and check with the new parent 194 | while parent >= 0 and self.heap[indx] < self.heap[parent]: 195 | self.heap[indx], self.heap[parent] = self.heap[parent], self.heap[indx] 196 | indx = parent 197 | parent = int(ceil(indx / 2 - 1)) 198 | 199 | def delete(self, indx): 200 | """ 201 | Deletes the value on the specified index node 202 | :param indx: index whose node is to be removed 203 | :return: Value of the node deleted from the heap 204 | """ 205 | if self.heap_size == 0: 206 | print("Heap Underflow!!") 207 | return 208 | 209 | self.heap[-1], self.heap[indx] = self.heap[indx], self.heap[-1] 210 | self.heap_size -= 1 211 | 212 | self.min_heapify(indx, self.heap, self.heap_size) 213 | 214 | return self.heap.pop() 215 | 216 | def extract_min(self): 217 | """ 218 | Extracts the minimum value from the heap 219 | :return: extracted min value 220 | """ 221 | return self.delete(0) 222 | 223 | def min(self): 224 | return self.heap[0] 225 | 226 | 227 | """ 228 | Algorithm: 229 | *) Split the array stream in 2 halves, min heap(upper array) and max heap (lower array) 230 | *) This way the min and max of the heaps will help you get the median fast. 231 | *) Note that the elements should be inserted in the heaps in such a way that the elements 232 | in lowerMaxHeap are all smaller than all the elements in the upperMinHeap 233 | (i.e., as if the arrays were sorted and then split into two heaps) 234 | """ 235 | n = int(input()) 236 | upperMinHeap = MinHeap() 237 | lowerMaxHeap = MaxHeap() 238 | 239 | for a_i in range(1, n+1): 240 | a_t = int(input()) 241 | 242 | if lowerMaxHeap.heap_size == 0: # this case occurs only initially when both heaps are empty 243 | lowerMaxHeap.insert(a_t) 244 | else: 245 | # Take example stream 1,2,3,4,9,8,7,6,5 to understand the logic 246 | if upperMinHeap.heap_size == lowerMaxHeap.heap_size: 247 | if a_t > upperMinHeap.min(): 248 | temp = upperMinHeap.extract_min() 249 | lowerMaxHeap.insert(temp) 250 | upperMinHeap.insert(a_t) 251 | else: 252 | lowerMaxHeap.insert(a_t) 253 | elif a_t > lowerMaxHeap.max(): 254 | upperMinHeap.insert(a_t) 255 | else: 256 | temp = lowerMaxHeap.extract_max() 257 | upperMinHeap.insert(temp) 258 | lowerMaxHeap.insert(a_t) 259 | 260 | # print the median directly if odd number of elements 261 | # otherwise average of sum of min heap and max heap tops 262 | num = a_i / 2 263 | if int(num) != num: 264 | print(float(lowerMaxHeap.max())) 265 | else: 266 | print((lowerMaxHeap.max() + upperMinHeap.min()) / 2) 267 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Anubhav Shrimal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LinkedList/CloneRandomPointerList.py: -------------------------------------------------------------------------------- 1 | # Python program to Clone a linked list with next and random pointer 2 | 3 | 4 | # Node class 5 | class Node: 6 | 7 | # Constructor to initialise data and next 8 | def __init__(self, data=None): 9 | self.data = data 10 | self.next = None 11 | self.random = None 12 | 13 | class SinglyLinkedList: 14 | 15 | # Constructor to initialise head 16 | def __init__(self, head=None): 17 | self.head = None 18 | 19 | # Function to create copy the linked list 20 | def copy_list(self, l2): 21 | # if first list is empty return 22 | if self.head is None: 23 | return 24 | 25 | curr1 = self.head 26 | 27 | # insert new nodes with same data as linst at adjacent positions of each node 28 | while curr1 is not None: 29 | node = Node(curr1.data) 30 | temp = curr1.next 31 | curr1.next = node 32 | node.next = temp 33 | curr1 = temp 34 | 35 | curr1 = self.head 36 | # update the random pointers of even node to point to the random nodes of odd nodes next 37 | while curr1 is not None: 38 | if curr1.random is not None: 39 | curr1.next.random = curr1.random.next 40 | curr1 = curr1.next.next 41 | 42 | curr1 = self.head 43 | curr2 = l2.head 44 | # assign even nodes to the Copy linked list to make the new list 45 | # re-assign the old links of list 1 46 | while curr1 is not None: 47 | if l2.head is None: 48 | l2.head = curr1.next 49 | curr2 = l2.head 50 | else: 51 | curr2.next = curr1.next 52 | curr2 = curr2.next 53 | curr1.next = curr1.next.next 54 | curr2.next = None 55 | curr1 = curr1.next 56 | 57 | 58 | 59 | # Function to Insert data at the beginning of the linked list 60 | def insert_at_beg(self, data): 61 | node = Node(data) 62 | node.next = self.head 63 | self.head = node 64 | 65 | # Function to print the linked list 66 | def print_data(self): 67 | current = self.head 68 | # print data of each node 69 | while current is not None: 70 | print(current.data, '-> ', end='') 71 | current = current.next 72 | 73 | current = self.head 74 | print('None') 75 | while current is not None: 76 | print("V", ' ', end='') 77 | current = current.next 78 | 79 | current = self.head 80 | print() 81 | # print random pointer node's data of each node 82 | while current is not None: 83 | if current.random is not None: 84 | print(current.random.data, ' ', end='') 85 | else: 86 | print("N", ' ', end='') 87 | current = current.next 88 | print() 89 | 90 | if __name__ == '__main__': 91 | linked_list = SinglyLinkedList() 92 | # make nodes 93 | node1 = Node(1) 94 | node2 = Node(2) 95 | node3 = Node(3) 96 | node4 = Node(4) 97 | node5 = Node(5) 98 | # set next pointer of each node 99 | node1.next = node2 100 | node2.next = node3 101 | node3.next = node4 102 | node4.next = node5 103 | # set random pointer of each node 104 | node1.random = node3 105 | node2.random = node1 106 | node3.random = node5 107 | node4.random = node3 108 | node5.random = node2 109 | # assing the nodes list to head 110 | linked_list.head = node1 111 | 112 | # print the data of linked list 113 | print('original list:') 114 | linked_list.print_data() 115 | 116 | # make empty LL2 to copy data of LL1 in 117 | linked_list2 = SinglyLinkedList(Node()) 118 | 119 | # copy LL1 into LL2 120 | linked_list.copy_list(linked_list2) 121 | 122 | # print the copied linked list 123 | print('copied list:') 124 | linked_list2.print_data() -------------------------------------------------------------------------------- /LinkedList/LineRemoveMiddlePoints.py: -------------------------------------------------------------------------------- 1 | """Given a linked list of co-ordinates where adjacent points either form a vertical line or a horizontal line. 2 | Delete points from the linked list which are in the middle of a horizontal or vertical line.""" 3 | """Input: (0,10)->(1,10)->(5,10)->(7,10) 4 | | 5 | (7,5)->(20,5)->(40,5) 6 | Output: Linked List should be changed to following 7 | (0,10)->(7,10) 8 | | 9 | (7,5)->(40,5) """ 10 | 11 | 12 | # Node class 13 | class Node: 14 | 15 | # Constructor to initialise (x, y) coordinates and next 16 | def __init__(self, x=None, y=None): 17 | self.x = x 18 | self.y = y 19 | self.next = None 20 | 21 | 22 | class SinglyLinkedList: 23 | 24 | # Constructor to initialise head 25 | def __init__(self): 26 | self.head = None 27 | 28 | # Function to find middle node of a linked list 29 | def delete_middle_nodes(self): 30 | current = self.head 31 | 32 | # iterate while the next of the next node is not none 33 | while current and current.next and current.next.next is not None: 34 | # assign variables for next and next of next nodes 35 | next = current.next 36 | next_next = current.next.next 37 | 38 | # if x coordinates are equal of current and next node i.e. horizontal line 39 | if current.x == next.x: 40 | # check if there are more than 2 nodes in the horizontal line 41 | # if yes then delete the middle node and update next and next_next 42 | while next_next is not None and next.x == next_next.x: 43 | current.next = next_next 44 | next = next_next 45 | next_next = next_next.next 46 | # if y coordinates are equal of current and next node i.e. vertical line 47 | elif current.y == next.y: 48 | # check if there are more than 2 nodes in the vertical line 49 | # if yes then delete the middle node and update next and next_next 50 | while next_next is not None and next.y == next_next.y: 51 | current.next = next_next 52 | next = next_next 53 | next_next = next_next.next 54 | # updated the current node to next node for checking the next line nodes 55 | current = current.next 56 | 57 | # Function to Insert data at the beginning of the linked list 58 | def insert_at_beg(self, x, y): 59 | node = Node(x, y) 60 | node.next = self.head 61 | self.head = node 62 | 63 | # Function to print the linked list 64 | def print_data(self): 65 | current = self.head 66 | while current is not None: 67 | print('(',current.x, ',', current.y, ') -> ', end='') 68 | current = current.next 69 | print('None') 70 | 71 | if __name__ == '__main__': 72 | linked_list = SinglyLinkedList() 73 | linked_list.insert_at_beg(40,5) 74 | linked_list.insert_at_beg(20,5) 75 | linked_list.insert_at_beg(7,5) 76 | linked_list.insert_at_beg(7,10) 77 | linked_list.insert_at_beg(5,10) 78 | linked_list.insert_at_beg(1,10) 79 | linked_list.insert_at_beg(0,10) 80 | 81 | # print the linked list representing vertical and horizontal lines 82 | linked_list.print_data() 83 | 84 | # call the delete_middle_nodes function 85 | linked_list.delete_middle_nodes() 86 | 87 | # print the new linked list 88 | linked_list.print_data() -------------------------------------------------------------------------------- /LinkedList/MaxSumLinkedList.py: -------------------------------------------------------------------------------- 1 | # Python program to Construct a Maximum Sum Linked List out of two Sorted Linked Lists having some Common nodes. 2 | 3 | """When constructing the result list, we may switch to the other input list only at the point of intersection 4 | (which mean the two node with the same value in the lists). You are allowed to use O(1) extra space.""" 5 | 6 | 7 | # Node class 8 | class Node: 9 | 10 | # Constructor to initialise data and next 11 | def __init__(self, data=None): 12 | self.data = data 13 | self.next = None 14 | 15 | 16 | class SinglyLinkedList: 17 | 18 | # Constructor to initialise head 19 | def __init__(self): 20 | self.head = None 21 | 22 | # Function to find max sum linked list using 2 linked lists 23 | def max_sum_list(self, l2): 24 | pre1 = cur1 = self.head 25 | pre2 = cur2 = l2.head 26 | result = None 27 | 28 | # while any of the lists are not empty keep traversing 29 | while cur1 or cur2 is not None: 30 | sum1 = sum2 = 0 31 | while cur1 and cur2 is not None and cur1.data != cur2.data: 32 | 33 | # if 1st list's node data is less than 2nd list's node 34 | if cur1.data < cur2.data: 35 | sum1 += cur1.data 36 | cur1 = cur1.next 37 | 38 | # if 2nd list's node data is less than 1st list's node 39 | else: 40 | sum2 += cur2.data 41 | cur2 = cur2.next 42 | 43 | # if any of the list has ended calculate the sum of the other list till the end 44 | if cur1 is None: 45 | while cur2 is not None: 46 | sum2 += cur2.data 47 | cur2 = cur2.next 48 | elif cur2 is None: 49 | while cur1 is not None: 50 | sum1 += cur1.data 51 | cur1 = cur1.next 52 | 53 | # initial case when result's head needs to be set 54 | if pre1 is self.head and pre2 is l2.head: 55 | result = pre1 if sum1 > sum2 else pre2 56 | else: 57 | if sum1 > sum2: 58 | pre2.next = pre1.next 59 | else: 60 | pre1.next = pre2.next 61 | 62 | pre1 = cur1 63 | pre2 = cur2 64 | 65 | if cur1 is not None: 66 | cur1 = cur1.next 67 | if cur2 is not None: 68 | cur2 = cur2.next 69 | 70 | return result 71 | 72 | # Function to Insert data at the beginning of the linked list 73 | def insert_at_beg(self, data): 74 | node = Node(data) 75 | node.next = self.head 76 | self.head = node 77 | 78 | # Function to print the linked list 79 | def print_data(self): 80 | current = self.head 81 | while current is not None: 82 | print(current.data, '-> ', end='') 83 | current = current.next 84 | print('None') 85 | 86 | if __name__ == '__main__': 87 | linked_list1 = SinglyLinkedList() 88 | linked_list1.insert_at_beg(130) 89 | linked_list1.insert_at_beg(120) 90 | linked_list1.insert_at_beg(100) 91 | linked_list1.insert_at_beg(90) 92 | linked_list1.insert_at_beg(32) 93 | linked_list1.insert_at_beg(12) 94 | linked_list1.insert_at_beg(3) 95 | linked_list1.insert_at_beg(0) 96 | 97 | linked_list2 = SinglyLinkedList() 98 | linked_list2.insert_at_beg(120) 99 | linked_list2.insert_at_beg(110) 100 | linked_list2.insert_at_beg(90) 101 | linked_list2.insert_at_beg(30) 102 | linked_list2.insert_at_beg(3) 103 | linked_list2.insert_at_beg(1) 104 | 105 | print('List 1:') 106 | linked_list1.print_data() 107 | print('List 2:') 108 | linked_list2.print_data() 109 | 110 | # call the max_sum_list function and update the list 1's head to point the max sum list 111 | linked_list1.head = linked_list1.max_sum_list(linked_list2) 112 | 113 | # print the max sum linked list 114 | print('Max sum linked list:') 115 | linked_list1.print_data() 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /LinkedList/MergeAlt.py: -------------------------------------------------------------------------------- 1 | # Python program to Merge a linked list into another linked list at alternate positions 2 | 3 | 4 | # Node class 5 | class Node: 6 | 7 | # Constructor to initialise data and next 8 | def __init__(self, data=None): 9 | self.data = data 10 | self.next = None 11 | 12 | 13 | class SinglyLinkedList: 14 | 15 | # Constructor to initialise head 16 | def __init__(self): 17 | self.head = None 18 | 19 | # Function to merge 2 linked lists at alternate positions 20 | def merge(self, l2): 21 | h1 = self.head 22 | h2 = l2.head 23 | 24 | # Merge at alternate positions until the h1 has alternate positions 25 | while h1 and h2 is not None: 26 | h1_next = h1.next 27 | h2_next = h2.next 28 | 29 | h1.next = h2 30 | h2.next = h1_next 31 | 32 | h1 = h1_next 33 | h2 = h2_next 34 | 35 | # update the head of h2 if linked list remains i.e. no more alternate positions in h1 36 | l2.head = h2 37 | 38 | # Function to Insert data at the beginning of the linked list 39 | def insert_at_beg(self, data): 40 | node = Node(data) 41 | node.next = self.head 42 | self.head = node 43 | 44 | # Function to print the linked list 45 | def print_data(self): 46 | current = self.head 47 | while current is not None: 48 | print(current.data, '-> ', end='') 49 | current = current.next 50 | print('None') 51 | 52 | if __name__ == '__main__': 53 | linked_list1 = SinglyLinkedList() 54 | linked_list1.insert_at_beg(9) 55 | linked_list1.insert_at_beg(8) 56 | linked_list1.insert_at_beg(7) 57 | linked_list1.insert_at_beg(6) 58 | linked_list1.insert_at_beg(5) 59 | 60 | linked_list2 = SinglyLinkedList() 61 | linked_list2.insert_at_beg(12) 62 | linked_list2.insert_at_beg(11) 63 | linked_list2.insert_at_beg(10) 64 | linked_list2.insert_at_beg(4) 65 | linked_list2.insert_at_beg(3) 66 | linked_list2.insert_at_beg(2) 67 | linked_list2.insert_at_beg(1) 68 | 69 | print('List 1:') 70 | linked_list1.print_data() 71 | print('List 2:') 72 | linked_list2.print_data() 73 | 74 | # call the merge function 75 | linked_list1.merge(linked_list2) 76 | 77 | # print the merged linked list 78 | print('Merged list:') 79 | linked_list1.print_data() 80 | linked_list2.print_data() 81 | -------------------------------------------------------------------------------- /LinkedList/MergeSort.py: -------------------------------------------------------------------------------- 1 | # Python program to perform Merge Sort on a Signly linked list 2 | 3 | 4 | # Node class 5 | class Node: 6 | 7 | # Constructor to initialise data and next 8 | def __init__(self, data=None): 9 | self.data = data 10 | self.next = None 11 | 12 | 13 | class SinglyLinkedList: 14 | 15 | # Constructor to initialise head 16 | def __init__(self, head=None): 17 | self.head = head 18 | 19 | # Function to Insert data at the beginning of the linked list 20 | def insert_at_beg(self, data): 21 | node = Node(data) 22 | node.next = self.head 23 | self.head = node 24 | 25 | # Function to print the linked list 26 | def print_data(self): 27 | current = self.head 28 | while current is not None: 29 | print(current.data, '-> ', end='') 30 | current = current.next 31 | print('None') 32 | 33 | 34 | # Function to split the linked list into two halves 35 | def split(head): 36 | slow = head 37 | 38 | if slow is None or slow.next is None: 39 | return head, None 40 | 41 | fast = slow.next 42 | 43 | # Reach to the middle of the linked list 44 | while fast is not None: 45 | fast = fast.next 46 | if fast is not None: 47 | fast = fast.next 48 | slow = slow.next 49 | 50 | fast = slow.next 51 | # break the linked list in half 52 | slow.next = None 53 | 54 | # return the 2 linked lists formed 55 | return head, fast 56 | 57 | 58 | # Function to merge linked lists in sorted order 59 | def merge(a, b): 60 | # Make a dummy node 61 | dummy = Node() 62 | # dummy node next will be the head of our merged list 63 | dummy.next = None 64 | 65 | temp = SinglyLinkedList(dummy) 66 | tail = temp.head 67 | 68 | while True: 69 | if a is None: 70 | tail.next = b 71 | break 72 | elif b is None: 73 | tail.next = a 74 | break 75 | elif a.data <= b.data: 76 | tail.next = a 77 | a = a.next 78 | else: 79 | tail.next = b 80 | b = b.next 81 | tail = tail.next 82 | 83 | return temp.head.next 84 | 85 | 86 | # Function Merge Sort 87 | def merge_sort(head): 88 | 89 | if head is None or head.next is None: 90 | return head 91 | 92 | a, b = split(head) 93 | a = merge_sort(a) 94 | b = merge_sort(b) 95 | 96 | head = merge(a, b) 97 | 98 | return head 99 | 100 | 101 | if __name__ == '__main__': 102 | linked_list = SinglyLinkedList() 103 | linked_list.insert_at_beg(9) 104 | linked_list.insert_at_beg(3) 105 | linked_list.insert_at_beg(2) 106 | linked_list.insert_at_beg(1) 107 | linked_list.insert_at_beg(5) 108 | linked_list.insert_at_beg(4) 109 | linked_list.insert_at_beg(8) 110 | linked_list.insert_at_beg(7) 111 | linked_list.insert_at_beg(6) 112 | 113 | # before sorting 114 | print('before sorting') 115 | linked_list.print_data() 116 | 117 | # call merge_sort function 118 | linked_list.head = merge_sort(linked_list.head) 119 | 120 | # after sorting 121 | print('after sorting') 122 | linked_list.print_data() 123 | -------------------------------------------------------------------------------- /LinkedList/MiddleNode.cpp: -------------------------------------------------------------------------------- 1 | // Find the middle node of a singly linked list 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | class Node { 8 | public: 9 | int data; 10 | Node* next; 11 | 12 | Node() { 13 | this->next = NULL; 14 | } 15 | 16 | Node(int data) { 17 | this->data = data; 18 | this->next = NULL; 19 | } 20 | }; 21 | 22 | class LinkedList { 23 | public: 24 | Node* head = NULL; 25 | 26 | void insert_at_beg(int data){ 27 | Node* temp = new Node(data); 28 | temp->next = this->head; 29 | this->head = temp; 30 | } 31 | 32 | void print_data(){ 33 | Node* itr = this->head; 34 | 35 | while(itr != NULL){ 36 | cout << itr->data << " "; 37 | itr = itr->next; 38 | } 39 | cout << endl; 40 | } 41 | }; 42 | 43 | Node* middle_node(LinkedList* ll){ 44 | Node *fast = ll->head, *slow = ll->head; 45 | 46 | // if list is empty or only 1 node is present 47 | if(fast == NULL || fast->next == NULL) 48 | return fast; 49 | 50 | // while the double speed pointer doesn't get to the end 51 | // keep updating both slow and fast pointers 52 | while(fast != NULL){ 53 | fast = fast->next; 54 | 55 | if(fast != NULL){ 56 | fast = fast->next; 57 | slow = slow->next; 58 | } 59 | } 60 | 61 | return slow; 62 | } 63 | 64 | int main() { 65 | LinkedList* ll = new LinkedList(); 66 | 67 | // Create Linked list 68 | ll->insert_at_beg(7); 69 | ll->insert_at_beg(6); 70 | ll->insert_at_beg(5); 71 | ll->insert_at_beg(4); 72 | ll->insert_at_beg(3); 73 | ll->insert_at_beg(2); 74 | ll->insert_at_beg(1); 75 | 76 | cout<<"Linked List data:\n"; 77 | ll->print_data(); 78 | 79 | cout << "Middle of the linked list is: " << middle_node(ll)->data << endl; 80 | 81 | ll->insert_at_beg(0); 82 | 83 | cout<<"Linked List data:\n"; 84 | ll->print_data(); 85 | 86 | cout << "Middle of the linked list is: " << middle_node(ll)->data << endl; 87 | return 0; 88 | } 89 | 90 | 91 | -------------------------------------------------------------------------------- /LinkedList/MiddleNode.py: -------------------------------------------------------------------------------- 1 | # Python program to find middle node of a singly linked list 2 | 3 | 4 | # Node class 5 | class Node: 6 | 7 | # Constructor to initialise data and next 8 | def __init__(self, data=None): 9 | self.data = data 10 | self.next = None 11 | 12 | 13 | class SinglyLinkedList: 14 | 15 | # Constructor to initialise head 16 | def __init__(self): 17 | self.head = None 18 | 19 | # Function to find middle node of a linked list 20 | def find_mid(self): 21 | fast = self.head 22 | slow = self.head 23 | 24 | # Make fast run twice the speed of slow 25 | # when fast is at the last of the list 26 | # slow will be at the mid node 27 | while fast is not None: 28 | fast = fast.next 29 | if fast is not None: 30 | fast = fast.next 31 | slow = slow.next 32 | 33 | return slow 34 | 35 | # Function to Insert data at the beginning of the linked list 36 | def insert_at_beg(self, data): 37 | node = Node(data) 38 | node.next = self.head 39 | self.head = node 40 | 41 | # Function to print the linked list 42 | def print_data(self): 43 | current = self.head 44 | while current is not None: 45 | print(current.data, '-> ', end='') 46 | current = current.next 47 | print('None') 48 | 49 | if __name__ == '__main__': 50 | linked_list = SinglyLinkedList() 51 | linked_list.insert_at_beg(9) 52 | linked_list.insert_at_beg(8) 53 | linked_list.insert_at_beg(7) 54 | linked_list.insert_at_beg(6) 55 | linked_list.insert_at_beg(5) 56 | linked_list.insert_at_beg(4) 57 | linked_list.insert_at_beg(3) 58 | linked_list.insert_at_beg(2) 59 | linked_list.insert_at_beg(1) 60 | linked_list.print_data() 61 | # call the find_mid function 62 | mid = linked_list.find_mid() 63 | # print the middle node if not None 64 | if mid is not None: 65 | print(mid.data) 66 | -------------------------------------------------------------------------------- /LinkedList/NextHigerValueNode.py: -------------------------------------------------------------------------------- 1 | # Python program to Point to next higher value node in a linked list with an arbitrary pointer 2 | 3 | 4 | # Node class 5 | class Node: 6 | 7 | # Constructor to initialise data and next and arbitrary pointer 8 | def __init__(self, data=None): 9 | self.data = data 10 | self.next = None 11 | self.arbit = None 12 | 13 | 14 | class SinglyLinkedList: 15 | 16 | # Constructor to initialise head 17 | def __init__(self, head=None): 18 | self.head = head 19 | 20 | # Function to Insert data at the beginning of the linked list 21 | def insert_at_beg(self, data): 22 | node = Node(data) 23 | node.next = self.head 24 | node.arbit = node.next 25 | self.head = node 26 | 27 | # Function to print the linked list 28 | def print_data(self): 29 | current = self.head 30 | # print data of each node 31 | while current is not None: 32 | print(current.data, '-> ', end='') 33 | current = current.next 34 | 35 | current = self.head 36 | print('None') 37 | while current is not None: 38 | print("V", ' ', end='') 39 | current = current.next 40 | 41 | current = self.head 42 | print() 43 | # print arbitrary pointer node's data of each node 44 | while current is not None: 45 | if current.arbit is not None: 46 | print(current.arbit.data, ' ', end='') 47 | else: 48 | print("N", ' ', end='') 49 | current = current.next 50 | print() 51 | 52 | 53 | # Function to split the linked list into two halves 54 | def split(head): 55 | slow = head 56 | 57 | if slow is None or slow.arbit is None: 58 | return head, None 59 | 60 | fast = slow.arbit 61 | 62 | # Reach to the middle of the linked list 63 | while fast is not None: 64 | fast = fast.arbit 65 | if fast is not None: 66 | fast = fast.arbit 67 | slow = slow.arbit 68 | 69 | fast = slow.arbit 70 | # break the linked list in half 71 | slow.arbit = None 72 | 73 | # return the 2 linked lists formed 74 | return head, fast 75 | 76 | 77 | # Function to merge linked lists in sorted order 78 | def merge(a, b): 79 | # Make a dummy node 80 | dummy = Node() 81 | # dummy node arbit will be the head of our merged list 82 | dummy.arbit = None 83 | 84 | temp = SinglyLinkedList(dummy) 85 | tail = temp.head 86 | 87 | while True: 88 | if a is None: 89 | tail.arbit = b 90 | break 91 | elif b is None: 92 | tail.arbit = a 93 | break 94 | elif a.data <= b.data: 95 | tail.arbit = a 96 | a = a.arbit 97 | else: 98 | tail.arbit = b 99 | b = b.arbit 100 | tail = tail.arbit 101 | 102 | return temp.head.arbit 103 | 104 | 105 | # Function Merge Sort 106 | def merge_sort(head): 107 | 108 | if head is None or head.arbit is None: 109 | return head 110 | 111 | a, b = split(head) 112 | a = merge_sort(a) 113 | b = merge_sort(b) 114 | 115 | head = merge(a, b) 116 | 117 | return head 118 | 119 | 120 | if __name__ == '__main__': 121 | linked_list = SinglyLinkedList() 122 | linked_list.insert_at_beg(3) 123 | linked_list.insert_at_beg(2) 124 | linked_list.insert_at_beg(10) 125 | linked_list.insert_at_beg(5) 126 | 127 | # before linking the arbit 128 | print('before linking') 129 | linked_list.print_data() 130 | 131 | # call merge_sort function 132 | # to sort the linked list on the basis of the arbitrary pointers 133 | merge_sort(linked_list.head) 134 | 135 | # after linking the arbit 136 | print('after linking') 137 | linked_list.print_data() 138 | -------------------------------------------------------------------------------- /LinkedList/NullOrCycle.py: -------------------------------------------------------------------------------- 1 | # Python program to check if the singly linked list contains cycle or not 2 | 3 | 4 | # Node class 5 | class Node: 6 | 7 | # Constructor to initialise data and next 8 | def __init__(self, data=None): 9 | self.data = data 10 | self.next = None 11 | 12 | 13 | class SinglyLinkedList: 14 | 15 | # Constructor to initialise head 16 | def __init__(self): 17 | self.head = None 18 | 19 | # Function to find cycle in linked list 20 | def find_cycle(self): 21 | fast = self.head.next 22 | slow = self.head 23 | 24 | # Make fast run twice the speed of slow 25 | # if fast coincide with slow 26 | # then there is a loop or cycle 27 | while fast is not None: 28 | # return True if cycle 29 | if fast is slow: 30 | return True 31 | fast = fast.next 32 | if fast is not None: 33 | fast = fast.next 34 | slow = slow.next 35 | 36 | # return False if no cycle 37 | return False 38 | 39 | # Function to Insert data at the beginning of the linked list 40 | def insert_at_beg(self, data): 41 | node = Node(data) 42 | node.next = self.head 43 | self.head = node 44 | 45 | # Function to print the linked list 46 | def print_data(self): 47 | current = self.head 48 | while current is not None: 49 | print(current.data, '-> ', end='') 50 | current = current.next 51 | print('None') 52 | 53 | if __name__ == '__main__': 54 | linked_list = SinglyLinkedList() 55 | linked_list.insert_at_beg(9) 56 | linked_list.insert_at_beg(8) 57 | linked_list.insert_at_beg(7) 58 | linked_list.insert_at_beg(6) 59 | linked_list.insert_at_beg(5) 60 | linked_list.insert_at_beg(4) 61 | linked_list.insert_at_beg(3) 62 | linked_list.insert_at_beg(2) 63 | linked_list.insert_at_beg(1) 64 | 65 | temp = head = linked_list.head 66 | 67 | # get pointer to the end of the list 68 | while temp.next is not None: 69 | temp = temp.next 70 | 71 | # Make a loop in the list 72 | temp.next = head.next.next.next 73 | 74 | # call the find_cycle function 75 | result = linked_list.find_cycle() 76 | 77 | # print if cycle or not 78 | print('Yes! there is a cycle') if result else print('No! there is no cycle') 79 | 80 | 81 | -------------------------------------------------------------------------------- /LinkedList/Random_Node.py: -------------------------------------------------------------------------------- 1 | # to select a random node in a singly linked list 2 | import random 3 | 4 | 5 | # Node class 6 | class Node: 7 | # Constructor to initialise data and next 8 | def __init__(self, data=None): 9 | self.data = data 10 | self.next = None 11 | 12 | 13 | class SinglyLinkedList: 14 | 15 | # Constructor to initialise head 16 | def __init__(self): 17 | self.head = None 18 | 19 | # Function to get random node in linked list 20 | def get_random_node(self): 21 | if self.head is None: 22 | return None 23 | 24 | random.seed() 25 | random_node = self.head 26 | current = self.head.next 27 | n = 2 28 | while current is not None: 29 | if random.randrange(n) == 0: 30 | random_node = current 31 | current = current.next 32 | n += 1 33 | return random_node 34 | 35 | # Function to Insert data at the beginning of the linked list 36 | def insert_at_beg(self, data): 37 | node = Node(data) 38 | node.next = self.head 39 | self.head = node 40 | 41 | # Function to print the linked list 42 | def print_data(self): 43 | current = self.head 44 | while current is not None: 45 | print(current.data, '-> ', end='') 46 | current = current.next 47 | print('None') 48 | 49 | if __name__ == '__main__': 50 | linked_list = SinglyLinkedList() 51 | linked_list.insert_at_beg(9) 52 | linked_list.insert_at_beg(8) 53 | linked_list.insert_at_beg(7) 54 | linked_list.insert_at_beg(6) 55 | linked_list.insert_at_beg(5) 56 | linked_list.insert_at_beg(4) 57 | linked_list.insert_at_beg(3) 58 | linked_list.insert_at_beg(2) 59 | linked_list.insert_at_beg(1) 60 | 61 | random_node = linked_list.get_random_node() 62 | print("Random node data is:") 63 | print(random_node.data) 64 | -------------------------------------------------------------------------------- /LinkedList/RemoveCycle.cpp: -------------------------------------------------------------------------------- 1 | // Find and remove cycle if present in a singly linked list 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | class Node { 8 | public: 9 | int data; 10 | Node* next; 11 | 12 | Node() { 13 | this->next = NULL; 14 | } 15 | 16 | Node(int data) { 17 | this->data = data; 18 | this->next = NULL; 19 | } 20 | }; 21 | 22 | class LinkedList { 23 | public: 24 | Node* head = NULL; 25 | 26 | void insert_at_beg(int data){ 27 | Node* temp = new Node(data); 28 | temp->next = this->head; 29 | this->head = temp; 30 | } 31 | 32 | void print_data(){ 33 | Node* itr = this->head; 34 | 35 | while(itr != NULL){ 36 | cout << itr->data << " "; 37 | itr = itr->next; 38 | } 39 | cout << endl; 40 | } 41 | }; 42 | 43 | bool remove_cycle(LinkedList* ll){ 44 | Node *fast = ll->head, *slow = ll->head; 45 | 46 | // while the double speed pointer doesn't get to the end if loop doesn't exists 47 | // or does not meet with slow pointer again if loop exists 48 | while(fast != NULL){ 49 | fast = fast->next; 50 | 51 | if(fast != NULL){ 52 | fast = fast->next; 53 | slow = slow->next; 54 | if(fast == slow) 55 | break; 56 | } 57 | } 58 | 59 | // cycle doesn't exists 60 | if(fast == NULL) return false; 61 | else { 62 | // bring slow back to linked list head 63 | slow = ll->head; 64 | 65 | // move both pointers at same speed until they meet again 66 | while(slow->next != fast->next){ 67 | fast = fast->next; 68 | slow = slow->next; 69 | } 70 | } 71 | 72 | // break the cycle 73 | fast->next = NULL; 74 | 75 | return true; 76 | } 77 | 78 | int main() { 79 | LinkedList* ll = new LinkedList(); 80 | 81 | // Create Linked list 82 | ll->insert_at_beg(6); 83 | ll->insert_at_beg(5); 84 | ll->insert_at_beg(4); 85 | ll->insert_at_beg(3); 86 | ll->insert_at_beg(2); 87 | ll->insert_at_beg(1); 88 | 89 | // Add cycle in the linked list 90 | ll->head->next->next->next->next->next->next = ll->head->next->next->next; 91 | 92 | // remove cycle if any 93 | bool found = remove_cycle(ll); 94 | 95 | // print list after removing loop 96 | found ? cout << "After removing loop linked list is: " : cout << "Loop not found in list: "; 97 | ll->print_data(); 98 | 99 | return 0; 100 | } 101 | 102 | 103 | -------------------------------------------------------------------------------- /LinkedList/RemoveCycle.py: -------------------------------------------------------------------------------- 1 | # Python program to check if the singly linked list contains cycle or not 2 | 3 | 4 | # Node class 5 | class Node: 6 | 7 | # Constructor to initialise data and next 8 | def __init__(self, data=None): 9 | self.data = data 10 | self.next = None 11 | 12 | 13 | class SinglyLinkedList: 14 | 15 | # Constructor to initialise head 16 | def __init__(self): 17 | self.head = None 18 | 19 | # Function to find cycle in linked list 20 | def find_cycle_remove(self): 21 | fast = self.head.next 22 | slow = self.head 23 | 24 | # Make fast run twice the speed of slow 25 | # if fast coincide with slow 26 | # then there is a loop or cycle 27 | while fast is not None: 28 | # break loop if cycle exists 29 | if fast is slow: 30 | break 31 | fast = fast.next 32 | if fast is not None: 33 | fast = fast.next 34 | slow = slow.next 35 | 36 | if fast is slow: 37 | slow = self.head 38 | while fast.next is not slow: 39 | fast = fast.next 40 | slow = slow.next 41 | fast.next = None 42 | return True 43 | 44 | # return False if no cycle 45 | return False 46 | 47 | # Function to Insert data at the beginning of the linked list 48 | def insert_at_beg(self, data): 49 | node = Node(data) 50 | node.next = self.head 51 | self.head = node 52 | 53 | # Function to print the linked list 54 | def print_data(self): 55 | current = self.head 56 | while current is not None: 57 | print(current.data, '-> ', end='') 58 | current = current.next 59 | print('None') 60 | 61 | if __name__ == '__main__': 62 | linked_list = SinglyLinkedList() 63 | linked_list.insert_at_beg(9) 64 | linked_list.insert_at_beg(8) 65 | linked_list.insert_at_beg(7) 66 | linked_list.insert_at_beg(6) 67 | linked_list.insert_at_beg(5) 68 | linked_list.insert_at_beg(4) 69 | linked_list.insert_at_beg(3) 70 | linked_list.insert_at_beg(2) 71 | linked_list.insert_at_beg(1) 72 | 73 | temp = head = linked_list.head 74 | 75 | # get pointer to the end of the list 76 | while temp.next is not None: 77 | temp = temp.next 78 | 79 | # Make a loop in the list 80 | temp.next = head.next.next.next 81 | 82 | # call the find_cycle function 83 | result = linked_list.find_cycle_remove() 84 | 85 | # print if cycle or not 86 | print('Yes! there was a cycle') if result else print('No! there was no cycle') 87 | linked_list.print_data() 88 | 89 | 90 | -------------------------------------------------------------------------------- /LinkedList/ReverseKNodes.cpp: -------------------------------------------------------------------------------- 1 | // Reverse a singly linked list in groups of size k 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | class Node { 8 | public: 9 | int data; 10 | Node* next; 11 | 12 | Node() { 13 | this->next = NULL; 14 | } 15 | 16 | Node(int data) { 17 | this->data = data; 18 | this->next = NULL; 19 | } 20 | }; 21 | 22 | class LinkedList { 23 | public: 24 | Node* head = NULL; 25 | 26 | void insert_at_beg(int data){ 27 | Node* temp = new Node(data); 28 | temp->next = this->head; 29 | this->head = temp; 30 | } 31 | 32 | void print_data(){ 33 | Node* itr = this->head; 34 | 35 | while(itr != NULL){ 36 | cout << itr->data << " "; 37 | itr = itr->next; 38 | } 39 | cout << endl; 40 | } 41 | }; 42 | 43 | Node* reverse_k_nodes_util(Node* head, int k) { 44 | // if linked list is empty or has only 1 node 45 | if(head == NULL || head->next == NULL) return head; 46 | 47 | Node *curr_ptr = head, *next_ptr, *prev_ptr = NULL; 48 | int count = 0; 49 | 50 | while(curr_ptr != NULL && count < k){ 51 | count += 1; 52 | next_ptr = curr_ptr->next; 53 | curr_ptr->next = prev_ptr; 54 | prev_ptr = curr_ptr; 55 | curr_ptr = next_ptr; 56 | } 57 | 58 | head->next = reverse_k_nodes_util(next_ptr, k); 59 | 60 | // update to the new head 61 | return prev_ptr; 62 | } 63 | 64 | void reverse_k_nodes(LinkedList *ll, int k){ 65 | ll->head = reverse_k_nodes_util(ll->head, k); 66 | } 67 | 68 | int main() { 69 | LinkedList* ll = new LinkedList(); 70 | 71 | // Create Linked list 72 | ll->insert_at_beg(8); 73 | ll->insert_at_beg(7); 74 | ll->insert_at_beg(6); 75 | ll->insert_at_beg(5); 76 | ll->insert_at_beg(4); 77 | ll->insert_at_beg(3); 78 | ll->insert_at_beg(2); 79 | ll->insert_at_beg(1); 80 | 81 | cout << "Linked list before reverse: " << endl; 82 | ll->print_data(); 83 | int k = 3; 84 | reverse_k_nodes(ll, k); 85 | cout << "Linked list after reversing in groups of " << k << ": " << endl; 86 | ll->print_data(); 87 | return 0; 88 | } 89 | 90 | 91 | -------------------------------------------------------------------------------- /LinkedList/ReverseKNodes.py: -------------------------------------------------------------------------------- 1 | # Python program to reverse a linked list in group of given size k 2 | 3 | 4 | # Node class 5 | class Node: 6 | 7 | # Constructor to initialise data and next 8 | def __init__(self, data=None): 9 | self.data = data 10 | self.next = None 11 | 12 | 13 | class SinglyLinkedList: 14 | 15 | # Constructor to initialise head 16 | def __init__(self): 17 | self.head = None 18 | 19 | # Function to reverse K nodes of linked list 20 | def reverse_k_nodes(self, head, k): 21 | current = head 22 | next = None 23 | prev = None 24 | count = 0 25 | 26 | # traverse k nodes ahead reversing the links or until current is not None 27 | while current is not None and count < k: 28 | next = current.next 29 | current.next = prev 30 | prev = current 31 | current = next 32 | count += 1 33 | 34 | # recursive call to the function to reverse the remaining n-k nodes 35 | if next is not None: 36 | head.next = self.reverse_k_nodes(next, k) 37 | 38 | # return the new header of the current sublist 39 | return prev 40 | 41 | # Function to Insert data at the beginning of the linked list 42 | def insert_at_beg(self, data): 43 | node = Node(data) 44 | node.next = self.head 45 | self.head = node 46 | 47 | # Function to print the linked list 48 | def print_data(self): 49 | current = self.head 50 | while current is not None: 51 | print(current.data, '-> ', end='') 52 | current = current.next 53 | print('None') 54 | 55 | if __name__ == '__main__': 56 | linked_list = SinglyLinkedList() 57 | linked_list.insert_at_beg(7) 58 | linked_list.insert_at_beg(6) 59 | linked_list.insert_at_beg(5) 60 | linked_list.insert_at_beg(4) 61 | linked_list.insert_at_beg(3) 62 | linked_list.insert_at_beg(2) 63 | linked_list.insert_at_beg(1) 64 | linked_list.print_data() 65 | # call the reverse k nodes function 66 | linked_list.head = linked_list.reverse_k_nodes(linked_list.head, 3) 67 | # print the reversed list 68 | linked_list.print_data() 69 | -------------------------------------------------------------------------------- /LinkedList/ReverseSLL.cpp: -------------------------------------------------------------------------------- 1 | // Reverse a singly linked list 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | class Node { 8 | public: 9 | int data; 10 | Node* next; 11 | 12 | Node() { 13 | this->next = NULL; 14 | } 15 | 16 | Node(int data) { 17 | this->data = data; 18 | this->next = NULL; 19 | } 20 | }; 21 | 22 | class LinkedList { 23 | public: 24 | Node* head = NULL; 25 | 26 | void insert_at_beg(int data){ 27 | Node* temp = new Node(data); 28 | temp->next = this->head; 29 | this->head = temp; 30 | } 31 | 32 | void print_data(){ 33 | Node* itr = this->head; 34 | 35 | while(itr != NULL){ 36 | cout << itr->data << " "; 37 | itr = itr->next; 38 | } 39 | cout << endl; 40 | } 41 | }; 42 | 43 | void reverse(LinkedList *ll){ 44 | // if linked list is empty or has only 1 node 45 | if(ll->head == NULL || ll->head->next == NULL) return; 46 | 47 | Node *curr_ptr = ll->head, *next_ptr, *prev_ptr = NULL; 48 | 49 | while(curr_ptr != NULL){ 50 | next_ptr = curr_ptr->next; 51 | curr_ptr->next = prev_ptr; 52 | prev_ptr = curr_ptr; 53 | curr_ptr = next_ptr; 54 | } 55 | 56 | // update to the new head 57 | ll->head = prev_ptr; 58 | } 59 | 60 | int main() { 61 | LinkedList* ll = new LinkedList(); 62 | 63 | // Create Linked list 64 | ll->insert_at_beg(6); 65 | ll->insert_at_beg(5); 66 | ll->insert_at_beg(4); 67 | ll->insert_at_beg(3); 68 | ll->insert_at_beg(2); 69 | ll->insert_at_beg(1); 70 | 71 | cout << "Linked list before reverse: " << endl; 72 | ll->print_data(); 73 | 74 | reverse(ll); 75 | cout << "Linked list after reverse: " << endl; 76 | ll->print_data(); 77 | return 0; 78 | } 79 | 80 | 81 | -------------------------------------------------------------------------------- /LinkedList/ReverseSLL.py: -------------------------------------------------------------------------------- 1 | # Python program to reverse a singly linked list 2 | 3 | 4 | # Node class 5 | class Node: 6 | 7 | # Constructor to initialise data and next 8 | def __init__(self, data=None): 9 | self.data = data 10 | self.next = None 11 | 12 | 13 | class SinglyLinkedList: 14 | 15 | # Constructor to initialise head 16 | def __init__(self): 17 | self.head = None 18 | 19 | # Function to reverse a linked list 20 | def reverse(self): 21 | 22 | # If linked list is empty 23 | if self.head is None: 24 | return None 25 | 26 | current = self.head 27 | prev = None 28 | 29 | while current is not None: 30 | # Store the value of current.next 31 | next = current.next 32 | # Set current.next to point to the previous node 33 | current.next = prev 34 | # Update pointers for next iteration 35 | prev = current 36 | current = next 37 | 38 | self.head = prev 39 | 40 | # Function to Insert data at the beginning of the linked list 41 | def insert_at_beg(self, data): 42 | node = Node(data) 43 | node.next = self.head 44 | self.head = node 45 | 46 | # Function to print the linked list 47 | def print_data(self): 48 | current = self.head 49 | while current is not None: 50 | print(current.data, '-> ', end='') 51 | current = current.next 52 | print('None') 53 | 54 | if __name__ == '__main__': 55 | linked_list = SinglyLinkedList() 56 | linked_list.insert_at_beg(7) 57 | linked_list.insert_at_beg(6) 58 | linked_list.insert_at_beg(5) 59 | linked_list.insert_at_beg(4) 60 | linked_list.insert_at_beg(3) 61 | linked_list.insert_at_beg(2) 62 | linked_list.insert_at_beg(1) 63 | linked_list.print_data() 64 | # call the reverse function 65 | linked_list.reverse() 66 | # print the reversed list 67 | linked_list.print_data() 68 | -------------------------------------------------------------------------------- /LinkedList/Reverse_Alt_K_Nodes.cpp: -------------------------------------------------------------------------------- 1 | // Reverse a singly linked list alternately in groups of size k 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | class Node { 8 | public: 9 | int data; 10 | Node* next; 11 | 12 | Node() { 13 | this->next = NULL; 14 | } 15 | 16 | Node(int data) { 17 | this->data = data; 18 | this->next = NULL; 19 | } 20 | }; 21 | 22 | class LinkedList { 23 | public: 24 | Node* head = NULL; 25 | 26 | void insert_at_beg(int data){ 27 | Node* temp = new Node(data); 28 | temp->next = this->head; 29 | this->head = temp; 30 | } 31 | 32 | void print_data(){ 33 | Node* itr = this->head; 34 | 35 | while(itr != NULL){ 36 | cout << itr->data << " "; 37 | itr = itr->next; 38 | } 39 | cout << endl; 40 | } 41 | }; 42 | 43 | Node* reverse_alt_k_nodes_util(Node* head, int k) { 44 | // if linked list is empty or has only 1 node 45 | if(head == NULL || head->next == NULL) return head; 46 | 47 | Node *curr_ptr = head, *next_ptr, *prev_ptr = NULL; 48 | int count = 0; 49 | 50 | while(curr_ptr != NULL && count < k){ 51 | count += 1; 52 | next_ptr = curr_ptr->next; 53 | curr_ptr->next = prev_ptr; 54 | prev_ptr = curr_ptr; 55 | curr_ptr = next_ptr; 56 | } 57 | 58 | head->next = curr_ptr; 59 | 60 | count = 0; 61 | while(curr_ptr != NULL && count < k-1) { 62 | curr_ptr = curr_ptr->next; 63 | count += 1; 64 | } 65 | if (curr_ptr != NULL) 66 | curr_ptr->next = reverse_alt_k_nodes_util(curr_ptr->next, k); 67 | 68 | // update to the new head 69 | return prev_ptr; 70 | } 71 | 72 | void reverse_alt_k_nodes(LinkedList *ll, int k){ 73 | ll->head = reverse_alt_k_nodes_util(ll->head, k); 74 | } 75 | 76 | int main() { 77 | LinkedList* ll = new LinkedList(); 78 | 79 | // Create Linked list 80 | ll->insert_at_beg(8); 81 | ll->insert_at_beg(7); 82 | ll->insert_at_beg(6); 83 | ll->insert_at_beg(5); 84 | ll->insert_at_beg(4); 85 | ll->insert_at_beg(3); 86 | ll->insert_at_beg(2); 87 | ll->insert_at_beg(1); 88 | 89 | cout << "Linked list before reverse: " << endl; 90 | ll->print_data(); 91 | int k = 3; 92 | reverse_alt_k_nodes(ll, k); 93 | cout << "Linked list after reversing in groups of " << k << ": " << endl; 94 | ll->print_data(); 95 | return 0; 96 | } 97 | 98 | 99 | -------------------------------------------------------------------------------- /LinkedList/Reverse_Alt_K_Nodes.py: -------------------------------------------------------------------------------- 1 | # Python program to alternately reverse a linked list in group of given size k 2 | 3 | 4 | # Node class 5 | class Node: 6 | 7 | # Constructor to initialise data and next 8 | def __init__(self, data=None): 9 | self.data = data 10 | self.next = None 11 | 12 | 13 | class SinglyLinkedList: 14 | 15 | # Constructor to initialise head 16 | def __init__(self): 17 | self.head = None 18 | 19 | # Function to reverse K nodes of linked list 20 | def reverse_k_nodes(self, head, k): 21 | current = head 22 | next = None 23 | prev = None 24 | count = 0 25 | 26 | # traverse k nodes ahead reversing the links or until current is not None 27 | while current is not None and count < k: 28 | next = current.next 29 | current.next = prev 30 | prev = current 31 | current = next 32 | count += 1 33 | 34 | if head is not None: 35 | head.next = current 36 | 37 | count = 0 38 | # traverse the k nodes to be skipped 39 | while current is not None and count < k-1: 40 | current = current.next 41 | count += 1 42 | 43 | # recursive call to the function to alternate reverse the remaining n-2k nodes 44 | if current is not None: 45 | current.next = self.reverse_k_nodes(current.next, k) 46 | 47 | # return the new header of the current sublist 48 | return prev 49 | 50 | # Function to Insert data at the beginning of the linked list 51 | def insert_at_beg(self, data): 52 | node = Node(data) 53 | node.next = self.head 54 | self.head = node 55 | 56 | # Function to print the linked list 57 | def print_data(self): 58 | current = self.head 59 | while current is not None: 60 | print(current.data, '-> ', end='') 61 | current = current.next 62 | print('None') 63 | 64 | if __name__ == '__main__': 65 | linked_list = SinglyLinkedList() 66 | linked_list.insert_at_beg(10) 67 | linked_list.insert_at_beg(9) 68 | linked_list.insert_at_beg(8) 69 | linked_list.insert_at_beg(7) 70 | linked_list.insert_at_beg(6) 71 | linked_list.insert_at_beg(5) 72 | linked_list.insert_at_beg(4) 73 | linked_list.insert_at_beg(3) 74 | linked_list.insert_at_beg(2) 75 | linked_list.insert_at_beg(1) 76 | linked_list.print_data() 77 | # call the reverse k nodes function 78 | linked_list.head = linked_list.reverse_k_nodes(linked_list.head, 3) 79 | # print the reversed list 80 | linked_list.print_data() 81 | -------------------------------------------------------------------------------- /LinkedList/SegregateEvenOdd.py: -------------------------------------------------------------------------------- 1 | # Python program to segregate Even and Odd value nodes in a singly linked list 2 | 3 | 4 | # Node class 5 | class Node: 6 | 7 | # Constructor to initialise data and next 8 | def __init__(self, data=None): 9 | self.data = data 10 | self.next = None 11 | 12 | 13 | class SinglyLinkedList: 14 | 15 | # Constructor to initialise head 16 | def __init__(self): 17 | self.head = None 18 | 19 | # Function to segregate even odd value nodes of linked list 20 | def segregateEvenOdd(self): 21 | current = None 22 | prev = self.head 23 | pivot = None 24 | 25 | # If empty list or single element in the list 26 | if self.head is None or self.head.next is None: 27 | return self.head 28 | 29 | # if the first node is even 30 | # initialise pivot as head 31 | if prev.data % 2 == 0: 32 | pivot = self.head 33 | current = prev.next 34 | # else find the first node in the list that is even 35 | # make that node the head of the list 36 | # initialise pivot as head 37 | else: 38 | while prev.next is not None: 39 | if prev.next.data % 2 == 0: 40 | pivot = prev.next 41 | prev.next = pivot.next 42 | pivot.next = self.head 43 | self.head = pivot 44 | current = prev.next 45 | break 46 | prev = prev.next 47 | 48 | # keep moving the current pointer and prev pointer 49 | while current is not None: 50 | # if even value is found at the node 51 | if current.data % 2 == 0: 52 | # if the node is adjacent to pivot 53 | # simply increment the pivot to next node 54 | # and shift prev and current one step ahead 55 | if prev is pivot: 56 | pivot = current 57 | prev = current 58 | current = current.next 59 | # else insert the node after the pivot 60 | # shift the pivot to the newly inserted node 61 | # update current and prev 62 | else: 63 | prev.next = current.next 64 | current.next = pivot.next 65 | pivot.next = current 66 | pivot = current 67 | current = prev.next 68 | # if odd value simply increment current and prev 69 | else: 70 | prev = current 71 | current = current.next 72 | 73 | # return the updated linked list head 74 | return self.head 75 | 76 | # Function to Insert data at the beginning of the linked list 77 | def insert_at_beg(self, data): 78 | node = Node(data) 79 | node.next = self.head 80 | self.head = node 81 | 82 | # Function to print the linked list 83 | def print_data(self): 84 | current = self.head 85 | while current is not None: 86 | print(current.data, '-> ', end='') 87 | current = current.next 88 | print('None') 89 | 90 | if __name__ == '__main__': 91 | linked_list = SinglyLinkedList() 92 | linked_list.insert_at_beg(7) 93 | linked_list.insert_at_beg(6) 94 | linked_list.insert_at_beg(5) 95 | linked_list.insert_at_beg(4) 96 | linked_list.insert_at_beg(2) 97 | linked_list.insert_at_beg(3) 98 | linked_list.insert_at_beg(2) 99 | print('Before segregation:', end=' ') 100 | linked_list.print_data() 101 | linked_list.head = linked_list.segregateEvenOdd() 102 | print('After segregation:', end=' ') 103 | linked_list.print_data() -------------------------------------------------------------------------------- /LinkedList/SinglyLinkedList.cpp: -------------------------------------------------------------------------------- 1 | // Implementation of Singly linked list 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | class Node { 8 | public: 9 | int data; 10 | Node* next; 11 | 12 | Node() { 13 | this->next = NULL; 14 | } 15 | 16 | Node(int data) { 17 | this->data = data; 18 | this->next = NULL; 19 | } 20 | }; 21 | 22 | class LinkedList { 23 | public: 24 | Node* head = NULL; 25 | 26 | void insert_at_beg(int data){ 27 | Node* temp = new Node(data); 28 | temp->next = this->head; 29 | this->head = temp; 30 | } 31 | 32 | void insert_at_end(int data){ 33 | Node* itr = this->head; 34 | if (itr == NULL){ 35 | this->insert_at_beg(data); 36 | return; 37 | } 38 | 39 | Node* temp = new Node(data); 40 | 41 | while(itr->next != NULL){ 42 | itr = itr->next; 43 | } 44 | 45 | itr->next = temp; 46 | } 47 | 48 | 49 | void delete_from_beg(){ 50 | if (this->head == NULL) return; 51 | 52 | Node* temp = this->head; 53 | this->head = this->head->next; 54 | free(temp); 55 | } 56 | 57 | void delete_from_end(){ 58 | Node* itr = this->head; 59 | if (itr == NULL){ 60 | return; 61 | } 62 | else if (itr->next == NULL){ 63 | this->head = NULL; 64 | free(itr); 65 | } 66 | 67 | while(itr->next->next != NULL){ 68 | itr = itr->next; 69 | } 70 | 71 | Node* temp = itr->next; 72 | itr->next = NULL; 73 | free(temp); 74 | } 75 | 76 | int size() { 77 | Node* itr = this->head; 78 | int length = 0; 79 | 80 | while(itr != NULL){ 81 | length += 1; 82 | itr = itr->next; 83 | } 84 | 85 | return length; 86 | } 87 | 88 | void print_data(){ 89 | Node* itr = this->head; 90 | 91 | while(itr != NULL){ 92 | cout << itr->data << " "; 93 | itr = itr->next; 94 | } 95 | cout << endl; 96 | } 97 | }; 98 | 99 | int main() { 100 | LinkedList* ll = new LinkedList(); 101 | 102 | ll->delete_from_beg(); 103 | ll->delete_from_end(); 104 | // Insert at the beginning 3, 2, 1 105 | ll->insert_at_beg(3); 106 | ll->insert_at_beg(2); 107 | ll->insert_at_beg(1); 108 | cout<<"After insertion at the beginning:\n"; 109 | ll->print_data(); 110 | 111 | // Insert at the end of the list 4, 5 112 | ll->insert_at_end(4); 113 | ll->insert_at_end(5); 114 | cout<<"After insertion at the end:\n"; 115 | ll->print_data(); 116 | 117 | // Delete 1 from the beginning 118 | cout<<"After deletion at the beginning:\n"; 119 | ll->delete_from_beg(); 120 | ll->print_data(); 121 | 122 | // Delete 5 from the end 123 | cout<<"After deletion at the end:\n"; 124 | ll->delete_from_end(); 125 | ll->print_data(); 126 | 127 | // print size of the list 128 | cout << "Size of the linked list: " << ll->size() << endl; 129 | return 0; 130 | } 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /LinkedList/SinglyLinkedList.py: -------------------------------------------------------------------------------- 1 | # class of a node 2 | class Node: 3 | def __init__(self, data): 4 | self.data = data 5 | self.next = None 6 | 7 | 8 | # class of the signly linked list 9 | class SinglyLinkedList: 10 | def __init__(self): 11 | self.head = None 12 | 13 | # function to calculate size of the list 14 | def size(self): 15 | # initialize temporary variable and size to zero 16 | current = self.head 17 | size = 0 18 | 19 | # count until current does not reach the end of the list i.e. NULL or None 20 | while current is not None: 21 | size += 1 22 | current = current.next 23 | return size 24 | 25 | # function to insert at the end of the list 26 | def insert_at_end(self, data): 27 | # Create the new node 28 | node = Node(data) 29 | 30 | # If the list is empty 31 | if self.head is None: 32 | self.head = node 33 | else: 34 | current = self.head 35 | 36 | # Otherwise move to the last node of the list 37 | while current.next is not None: 38 | current = current.next 39 | 40 | # Point the last node of the list to the new node 41 | # So that the new node gets added to the end of the list 42 | current.next = node 43 | 44 | # function to insert at the beginning of the list 45 | def insert_at_beg(self, data): 46 | node = Node(data) 47 | # Next pointer of the new node points to the head 48 | node.next = self.head 49 | 50 | # Updated the head as new node 51 | self.head = node 52 | 53 | # function to delete from the end of the list 54 | def delete_from_end(self): 55 | current = self.head 56 | previous = None 57 | 58 | if current is None: 59 | print("Linked List Underflow!!") 60 | else: 61 | while current.next is not None: 62 | previous = current 63 | current = current.next 64 | 65 | if previous is None: 66 | self.head = None 67 | else: 68 | previous.next = None 69 | 70 | # function to delete from the beginning of the list 71 | def delete_from_beg(self): 72 | current = self.head 73 | 74 | if current is None: 75 | print("Linked List Underflow!!") 76 | else: 77 | self.head = current.next 78 | 79 | # function to print the linked list data 80 | def print_data(self): 81 | current = self.head 82 | 83 | while current is not None: 84 | print(current.data, '->', end='') 85 | current = current.next 86 | print('End of list') 87 | 88 | 89 | # Main program: 90 | if __name__ == '__main__': 91 | # Create a singly linked list object 92 | linked_list = SinglyLinkedList() 93 | 94 | # Insert at the beginning 3, 2, 1 95 | linked_list.insert_at_beg(3) 96 | linked_list.insert_at_beg(2) 97 | linked_list.insert_at_beg(1) 98 | print('After insertion at the beginning:') 99 | linked_list.print_data() 100 | 101 | # Insert at the end of the list 4, 5 102 | linked_list.insert_at_end(4) 103 | linked_list.insert_at_end(5) 104 | print('After insertion at the end:') 105 | linked_list.print_data() 106 | 107 | # Delete 1 from the beginning 108 | print('After deletion at the beginning:') 109 | linked_list.delete_from_beg() 110 | linked_list.print_data() 111 | 112 | # Delete 5 from the end 113 | print('After deletion at the end:') 114 | linked_list.delete_from_end() 115 | linked_list.print_data() 116 | 117 | # print size of the list 118 | print("size: ", linked_list.size()) -------------------------------------------------------------------------------- /LinkedList/SkipMDeleteN.cpp: -------------------------------------------------------------------------------- 1 | // Skip M nodes and delete N nodes from a linked list alternately 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | class Node { 8 | public: 9 | int data; 10 | Node* next; 11 | 12 | Node() { 13 | this->next = NULL; 14 | } 15 | 16 | Node(int data) { 17 | this->data = data; 18 | this->next = NULL; 19 | } 20 | }; 21 | 22 | class LinkedList { 23 | public: 24 | Node* head = NULL; 25 | 26 | void insert_at_beg(int data){ 27 | Node* temp = new Node(data); 28 | temp->next = this->head; 29 | this->head = temp; 30 | } 31 | 32 | void print_data(){ 33 | Node* itr = this->head; 34 | 35 | while(itr != NULL){ 36 | cout << itr->data << " "; 37 | itr = itr->next; 38 | } 39 | cout << endl; 40 | } 41 | }; 42 | 43 | void skip_m_delete_n(LinkedList* ll, int m, int n){ 44 | Node *curr = ll->head, *del_ptr, *temp; 45 | 46 | while(curr != NULL){ 47 | // Skip M nodes, reach to the mth node 48 | for(int i=0; i < m-1 && curr != NULL; i++){ 49 | curr = curr->next; 50 | } 51 | if(curr == NULL) return; 52 | 53 | del_ptr = curr->next; 54 | 55 | // Delete N nodes, reach to the node and replace pointers 56 | for(int i=0; i < n && del_ptr != NULL; i++){ 57 | temp = del_ptr; 58 | del_ptr = del_ptr->next; 59 | free(temp); 60 | } 61 | 62 | curr->next = del_ptr; 63 | curr = curr->next; 64 | } 65 | } 66 | 67 | int main() { 68 | LinkedList* ll = new LinkedList(); 69 | 70 | // Create Linked list 71 | ll->insert_at_beg(8); 72 | ll->insert_at_beg(7); 73 | ll->insert_at_beg(6); 74 | ll->insert_at_beg(5); 75 | ll->insert_at_beg(4); 76 | ll->insert_at_beg(3); 77 | ll->insert_at_beg(2); 78 | ll->insert_at_beg(1); 79 | 80 | cout << "Linked list before removal: " << endl; 81 | ll->print_data(); 82 | int k = 3; 83 | int m = 2, n = 3; 84 | skip_m_delete_n(ll, m, n); 85 | cout << "Linked list after skip "<< m << " delete " << n << ": "<< endl; 86 | ll->print_data(); 87 | return 0; 88 | } 89 | 90 | 91 | -------------------------------------------------------------------------------- /LinkedList/SkipMDeleteN.py: -------------------------------------------------------------------------------- 1 | # Python program to skip M nodes and then delete N nodes alternately in a singly linked list 2 | 3 | 4 | # Node class 5 | class Node: 6 | 7 | # Constructor to initialise data and next 8 | def __init__(self, data=None): 9 | self.data = data 10 | self.next = None 11 | 12 | 13 | class SinglyLinkedList: 14 | 15 | # Constructor to initialise head 16 | def __init__(self): 17 | self.head = None 18 | 19 | # Function to skip M delete N nodes 20 | def skip_m_delete_n(self, m, n): 21 | current = self.head 22 | 23 | # if list is empty return 24 | if current is None: 25 | return 26 | 27 | # Main loop to traverse the whole list 28 | while current is not None: 29 | # loop to skip M nodes 30 | for i in range(1, m): 31 | if current is None: 32 | return 33 | current = current.next 34 | 35 | if current is None: 36 | return 37 | 38 | # loop to delete N nodes 39 | temp = current.next 40 | for i in range(1, n+1): 41 | if temp is None: 42 | break 43 | temp = temp.next 44 | 45 | # Point the last node skipped to the node after N nodes deletion 46 | current.next = temp 47 | # set current for next iteration 48 | current = temp 49 | 50 | # Function to Insert data at the beginning of the linked list 51 | def insert_at_beg(self, data): 52 | node = Node(data) 53 | node.next = self.head 54 | self.head = node 55 | 56 | # Function to print the linked list 57 | def print_data(self): 58 | current = self.head 59 | while current is not None: 60 | print(current.data, '-> ', end='') 61 | current = current.next 62 | print('None') 63 | 64 | if __name__ == '__main__': 65 | linked_list = SinglyLinkedList() 66 | linked_list.insert_at_beg(9) 67 | linked_list.insert_at_beg(8) 68 | linked_list.insert_at_beg(7) 69 | linked_list.insert_at_beg(6) 70 | linked_list.insert_at_beg(5) 71 | linked_list.insert_at_beg(4) 72 | linked_list.insert_at_beg(3) 73 | linked_list.insert_at_beg(2) 74 | linked_list.insert_at_beg(1) 75 | 76 | linked_list.print_data() 77 | 78 | # call the skip_m_delete_n function 79 | linked_list.skip_m_delete_n(2, 2) 80 | 81 | # print the modified linked list 82 | linked_list.print_data() 83 | -------------------------------------------------------------------------------- /Mathematics/Factorial_Trailing_Zeros.cpp: -------------------------------------------------------------------------------- 1 | // Find the number of trailing zeros present in the factorial of a number n. 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | int fact_trailing_zeros(int num){ 8 | int c = 5; 9 | int count = 0; 10 | 11 | // count number of factors of 5 possible in num! 12 | // 5 paired with 2 will give 10 i.e. 1 trailing zero 13 | // powers of 5 will give multiple zeros 14 | while(num / c != 0){ 15 | count += num / c; 16 | c *= 5; 17 | } 18 | return count; 19 | } 20 | 21 | int main(){ 22 | 23 | int num = 1000; 24 | cout << num<< "! has " << fact_trailing_zeros(num) << " trailing zeros"<< endl; 25 | return 0; 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Mathematics/Factorial_Trailing_Zeros.py: -------------------------------------------------------------------------------- 1 | # Find the number of trailing zeros present in the factorial of a number n. 2 | 3 | def fact_trailing_zeros(num): 4 | c = 5 5 | count = 0 6 | 7 | # count number of factors of 5 possible in num! 8 | # 5 paired with 2 will give 10 i.e. 1 trailing zero 9 | # powers of 5 will give multiple zeros 10 | while num // c != 0: 11 | count += num // c 12 | c *= 5 13 | 14 | return count 15 | 16 | num = 1000 17 | print(f"{num}! has {fact_trailing_zeros(num)} trailing zeros") 18 | -------------------------------------------------------------------------------- /Mathematics/GCD.py: -------------------------------------------------------------------------------- 1 | # Basic eucledian algorithm to find the greatest common divisor of 2 numbers 2 | 3 | 4 | def gcd(a, b): 5 | if a == 0: 6 | return b 7 | return gcd(b % a, a) 8 | 9 | print(gcd(10, 15)) 10 | -------------------------------------------------------------------------------- /Mathematics/Prime_factors.py: -------------------------------------------------------------------------------- 1 | # print all prime factors of a given number 2 | """Given a number n, write an efficient function to print all prime factors of n. 3 | For example, if the input number is 12, then output should be “2 2 3”.""" 4 | 5 | from math import sqrt 6 | 7 | 8 | def prime_factors(num): 9 | # list to store the prime factors 10 | prime_factor_lis = [] 11 | 12 | # if 2 is a factor of the number 13 | while num % 2 == 0: 14 | prime_factor_lis.append(2) 15 | num /= 2 16 | 17 | for i in range(3, int(sqrt(num)), 2): 18 | while num % i == 0: 19 | prime_factor_lis.append(i) 20 | num /= i 21 | 22 | return prime_factor_lis 23 | 24 | if __name__ == '__main__': 25 | print(prime_factors(315)) 26 | 27 | 28 | -------------------------------------------------------------------------------- /Mathematics/Sieve_of_Eratosthenes.py: -------------------------------------------------------------------------------- 1 | # Given a number n, print all primes smaller than or equal to n. It is also given that n is a small number. 2 | """ The sieve of Eratosthenes is one of the most efficient ways to find all primes smaller than n when n is 3 | smaller than 10 million or so """ 4 | 5 | 6 | # function to find prime numbers less than or equal to num 7 | def find_primes_sieve(num): 8 | # list of all numbers upto n 9 | intList = [True for i in range(num+1)] 10 | 11 | # first prime 12 | p = 2 13 | 14 | while p * p <= num: 15 | 16 | # if intList[p] is True means its a prime number 17 | if intList[p]: 18 | for i in range(p**2, num+1, p): 19 | intList[i] = False 20 | 21 | p += 1 22 | 23 | lis = [] 24 | for i in range(2, len(intList)): 25 | if intList[i]: 26 | lis.append(i) 27 | 28 | return lis 29 | 30 | if __name__ == '__main__': 31 | primes = find_primes_sieve(30) 32 | print(primes) 33 | -------------------------------------------------------------------------------- /Matrix/CheckQueenThreatsKing.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given the Coordinates of King and Queen on a chessboard, check if queen threatens the king. 3 | """ 4 | 5 | 6 | def check_threat(king_x, king_y, queen_x, queen_y): 7 | # If coordinates are non-integer or outside the bounds of the chessboard 8 | if not (validate(king_x) and validate(king_y) and validate(queen_x) and validate(queen_y)): 9 | return False 10 | 11 | # if king is in the vertical column of queen, king_x = queen_x 12 | # if king is in the horizontal row of queen, king_y = queen_y 13 | # if king is in the diagonal of queen, abs(king_y - queen_y) = abs(king_x - queen_x) because the will form a square 14 | if king_x == queen_x or king_y == queen_y or abs(king_y - queen_y) == abs(king_x - queen_x): 15 | return True 16 | 17 | return False 18 | 19 | 20 | def validate(coordinate): 21 | if type(coordinate) is int and 1 <= coordinate <= 8: 22 | return True 23 | 24 | return False 25 | 26 | 27 | print("Queen threatens King") if check_threat(1, 1, 5, 5) else print("Queen does not threaten King") 28 | -------------------------------------------------------------------------------- /Matrix/SearchRowColumnSorted.py: -------------------------------------------------------------------------------- 1 | """Given an n x n matrix, where every row and column is sorted in increasing order. 2 | Given a number x, how to decide whether this x is in the matrix.""" 3 | 4 | 5 | def search(mat, x): 6 | n = len(mat) 7 | i = 0 8 | j = n-1 9 | while i < n and j >= 0: 10 | if mat[i][j] == x: 11 | return i, j 12 | elif mat[i][j] < x: 13 | i += 1 14 | else: 15 | j -= 1 16 | return [-1] 17 | 18 | 19 | matrix = [[10, 20, 30, 40], 20 | [15, 25, 35, 45], 21 | [27, 29, 37, 48], 22 | [32, 33, 39, 50] 23 | ] 24 | 25 | print("Enter element you want to search: ") 26 | element = int(input()) 27 | index = search(matrix, element) 28 | if len(index) == 1: 29 | print("Element not found") 30 | else: 31 | print("element found at position:(", index[0], ",", index[1], ")") 32 | -------------------------------------------------------------------------------- /Matrix/SpiralPrint.py: -------------------------------------------------------------------------------- 1 | # Given a 2D array, print it in spiral form. 2 | """Input: 3 | 1 2 3 4 4 | 5 6 7 8 5 | 9 10 11 12 6 | 13 14 15 16 7 | Output: 8 | 1 2 3 4 8 12 16 15 14 13 9 5 6 7 11 10 9 | """ 10 | 11 | 12 | def print_spiral(mat): 13 | row, col = len(mat), len(mat[0]) 14 | k = 0 15 | l = 0 16 | while k < row and l < col: 17 | for i in range(col): 18 | print(mat[k][i], end=' ') 19 | k += 1 20 | 21 | for i in range(k, row): 22 | print(mat[i][col-1], end=' ') 23 | col -= 1 24 | 25 | if k < row: 26 | for i in reversed(range(l, col-1)): 27 | print(mat[row-1][i], end=' ') 28 | row -= 1 29 | 30 | if l < col: 31 | for i in reversed(range(k, row-1)): 32 | print(mat[i][l], end=' ') 33 | l += 1 34 | 35 | 36 | a = [[1, 2, 3, 4, 5, 6], 37 | [7, 8, 9, 10, 11, 12], 38 | [13, 14, 15, 16, 17, 18] 39 | ] 40 | 41 | print_spiral(a) 42 | -------------------------------------------------------------------------------- /Misc/Flatten_Dictionary.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def flatten_dict(initialVal, dictionary, flatDictionary): 4 | for key in dictionary: 5 | value = dictionary[key] 6 | if type(value) is not dict: 7 | if initialVal is None: 8 | flatDictionary[key] = value 9 | else: 10 | flatDictionary[initialVal + '.' + key] = value 11 | else: 12 | if initialVal is None: 13 | flatten_dict(key, value, flatDictionary) 14 | else: 15 | flatten_dict(initialVal + '.' + key, value, flatDictionary) 16 | 17 | 18 | # iterative solution 19 | def flatten_dict2(dictionary): 20 | flatDictionary = {} 21 | stack = [(dictionary, None)] 22 | while stack: 23 | d, path = stack.pop() 24 | 25 | for k, v in d.items(): 26 | if path is None: 27 | newkey = k 28 | else: 29 | newkey = '.'.join([path, k]) 30 | if isinstance(v, dict): 31 | stack.append((v, newkey)) 32 | else: 33 | flatDictionary[newkey] = v 34 | return flatDictionary 35 | 36 | 37 | if __name__ == '__main__': 38 | flatDictionary = {} 39 | dictionary = { 40 | 'Key1': '1', 41 | 'Key2': { 42 | 'a': '2', 43 | 'b': '3', 44 | 'c': { 45 | 'd': '3', 46 | 'e': '1' 47 | } 48 | } 49 | } 50 | 51 | # recursive function call 52 | flatten_dict(None, dictionary, flatDictionary) 53 | 54 | # iterative function call 55 | f = flatten_dict2(dictionary) 56 | 57 | for k in f: 58 | print(k, ":", f[k]) 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Data Structures and Algorithms 2 | 3 | My implementation of some popular data structures and algorithms and interview questions relating to them in Python 3 and C++ 4 | 5 | ## Index: 6 | 7 | - [Data Structures and Algorithms](#Data-Structures-and-Algorithms) 8 | - [Index:](#Index) 9 | - [Content:](#Content) 10 | - [Bit Manipulation](#Bit-Manipulation) 11 | - [Dynamic Programming](#Dynamic-Programming) 12 | - [Graph](#Graph) 13 | - [Heaps](#Heaps) 14 | - [Linked List](#Linked-List) 15 | - [Singly Linked List](#Singly-Linked-List) 16 | - [Mathematics](#Mathematics) 17 | - [Matrix](#Matrix) 18 | - [Misc](#Misc) 19 | - [String or Array](#String-or-Array) 20 | - [Searching](#Searching) 21 | - [Sorting](#Sorting) 22 | - [Tree](#Tree) 23 | - [Binary Search Tree](#Binary-Search-Tree) 24 | - [Binary Tree](#Binary-Tree) 25 | - [Trie](#Trie) 26 | 27 | ------------------------------------------------------------------------------ 28 | ## Content: 29 | 30 | ### Bit Manipulation 31 | 32 | Contains some popular questions based on *bit manipulations*. 33 | 34 | | Topic/Question | Code in Python | Code in C++ | 35 | |-----------------------------------|:------------------:|:-----------------:| 36 | |Check whether a given number n is a power of 2 or 0 |[py](Bit_Manipulation/Check_Pow_2.py) |[cpp](Bit_Manipulation/Check_Pow_2.cpp)| 37 | |Count number of bits needed to be flipped to convert A to B |[py](Bit_Manipulation/Count_Bits_Flip_A_B.py) |[cpp](Bit_Manipulation/Count_Bits_Flip_A_B.cpp)| 38 | |Find the two non-repeating elements in an array of repeating elements |[py](Bit_Manipulation/Find_Non_Repeating.py) |[cpp](Bit_Manipulation/Find_Non_Repeating.cpp)| 39 | |Find the next greater and next smaller number with same number of set bits |[py](Bit_Manipulation/Next_Number.py) |[cpp](Bit_Manipulation/Next_Number.cpp)| 40 | 41 | ------------------------------------------------------------------------------ 42 | ### Dynamic Programming 43 | 44 | Contains some popular questions based on *dynamic programming approach*. 45 | 46 | | Topic/Question | Code in Python | Code in C++ | 47 | |-----------------------------------|:------------------:|:-----------------:| 48 | | 0-1 Knapsack Problem |[py](DynamicProgramming/01_KnapsackProblem.py)| [-](DynamicProgramming/01_KnapsackProblem.cpp)| 49 | |Cutting Rod problem |[py](DynamicProgramming/CuttingRod.py)| [-](DynamicProgramming/CuttingRod.cpp)| 50 | | minimum number of edits (operations) required to convert ‘str1’ into ‘str2’ |[py](DynamicProgramming/EditDistance.py)|[-](DynamicProgramming/EditDistance.cpp)| 51 | | Given a 2-D matrix of 0s and 1s, find the Largest Square which contains all 1s in itself |[py](DynamicProgramming/LargestSquareInMatrix.py)|[-](DynamicProgramming/LargestSquareInMatrix.cpp)| 52 | |Given two sequences, print the longest subsequence present in both of them. |[py](DynamicProgramming/LongestCommonSubsequence.py)|[-](DynamicProgramming/LongestCommonSubsequence.cpp)| 53 | |Length of the longest subsequence in an array such that all elements of the subsequence are sorted in increasing order |[py](DynamicProgramming/LongestIncreasingSubsequence.py)|[-](DynamicProgramming/LongestIncreasingSubsequence.cpp)| 54 | |Find minimum cost path in a matrix from (0,0) to given point (m,n) |[py](DynamicProgramming/MinCostPath.py)| [-](DynamicProgramming/MinCostPath.cpp)| 55 | |Partition a set into two subsets such that the difference of subset sums is minimum |[py](DynamicProgramming/MinimumPartition.py)|[-](DynamicProgramming/MinimumPartition.cpp)| 56 | |Minimum number of umbrellas of m different sizes required to accomodate N people |[py](DynamicProgramming/MinUmbrellaNeeded.py)|[cpp](DynamicProgramming/MinUmbrellaNeeded.cpp)| 57 | |Determine if there is a subset of the given set with sum equal to given sum |[py](DynamicProgramming/SubsetSum.py)|[-](DynamicProgramming/SubsetSum.cpp)| 58 | | Maximum Subarray Problem |[py](DynamicProgramming/TheMaximumSubarray.py)|[-](DynamicProgramming/TheMaximumSubarray.cpp)| 59 | |Given a distance ‘dist, count total number of ways to cover the distance with 1, 2 and 3 steps |[py](DynamicProgramming/WaysToCoverDistance.py)|[-](DynamicProgramming/WaysToCoverDistance.cpp)| 60 | 61 | ------------------------------------------------------------------------------ 62 | ### Graph 63 | 64 | Contains implementation of Graph data structure and some common questions and algorithms related to it. 65 | 66 | | Topic/Question | Code in Python | Code in C++ | 67 | |-----------------------------------|:------------------:|:-----------------:| 68 | |Find all possible words in a board of characters |[py](Graph/Boggle.py)|[-](Graph/Boggle.cpp)| 69 | | Breadth First Search Traversal |[py](Graph/BreadthFirstTraversal.py)|[-](Graph/BreadthFirstTraversal.cpp)| 70 | | Depth First Search Traversal |[py](Graph/DepthFirstTraversal.py)|[-](Graph/DepthFirstTraversal.cpp)| 71 | | Detect Cycle in directed graph |[py](Graph/DetectCycleDirected.py)|[-](Graph/DetectCycleDirected.cpp)| 72 | |Detect cycle in undirected graph |[py](Graph/DetectCycleUndirected.py)|[-](Graph/DetectCycleUndirected.cpp)| 73 | |Dijkstra’s Shortest Path Algorithm |[py](Graph/DijkstraShortestPath.py)|[-](Graph/DijkstraShortestPath.cpp)| 74 | |Find shortest distances between each pair of vertices in a given edge weighted directed Graph |[py](Graph/FloydWarshall_AllPairsShortestPath.py)|[-](Graph/FloydWarshall_AllPairsShortestPath.cpp)| 75 | | Graph implementation |[py](Graph/Graph.py)|[-](Graph/Graph.cpp)| 76 | | Kruskal's Algorithm for Minimum Spanning Tree |[py](Graph/KruskalMST.py)|[-](Graph/KruskalMST.cpp)| 77 | | Topological Sort |[py](Graph/TopologicalSort.py)|[-](Graph/TopologicalSort.cpp)| 78 | 79 | ------------------------------------------------------------------------------ 80 | ### Heaps 81 | 82 | Contains implementation of Heap data structure and some common questions and algorithms related to it. 83 | 84 | | Topic/Question | Code in Python | Code in C++ | 85 | |-----------------------------------|:------------------:|:-----------------:| 86 | | Heap Sort algorithm |[py](Heaps/HeapSort.py)|[-](Heaps/HeapSort.cpp)| 87 | | Max Heap implementation |[py](Heaps/MaxHeap.py)|[-](Heaps/MaxHeap.cpp)| 88 | | Min Heap implementation |[py](Heaps/MinHeap.py)|[-](Heaps/MinHeap.cpp)| 89 | |Find the median for an incoming stream of numbers after each insertion in the list of numbers |[py](Heaps/RunningMedian.py)|[-](Heaps/RunningMedian.cpp)| 90 | 91 | ------------------------------------------------------------------------------ 92 | ### Linked List 93 | 94 | Contains implementation of Linked List data structure and some common questions and algorithms related to it. 95 | 96 | ##### Singly Linked List 97 | 98 | | Topic/Question | Code in Python | Code in C++ | 99 | |-----------------------------------|:------------------:|:-----------------:| 100 | |Clone a linked list with next and random pointer |[py](LinkedList/CloneRandomPointerList.py)|[-](LinkedList/CloneRandomPointerList.cpp)| 101 | |Given a linked list of line segments, remove middle points if any |[py](LinkedList/LineRemoveMiddlePoints.py)|[-](LinkedList/LineRemoveMiddlePoints.cpp)| 102 | |Construct a Maximum Sum Linked List out of two Sorted Linked Lists having some Common nodes. |[py](LinkedList/MaxSumLinkedList.py)|[-](LinkedList/MaxSumLinkedList.cpp)| 103 | |Merge a linked list into another linked list at alternate positions |[py](LinkedList/MergeAlt.py)|[-](LinkedList/MergeAlt.cpp)| 104 | | Perform Merge Sort |[py](LinkedList/MergeSort.py)|[-](LinkedList/MergeSort.cpp)| 105 | | Find Middle Node |[py](LinkedList/MiddleNode.py)|[cpp](LinkedList/MiddleNode.cpp)| 106 | |Point to next higher value node in a linked list with an arbitrary pointer |[py](LinkedList/NextHigerValueNode.py)|[-](LinkedList/NextHigerValueNode.cpp)| 107 | | Find if linked list contains any cycle |[py](LinkedList/NullOrCycle.py)|[-](LinkedList/NullOrCycle.cpp)| 108 | |To select a random node in a singly linked list |[py](LinkedList/Random_Node.py)|[-](LinkedList/Random_Node.cpp)| 109 | | Find and remove cycle if any |[py](LinkedList/RemoveCycle.py)|[cpp](LinkedList/RemoveCycle.cpp)| 110 | | Reverse sub list of K nodes each |[py](LinkedList/ReverseKNodes.py)|[cpp](LinkedList/ReverseKNodes.cpp)| 111 | | Reverse alternate sub list of K nodes each |[py](LinkedList/Reverse_Alt_K_Nodes.py)|[cpp](LinkedList/Reverse_Alt_K_Nodes.cpp)| 112 | | Reverse a linked list |[py](LinkedList/ReverseSLL.py)|[cpp](LinkedList/ReverseSLL.cpp)| 113 | | Bring even valued nodes to the front |[py](LinkedList/SegregateEvenOdd.py)|[-](LinkedList/SegregateEvenOdd.cpp)| 114 | | Implementation of Singly Linked List |[py](LinkedList/SinglyLinkedList.py)|[cpp](LinkedList/SinglyLinkedList.cpp)| 115 | |Skip M nodes and then delete N nodes alternately |[py](LinkedList/SkipMDeleteN.py)|[cpp](LinkedList/SkipMDeleteN.cpp)| 116 | 117 | ------------------------------------------------------------------------------ 118 | ### Mathematics 119 | 120 | Contains implementation of some common questions and algorithms related to Mathematics. 121 | 122 | | Topic/Question | Code in Python | Code in C++ | 123 | |-----------------------------------|:------------------:|:-----------------:| 124 | |Fine the number of trailing zeros in factorial of a number |[py](Mathematics/Factorial_Trailing_Zeros.py)|[cpp](Mathematics/Factorial_Trailing_Zeros.cpp)| 125 | |Find the greatest common divisor of 2 numbers |[py](Mathematics/GCD.py)|[-](Mathematics/GCD.cpp)| 126 | | print all prime factors of a given number |[py](Mathematics/Prime_factors.py)|[-](Mathematics/Prime_factors.cpp)| 127 | | Sieve of Eratosthenes (find prime numbers up to n efficiently) |[py](Mathematics/Sieve_of_Eratosthenes.py)|[-](Mathematics/Sieve_of_Eratosthenes.cpp)| 128 | 129 | ------------------------------------------------------------------------------ 130 | ### Matrix 131 | 132 | Contains some common algorithms and questions based on *Matrix*. 133 | 134 | | Topic/Question | Code in Python | Code in C++ | 135 | |-----------------------------------|:------------------:|:-----------------:| 136 | |Given the Coordinates of King and Queen on a chessboard, check if queen threatens the king |[py](Matrix/CheckQueenThreatsKing.py)|[-](Matrix/CheckQueenThreatsKing.cpp)| 137 | |Search in a row wise and column wise sorted matrix |[py](Matrix/SearchRowColumnSorted.py)|[-](Matrix/SearchRowColumnSorted.cpp)| 138 | |Given a 2D array, print it in spiral form |[py](Matrix/SpiralPrint.py)|[-](Matrix/SpiralPrint.cpp)| 139 | 140 | ------------------------------------------------------------------------------ 141 | ### Misc 142 | 143 | Contains some miscellaneous questions and algorithms. 144 | 145 | | Topic/Question | Code in Python | Code in C++ | 146 | |-----------------------------------|:------------------:|:-----------------:| 147 | |Given a dictionary, write a function to flatten it |[py](Misc/Flatten_Dictionary.py)|[-](Misc/Flatten_Dictionary.cpp)| 148 | 149 | ------------------------------------------------------------------------------ 150 | ### String or Array 151 | 152 | Contains some common questions and algorithms related to strings or 1-d arrays. 153 | 154 | | Topic/Question | Code in Python | Code in C++ | 155 | |-----------------------------------|:------------------:|:-----------------:| 156 | |Find the longest substring with k unique characters in a given string |[py](String_or_Array/K_Unique_Substring.py)|[-](String_or_Array/K_Unique_Substring.cpp)| 157 | |Find a pattern in a string using KMP search algorithm |[py](String_or_Array/KMP_StringMatching.py)|[-](String_or_Array/KMP_StringMatching.cpp)| 158 | |Find the Kth smallest element in the array |[py](String_or_Array/Kth_Smallest.py)|[-](String_or_Array/Kth_Smallest.cpp)| 159 | |Find a pair in an array with sum x |[py](String_or_Array/PairSum_is_X.py)|[-](String_or_Array/PairSum_is_X.cpp)| 160 | |Print all valid (properly opened and closed) combinations of n pairs of parentheses|[py](String_or_Array/ParenthesesCombinations.py)|[-](String_or_Array/ParenthesesCombinations.cpp)| 161 | |reverse the order of the words in the array |[py](String_or_Array/Sentence_Reverse.py)|[-](String_or_Array/Sentence_Reverse.cpp)| 162 | |Find index of given number in a sorted array shifted by an unknown offset |[py](String_or_Array/Shifted_Array_Search.py)|[-](String_or_Array/Shifted_Array_Search.cpp)| 163 | |Print all permutations of a given string |[py](String_or_Array/StringPermutations.py)|[-](String_or_Array/StringPermutations.cpp)| 164 | 165 | #### Searching 166 | 167 | | Topic/Question | Code in Python | Code in C++ | 168 | |-----------------------------------|:------------------:|:-----------------:| 169 | |Linear Search in an array |[py](String_or_Array/Searching/Linear_Search.py)|[-](String_or_Array/Searching/Linear_Search.cpp)| 170 | |Binary Search in an array |[py](String_or_Array/Searching/Binary_Search.py)|[-](String_or_Array/Searching/Binary_Search.cpp)| 171 | |Interpolation Search in an array |[py](String_or_Array/Searching/Interpolation_Search.py)|[-](String_or_Array/Searching/Interpolation_Search.cpp)| 172 | 173 | #### Sorting 174 | 175 | | Topic/Question | Code in Python | Code in C++ | 176 | |-----------------------------------|:------------------:|:-----------------:| 177 | |Bubble sort Algorithm |[py](String_or_Array/Sorting/Bubble_Sort.py)|[-](String_or_Array/Sorting/Bubble_Sort.cpp)| 178 | |Counting sort Algorithm (non-comparision based sorting) |[py](String_or_Array/Sorting/Counting_Sort.py)|[-](String_or_Array/Sorting/Counting_Sort.cpp)| 179 | |Insertion sort Algorithm |[py](String_or_Array/Sorting/Insertion_Sort.py)|[-](String_or_Array/Sorting/Insertion_Sort.cpp)| 180 | |Sort an array where each element is at most k places away from its sorted position |[py](String_or_Array/Sorting/K_Messed_Sort.py)|[-](String_or_Array/Sorting/K_Messed_Sort.cpp)| 181 | |Merge Sort Algorithm |[py](String_or_Array/Sorting/Merge_Sort.py)|[-](String_or_Array/Sorting/Merge_Sort.cpp)| 182 | |Quick Sort Algorithm using last element as pivot |[py](String_or_Array/Sorting/Quick_Sort.py)|[-](String_or_Array/Sorting/Quick_Sort.cpp)| 183 | |Selection sort Algorithm |[py](String_or_Array/Sorting/Selection_Sort.py)|[-](String_or_Array/Sorting/Selection_Sort.cpp)| 184 | 185 | ------------------------------------------------------------------------------ 186 | ### Tree 187 | 188 | Contains implementation of Tree data structure and some common questions and algorithms related to it. 189 | 190 | ##### Binary Search Tree 191 | 192 | | Topic/Question | Code in Python | Code in C++ | 193 | |-----------------------------------|:------------------:|:-----------------:| 194 | | Binary Search Tree implementation |[py](Tree/BinarySearchTree/BST.py)|[-](Tree/BinarySearchTree/BST.cpp)| 195 | |Check if a given array can represent Preorder Traversal of Binary Search Tree |[py](Tree/BinarySearchTree/Check_Correct_Preorder.py)|[-](Tree/BinarySearchTree/Check_Correct_Preorder.cpp)| 196 | |Find the in-order ancestor of a given node in BST |[py](Tree/BinarySearchTree/InOrder_Ancestor.py)|[-](Tree/BinarySearchTree/InOrder_Ancestor.cpp)| 197 | |Find the Lowest Common Ancestor |[py](Tree/BinarySearchTree/Lowest_Common_Ancestor.py)|[-](Tree/BinarySearchTree/Lowest_Common_Ancestor.cpp)| 198 | |Given a sorted array, create a BST with minimal height |[py](Tree/BinarySearchTree/Minimal_Tree.py)|[-](Tree/BinarySearchTree/Minimal_Tree.cpp)| 199 | 200 | ##### Binary Tree 201 | 202 | | Topic/Question | Code in Python | Code in C++ | 203 | |-----------------------------------|:------------------:|:-----------------:| 204 | |Print Nodes in Bottom View of Binary Tree |[py](Tree/BinaryTree/Bottom_View.py)|[-](Tree/BinaryTree/Bottom_View.cpp)| 205 | |Check if a binary tree is height balanced |[py](Tree/BinaryTree/Check_Balanced.py)|[-](Tree/BinaryTree/Check_Balanced.cpp)| 206 | |Check whether a binary tree is a full binary tree or not |[py](Tree/BinaryTree/Check_Full_BinaryTree.py)|[-](Tree/BinaryTree/Check_Full_BinaryTree.cpp)| 207 | |Given two binary trees, check if the first tree is subtree of the second one |[py](Tree/BinaryTree/Is_SubTree.py)|[-](Tree/BinaryTree/Is_SubTree.cpp)| 208 | |Find the Lowest Common Ancestor in a Binary Tree |[py](Tree/BinaryTree/Lowest_Common_Ancestor.py)|[-](Tree/BinaryTree/Lowest_Common_Ancestor.cpp)| 209 | |Create a list of all nodes at each depth |[py](Tree/BinaryTree/List_Of_Depths.py)|[-](Tree/BinaryTree/List_Of_Depths.cpp)| 210 | |Find the maximum path sum i.e. max sum of a path in a binary tree |[py](Tree/BinaryTree/Max_Path_Sum.py)|[-](Tree/BinaryTree/Max_Path_Sum.cpp)| 211 | | Find minimum depth of a binary tree |[py](Tree/BinaryTree/Minimum_height.py)|[-](Tree/BinaryTree/Minimum_height.cpp)| 212 | |Remove nodes on root to leaf paths of length < K |[py](Tree/BinaryTree/Remove_Path_Less_Than_K.py)|[-](Tree/BinaryTree/Remove_Path_Less_Than_K.cpp)| 213 | |Given a Perfect Binary Tree, reverse the alternate level nodes of the tree |[py](Tree/BinaryTree/Reverse_Alternate_Levels_PBT.py)|[-](Tree/BinaryTree/Reverse_Alternate_Levels_PBT.cpp)| 214 | |Print Nodes in Top View of Binary Tree |[py](Tree/BinaryTree/Top_View.py)|[-](Tree/BinaryTree/Top_View.cpp)| 215 | 216 | ##### Trie 217 | 218 | | Topic/Question | Code in Python | Code in C++ | 219 | |-----------------------------------|:------------------:|:-----------------:| 220 | |Implementation of Trie data structure |[py](Tree/Trie/Trie.py)|[-](Tree/Trie/Trie.cpp)| 221 | 222 | ------------------------------------------------------------------------------ 223 | -------------------------------------------------------------------------------- /String_or_Array/KMP_StringMatching.py: -------------------------------------------------------------------------------- 1 | # To find indexes of String "Pattern" in a given String "Text" using KMP Algorithm 2 | 3 | 4 | # function that returns list of indexes where the patters matches 5 | def KMP_Search(pattern, text): 6 | n = len(text) 7 | m = len(pattern) 8 | 9 | # pre-compute prefix array of the pattern 10 | prefix_arr = get_prefix_arr(pattern, m) 11 | 12 | # stores start point of pattern match in text 13 | start_points = [] 14 | 15 | i = 0 16 | j = 0 17 | 18 | # while the whole text has not been searched 19 | while i != n: 20 | # if the character in text matches the pattern character 21 | if text[i] == pattern[j]: 22 | i += 1 23 | j += 1 24 | # else find the previous index from where the matching can resume 25 | else: 26 | j = prefix_arr[j-1] 27 | 28 | # if pattern length has been reached that means a pattern has been found 29 | if j == m: 30 | start_points.append(i-j) 31 | j = prefix_arr[j-1] 32 | elif j == 0: 33 | i += 1 34 | # return the starting position of pattern in text 35 | return start_points 36 | 37 | 38 | # pre-computes the prefix array for KMP search 39 | def get_prefix_arr(pattern, m): 40 | prefix_arr = [0] * m 41 | j = 0 42 | i = 1 43 | 44 | while i != m: 45 | if pattern[i] == pattern[j]: 46 | j += 1 47 | prefix_arr[i] = j 48 | i += 1 49 | elif j != 0: 50 | j = prefix_arr[j-1] 51 | else: 52 | prefix_arr[i] = 0 53 | i += 1 54 | 55 | return prefix_arr 56 | 57 | txt = "ABABDABACDABABCABABCABAB" 58 | pat = "ABABCABAB" 59 | 60 | start_indexes = KMP_Search(pat, txt) 61 | 62 | for i in start_indexes: 63 | print(i) 64 | -------------------------------------------------------------------------------- /String_or_Array/K_Unique_Substring.py: -------------------------------------------------------------------------------- 1 | # Find the longest substring with k unique characters in a given string 2 | 3 | 4 | def longest_k_unique(string, k): 5 | unique = 0 6 | sets = set({}) 7 | 8 | for i in string: 9 | if i not in sets: 10 | sets.add(i) 11 | unique += 1 12 | 13 | if unique < k: 14 | return -1, -1 15 | 16 | count = [0] * 26 17 | curr_end = curr_start = max_window_start = 0 18 | max_window_len = 1 19 | 20 | count[ord(string[0]) - ord('a')] += 1 21 | for i in range(1, len(string)): 22 | count[ord(string[i]) - ord('a')] += 1 23 | curr_end += 1 24 | 25 | while not isValid(count, k): 26 | count[ord(string[curr_start]) - ord('a')] -= 1 27 | curr_start += 1 28 | 29 | if curr_end - curr_start + 1 > max_window_len: 30 | max_window_len = curr_end - curr_start + 1 31 | max_window_start = curr_start 32 | 33 | return max_window_start, max_window_len 34 | 35 | 36 | def isValid(count, k): 37 | val = 0 38 | for i in count: 39 | if i > 0: 40 | val += 1 41 | 42 | return k >= val 43 | 44 | 45 | if __name__ == '__main__': 46 | string = 'aabaabab' 47 | k = 3 48 | max_start, max_len = longest_k_unique(string, k) 49 | 50 | if max_len == -1: 51 | print("K unique characters sub string does not exist.") 52 | else: 53 | print('max string with {} unique characters is "'.format(k) + string[max_start: max_start + max_len] + 54 | '" of length', max_len) 55 | -------------------------------------------------------------------------------- /String_or_Array/Kth_Smallest.py: -------------------------------------------------------------------------------- 1 | # Find the Kth smallest element in a given array. 2 | # taking smallest in arr as 1st smallest 3 | 4 | """ 5 | Approach used: QuickSelect 6 | Time Complexity: O(n) 7 | """ 8 | 9 | 10 | def partition(arr, low, high): 11 | i = (low - 1) 12 | pivot = arr[high] # pivot 13 | 14 | for j in range(low, high): 15 | 16 | # If current element is smaller than or 17 | # equal to pivot 18 | if arr[j] <= pivot: 19 | # increment index of smaller element 20 | i += 1 21 | arr[i], arr[j] = arr[j], arr[i] 22 | 23 | arr[i + 1], arr[high] = arr[high], arr[i + 1] 24 | return i + 1 25 | 26 | 27 | def quick_select(arr, low, high, k): 28 | # arr follows zero indexing hence kth smallest will be at index (k - 1) 29 | k -= 1 30 | while low < high: 31 | p_index = partition(arr, low, high) 32 | 33 | # found the kth smallest value 34 | if p_index == k: 35 | return arr[p_index] 36 | # pivot index is less than k hence kth smallest is in the right half 37 | elif p_index < k: 38 | low = p_index + 1 39 | # pivot index is greater than k hence kth smallest is in the left half 40 | else: 41 | high = p_index - 1 42 | # if k < 0 or k > len(arr) then simply return the smallest or largest value in arr 43 | return arr[low] 44 | 45 | 46 | arr = [10, 7, 8, 9, 1, 5] 47 | n = len(arr) - 1 48 | 49 | # find 4th smallest element in the array 50 | print(quick_select(arr, 0, n, 4)) 51 | 52 | 53 | -------------------------------------------------------------------------------- /String_or_Array/PairSum_is_X.py: -------------------------------------------------------------------------------- 1 | # Find a pair of elements in the array with sum = x 2 | 3 | """ 4 | Method 1: If unsorted array 5 | Time Complexity: O(n) 6 | Space Complexity: O(n) 7 | """ 8 | 9 | 10 | def find_pair_unsorted(arr, x): 11 | elem_set = set({}) 12 | 13 | # To store the indexes of both the elements 14 | pair = [-1, -1] 15 | 16 | for value in arr: 17 | # if x - value has already been discovered in the array 18 | # Pair found, return the values 19 | if (x-value) in elem_set: 20 | return x-value, value 21 | 22 | # else add the current value in the elem_set 23 | else: 24 | elem_set.add(value) 25 | 26 | return "Not found" 27 | 28 | arr = [1, 4, 45, 6, 10, 8] 29 | print('Unsorted array:', arr) 30 | print('Pair with sum 16 in unsorted array:', find_pair_unsorted(arr, 16)) 31 | 32 | 33 | """ 34 | Method 2: If array is sorted 35 | Time Complexity: O(n) 36 | Space Complexity: O(1) 37 | """ 38 | 39 | 40 | def find_pair_sorted(arr, x): 41 | # initialize variables to the start and end of the array 42 | l = 0 43 | r = len(arr) - 1 44 | 45 | while l < r: 46 | pair_sum = arr[l] + arr[r] 47 | 48 | # if pair is found 49 | if pair_sum == x: 50 | return arr[l], arr[r] 51 | # if the pair sum is less than x go to the next bigger value from left 52 | elif pair_sum < x: 53 | l += 1 54 | # if the pair sum is more than x go to the next lesser value from right 55 | else: 56 | r -= 1 57 | 58 | # If pair not found 59 | return "Not found" 60 | 61 | 62 | arr = [2, 6, 10, 15, 18, 20, 23, 25] 63 | print('Sorted array:', arr) 64 | print('Pair with sum 28 in sorted array:', find_pair_sorted(arr, 28)) 65 | -------------------------------------------------------------------------------- /String_or_Array/ParenthesesCombinations.py: -------------------------------------------------------------------------------- 1 | """ 2 | Print all valid (properly opened and closed) combinations of n pairs of parentheses. 3 | """ 4 | 5 | 6 | def addParentheses(str_arr, leftParenCount, rightParenCount, combinations, index): 7 | if leftParenCount < 0 or rightParenCount < 0: 8 | return 9 | if leftParenCount == 0 and rightParenCount == 0: 10 | combinations.append(''.join(str_arr)) 11 | else: 12 | if leftParenCount > 0: 13 | str_arr[index] = '(' 14 | addParentheses(str_arr, leftParenCount - 1, rightParenCount, combinations, index + 1) 15 | 16 | if rightParenCount > leftParenCount: 17 | str_arr[index] = ')' 18 | addParentheses(str_arr, leftParenCount, rightParenCount - 1, combinations, index + 1) 19 | 20 | 21 | def generateParentheses(count): 22 | str_arr = [''] * (count * 2) 23 | combinations = [] 24 | addParentheses(str_arr, count, count, combinations, 0) 25 | return combinations 26 | 27 | 28 | parenthesis_pairs = 3 29 | combinations = generateParentheses(parenthesis_pairs) 30 | print(*combinations, sep=', ') 31 | -------------------------------------------------------------------------------- /String_or_Array/Searching/Binary_Search.py: -------------------------------------------------------------------------------- 1 | # Function for binary search 2 | # inputs: sorted array 'arr', key to be searched 'x' 3 | # returns: index of the occurrence of x found in arr 4 | 5 | 6 | def binary_search(arr, x): 7 | l = 0 8 | r = len(arr) 9 | 10 | # while the left index marker < right index marker 11 | while l < r: 12 | # find the index of the middle element 13 | mid = int(l + ((r - l) / 2)) 14 | 15 | # if middle element is x, return mid 16 | if arr[mid] == x: 17 | return mid 18 | 19 | # if middle element is < x, update l to search to the right of mid 20 | elif arr[mid] < x: 21 | l = mid + 1 22 | 23 | # if middle element is > x, update r to search to the left of mid 24 | else: 25 | r = mid - 1 26 | 27 | return -1 28 | 29 | 30 | arr = [1, 4, 5, 7, 8, 10, 13, 15] 31 | print(binary_search(arr, 5)) 32 | -------------------------------------------------------------------------------- /String_or_Array/Searching/Interpolation_Search.py: -------------------------------------------------------------------------------- 1 | def interpolation_search(arr, key): 2 | low = 0 3 | high = len(arr) - 1 4 | 5 | while arr[high] != arr[low] and key >= arr[low] and key <= arr[high]: 6 | mid = int(low + ((key - arr[low]) * (high - low) / (arr[high] - arr[low]))) 7 | 8 | if arr[mid] == key: 9 | return mid 10 | elif arr[mid] < key: 11 | low = mid + 1 12 | else: 13 | high = mid - 1 14 | 15 | return -1 16 | 17 | 18 | # input arr 19 | arr = [2, 4, 6, 8, 10, 12, 14, 16] 20 | 21 | # interpolation_search call to search 3 in arr 22 | print('6 is at index: ', interpolation_search(arr, 6)) 23 | 24 | # Output: 6 is at index: 2 -------------------------------------------------------------------------------- /String_or_Array/Searching/Linear_Search.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Function for linear search 4 | # inputs: array of elements 'arr', key to be searched 'x' 5 | # returns: index of first occurrence of x in arr 6 | def linear_search(arr, x): 7 | # traverse the array 8 | for i in range(0, len(arr)): 9 | 10 | # if element at current index is same as x 11 | # return the index value 12 | if arr[i] == x: 13 | return i 14 | 15 | # if the element is not found in the array return -1 16 | return -1 17 | 18 | arr = [3, 2, 1, 5, 6, 4] 19 | print(linear_search(arr, 1)) 20 | -------------------------------------------------------------------------------- /String_or_Array/Sentence_Reverse.py: -------------------------------------------------------------------------------- 1 | """[ 'p', 'e', 'r', 'f', 'e', 'c', 't', ' ', 'm', 'a', 'k', 'e', 's', ' ', 'p', 'r', 'a', 'c', 't', 'i', 'c', 'e' ] 2 | 3 | would turn into: 4 | [ 'p', 'r', 'a', 'c', 't', 'i', 'c', 'e', ' ', 'm', 'a', 'k', 'e', 's', ' ', 'p', 'e', 'r', 'f', 'e', 'c', 't' ]""" 5 | 6 | 7 | def reverse_sentence(arr): 8 | # reverse all characters: 9 | n = len(arr) 10 | mirrorReverse(arr, 0, n-1) 11 | 12 | # reverse each word: 13 | word_start = None 14 | for i in range(0, n): 15 | if arr[i] == " ": 16 | if word_start is not None: 17 | mirrorReverse(arr, word_start, i-1) 18 | word_start = None 19 | elif i == n-1: 20 | if word_start is not None: 21 | mirrorReverse(arr, word_start, i) 22 | else: 23 | if word_start is None: 24 | word_start = i 25 | 26 | 27 | def mirrorReverse(arr, start, end): 28 | while start < end: 29 | tmp = arr[start] 30 | arr[start] = arr[end] 31 | arr[end] = tmp 32 | start += 1 33 | end -= 1 34 | 35 | 36 | if __name__ == '__main__': 37 | arr = ['p', 'e', 'r', 'f', 'e', 'c', 't', ' ', 'm', 'a', 'k', 'e', 's', ' ', 'p', 'r', 'a', 'c', 't', 'i', 'c', 'e'] 38 | 39 | print('Before reverse:', ''.join(arr)) 40 | reverse_sentence(arr) 41 | print('After reverse: ', ''.join(arr)) 42 | 43 | -------------------------------------------------------------------------------- /String_or_Array/Shifted_Array_Search.py: -------------------------------------------------------------------------------- 1 | """If the sorted array arr is shifted left by an unknown offset and you don't have a pre-shifted copy of it, 2 | how would you modify your method to find a number in the shifted array?""" 3 | 4 | 5 | def binarySearch(arr, num, begin, end): 6 | while begin <= end: 7 | mid = round((begin+end)/2) 8 | if arr[mid] < num: 9 | begin = mid + 1 10 | elif arr[mid] == num: 11 | return mid 12 | else: 13 | end = mid - 1 14 | return -1 15 | 16 | 17 | def shiftedArrSearch(shiftArr, num): 18 | originalFirst = getOrigFirst(shiftArr) 19 | n = len(shiftArr) 20 | if shiftArr[originalFirst] <= num <= shiftArr[n-1]: 21 | return binarySearch(shiftArr, num, originalFirst, n - 1) 22 | else: 23 | return binarySearch(shiftArr, num, 0, originalFirst - 1) 24 | 25 | 26 | def getOrigFirst(arr): 27 | begin = 0 28 | end = len(arr)-1 29 | while begin <= end: 30 | mid = int((begin+end)/2) 31 | if mid == 0 or arr[mid] < arr[mid-1]: 32 | return mid 33 | if arr[mid] > arr[0]: 34 | begin = mid + 1 35 | else: 36 | end = mid - 1 37 | return 0 38 | 39 | if __name__ == '__main__': 40 | shiftArr = [9, 12, 17, 2, 4, 5] 41 | print(shiftedArrSearch(shiftArr, 4)) 42 | -------------------------------------------------------------------------------- /String_or_Array/Sorting/Bubble_Sort.py: -------------------------------------------------------------------------------- 1 | # bubble sort function 2 | def bubble_sort(arr): 3 | n = len(arr) 4 | 5 | # Repeat loop N times 6 | # equivalent to: for(i = 0; i < n-1; i++) 7 | for i in range(0, n-1): 8 | # Repeat internal loop for (N-i)th largest element 9 | for j in range(0, n-i-1): 10 | 11 | # if jth value is greater than (j+1) value 12 | if arr[j] > arr[j+1]: 13 | # swap the values at j and j+1 index 14 | # Pythonic way to swap 2 variable values -> x, y = y, x 15 | arr[j], arr[j+1] = arr[j+1], arr[j] 16 | 17 | 18 | arr = [64, 34, 25, 12, 22, 11, 90] 19 | print('Before sorting:', arr) 20 | 21 | # call bubble sort function on the array 22 | bubble_sort(arr) 23 | 24 | print('After sorting:', arr) 25 | 26 | """ 27 | Output: 28 | Before sorting: [64, 34, 25, 12, 22, 11, 90] 29 | After sorting: [11, 12, 22, 25, 34, 64, 90] 30 | """ -------------------------------------------------------------------------------- /String_or_Array/Sorting/Counting_Sort.py: -------------------------------------------------------------------------------- 1 | # counting sort without stable sorting 2 | 3 | 4 | def counting_sort(arr): 5 | n = len(arr) 6 | 7 | # get the maximum value of the array 8 | max_val = max(arr) 9 | 10 | count = [0] * (max_val + 1) 11 | 12 | # fill the count array 13 | # for each element x in the array 14 | for x in arr: 15 | count[x] += 1 16 | 17 | k = 0 18 | for i in range(0, len(count)): 19 | for j in range(0, count[i]): 20 | arr[k] = i 21 | k += 1 22 | 23 | 24 | arr = [3, 2, 1, 3, 2, 5, 5, 3] 25 | print('Before counting sort:', arr) 26 | 27 | # call counting sort function 28 | counting_sort(arr) 29 | 30 | print('After counting sort:', arr) 31 | -------------------------------------------------------------------------------- /String_or_Array/Sorting/Insertion_Sort.py: -------------------------------------------------------------------------------- 1 | def insertion_sort(arr): 2 | n = len(arr) 3 | 4 | for i in range(1, n): 5 | x = arr[i] 6 | j = i - 1 7 | while j >= 0 and arr[j] > x: 8 | # copy value of previous index to index + 1 9 | arr[j + 1] = arr[j] 10 | # j = j - 1 11 | j -= 1 12 | # copy the value which was at ith index to its correct sorted position 13 | arr[j + 1] = x 14 | 15 | 16 | arr = [12, 11, 13, 5, 6] 17 | print('Before sort arr: ', arr) 18 | insertion_sort(arr) 19 | print('Sorted arr: ', arr) 20 | 21 | """ 22 | Output: 23 | Before sort arr: [12, 11, 13, 5, 6] 24 | Sorted arr: [5, 6, 11, 12, 13] 25 | """ -------------------------------------------------------------------------------- /String_or_Array/Sorting/K_Messed_Sort.py: -------------------------------------------------------------------------------- 1 | """Given an array arr of length n where each element is at most k places away from its sorted position, 2 | Code an efficient algorithm to sort arr. 3 | """ 4 | import heapq 5 | 6 | 7 | def kHeapSort(arr, k): 8 | h = [] 9 | n = len(arr) 10 | for i in range(0, k+1): 11 | heapq.heappush(h, arr[i]) 12 | for i in range(k+1, n): 13 | arr[i-(k+1)] = heapq.heappop(h) 14 | heapq.heappush(h, arr[i]) 15 | for i in range(0, k+1): 16 | arr[n-k-1 + i] = heapq.heappop(h) 17 | return arr 18 | 19 | if __name__ == '__main__': 20 | arr = [2, 1, 4, 3, 6, 5] 21 | 22 | print(kHeapSort(arr, 2)) 23 | -------------------------------------------------------------------------------- /String_or_Array/Sorting/Merge_Sort.py: -------------------------------------------------------------------------------- 1 | # Program to perform merge sort on an array 2 | 3 | 4 | def merge(arr, low, mid, high): 5 | n1 = mid - low + 1 6 | n2 = high - mid 7 | 8 | # create temporary arrays 9 | """ 10 | arr = [0] * n is equivalent to: 11 | arr = [0, 0, 0, ..., 0] 12 | array of n zeros 13 | """ 14 | arr1 = [0] * n1 15 | arr2 = [0] * n2 16 | 17 | # copy data of arr into arr1 and arr2 18 | for i in range(0, n1): 19 | arr1[i] = arr[low + i] 20 | 21 | for i in range(0, n2): 22 | arr2[i] = arr[mid + 1 + i] 23 | 24 | # initialize i, j to 0 25 | i = j = 0 26 | 27 | # initialize k to lower index 28 | k = low 29 | 30 | # merge the 2 arrays 31 | while i < n1 and j < n2: 32 | if arr1[i] < arr2[j]: 33 | arr[k] = arr1[i] 34 | i += 1 35 | else: 36 | arr[k] = arr2[j] 37 | j += 1 38 | k += 1 39 | 40 | # if elements left in arr1 copy them to arr 41 | while i < n1: 42 | arr[k] = arr1[i] 43 | i += 1 44 | k += 1 45 | 46 | # if elements left in arr2 copy them to arr 47 | while j < n2: 48 | arr[k] = arr2[j] 49 | j += 1 50 | k += 1 51 | 52 | 53 | def merge_sort(arr, low, high): 54 | if low < high: 55 | # mid = int((low + high) / 2) 56 | mid = int(low + ((high - low) / 2)) 57 | 58 | # call merge_sort on 2 halves 59 | merge_sort(arr, low, mid) 60 | merge_sort(arr, mid+1, high) 61 | 62 | # merge the two sorted halves 63 | merge(arr, low, mid, high) 64 | 65 | 66 | arr = [5, 21, 7, 3, 4, 8, 9, 10, 100, 15] 67 | 68 | print('Before merge sort:', arr) 69 | 70 | # Call merge sort on arr 71 | merge_sort(arr, 0, len(arr)-1) 72 | 73 | print('After merge sort:', arr) 74 | -------------------------------------------------------------------------------- /String_or_Array/Sorting/Quick_Sort.py: -------------------------------------------------------------------------------- 1 | # Python program for implementation of Quicksort Sort by taking last element as pivot 2 | 3 | 4 | def partition(arr, low, high): 5 | i = (low - 1) 6 | pivot = arr[high] # pivot 7 | 8 | for j in range(low, high): 9 | 10 | # If current element is smaller than or 11 | # equal to pivot 12 | if arr[j] <= pivot: 13 | # increment index of smaller element 14 | i += 1 15 | arr[i], arr[j] = arr[j], arr[i] 16 | 17 | arr[i + 1], arr[high] = arr[high], arr[i + 1] 18 | return i + 1 19 | 20 | 21 | # Function to do Quick sort 22 | def quickSort(arr, low, high): 23 | if low < high: 24 | # pivot is set to its right position after partition call 25 | pi = partition(arr, low, high) 26 | 27 | # Separately sort elements before 28 | # partition and after partition 29 | quickSort(arr, low, pi - 1) 30 | quickSort(arr, pi + 1, high) 31 | 32 | 33 | # Driver code to test above 34 | arr = [10, 7, 8, 9, 1, 5] 35 | n = len(arr) 36 | print("Before sorting array is:") 37 | for i in range(n): 38 | print(arr[i], end=' -> ') 39 | print('end') 40 | 41 | quickSort(arr, 0, n - 1) 42 | 43 | print("Sorted array is:") 44 | for i in range(n): 45 | print(arr[i], end=' -> ') 46 | print('end') 47 | -------------------------------------------------------------------------------- /String_or_Array/Sorting/Selection_Sort.py: -------------------------------------------------------------------------------- 1 | # selection sort function 2 | def selection_sort(arr): 3 | n = len(arr) 4 | for i in range(0, n): 5 | for j in range(i+1, n): 6 | # if the value at i is > value at j -> swap 7 | if arr[i] > arr[j]: 8 | arr[i], arr[j] = arr[j], arr[i] 9 | 10 | 11 | # input arr 12 | arr = [3, 2, 4, 1, 5] 13 | print('Before selection sort:', arr) 14 | 15 | # call selection sort function 16 | selection_sort(arr) 17 | print('After selection sort:', arr) 18 | -------------------------------------------------------------------------------- /String_or_Array/StringPermutations.py: -------------------------------------------------------------------------------- 1 | # To print all permutations of a given string 2 | 3 | count = 0 4 | 5 | 6 | def permutations(mat, l, r): 7 | if l == r: 8 | print(''.join(mat)) 9 | global count 10 | count += 1 11 | else: 12 | for i in range(l, r+1): 13 | mat[l], mat[i] = mat[i], mat[l] 14 | permutations(mat, l+1, r) 15 | mat[l], mat[i] = mat[i], mat[l] 16 | 17 | 18 | string = "ABC" 19 | permutations(list(string), 0, len(string)-1) 20 | print('total permutations:', count) 21 | -------------------------------------------------------------------------------- /Tree/BinarySearchTree/BST.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | 4 | class Node: 5 | def __init__(self, data=None, right_child=None, left_child=None, parent=None): 6 | self.data = data 7 | self.right_child = right_child 8 | self.left_child = left_child 9 | self.parent = parent 10 | 11 | def has_left_child(self): 12 | return self.left_child 13 | 14 | def has_right_child(self): 15 | return self.right_child 16 | 17 | def has_both_children(self): 18 | return self.right_child and self.left_child 19 | 20 | def has_any_children(self): 21 | return self.right_child or self.left_child 22 | 23 | def is_root(self): 24 | return not self.parent 25 | 26 | def is_leaf(self): 27 | return not(self.right_child or self.left_child) 28 | 29 | def is_left_child(self): 30 | return self.parent and self.parent.left_child == self 31 | 32 | def is_right_child(self): 33 | return self.parent and self.parent.right_child == self 34 | 35 | def replace_data(self, data): 36 | self.data = data 37 | 38 | def replace_left_child(self, left_child): 39 | self.left_child = left_child 40 | 41 | def replace_right_child(self, right_child): 42 | self.right_child = right_child 43 | 44 | 45 | class BinarySearchTree: 46 | def __init__(self): 47 | self.root = None 48 | 49 | def insert_node(self, data): 50 | if self.root is None: 51 | self.root = Node(data) 52 | else: 53 | self._insert(data, self.root) 54 | 55 | def _insert(self, data, current_node): 56 | if data < current_node.data: 57 | if current_node.has_left_child(): 58 | self._insert(data, current_node.left_child) 59 | else: 60 | current_node.left_child = Node(data, parent=current_node) 61 | else: 62 | if current_node.has_right_child(): 63 | self._insert(data, current_node.right_child) 64 | else: 65 | current_node.right_child = Node(data, parent=current_node) 66 | 67 | @staticmethod 68 | def find_inorder_ancestor(current_node): 69 | if current_node.has_right_child(): 70 | current_node = current_node.right_child 71 | while current_node.has_left_child(): 72 | current_node = current_node.left_child 73 | return current_node 74 | 75 | ancestor = current_node.parent 76 | child = current_node 77 | while ancestor is not None and child is ancestor.right_child: 78 | child = ancestor 79 | ancestor = child.parent 80 | return ancestor 81 | 82 | def delete_node(self, data): 83 | if self.root is None: 84 | print("No node to delete in the tree") 85 | else: 86 | if self._delete(data, self.root) is not None: 87 | print("Deleted", data) 88 | else: 89 | print(data,"not found") 90 | 91 | def _delete(self, data, current_node): 92 | while current_node is not None and data != current_node.data: 93 | if data <= current_node.data: 94 | current_node = current_node.left_child 95 | else: 96 | current_node = current_node.right_child 97 | 98 | if current_node is not None: 99 | if current_node.is_leaf(): 100 | if current_node.is_left_child(): 101 | current_node.parent.left_child = None 102 | else: 103 | current_node.parent.right_child = None 104 | else: 105 | successor = self.find_inorder_ancestor(current_node) 106 | if successor is None: 107 | current_node.data = current_node.left_child.data 108 | current_node.left_child = None 109 | else: 110 | temp = current_node.data 111 | current_node.data = successor.data 112 | successor.data = temp 113 | self._delete(temp, successor) 114 | return True 115 | else: 116 | return None 117 | 118 | def inorder(self): 119 | current_node = self.root 120 | self._inorder(current_node) 121 | print('End') 122 | 123 | def _inorder(self, current_node): 124 | if current_node is None: 125 | return 126 | self._inorder(current_node.left_child) 127 | print(current_node.data," -> ",end='') 128 | self._inorder(current_node.right_child) 129 | 130 | if __name__ == '__main__': 131 | tree = BinarySearchTree() 132 | tree.insert_node(6) 133 | tree.insert_node(9) 134 | tree.insert_node(6) 135 | tree.insert_node(5) 136 | tree.insert_node(8) 137 | tree.insert_node(7) 138 | tree.insert_node(3) 139 | tree.insert_node(2) 140 | tree.insert_node(4) 141 | tree.inorder() 142 | tree.delete_node(6) 143 | tree.delete_node(1) 144 | tree.delete_node(3) 145 | tree.inorder() -------------------------------------------------------------------------------- /Tree/BinarySearchTree/Check_Correct_Preorder.py: -------------------------------------------------------------------------------- 1 | # Check if a given array can represent Preorder Traversal of Binary Search Tree 2 | 3 | 4 | def check_pre_order(arr): 5 | minimum = -float('inf') 6 | 7 | stack = [] 8 | 9 | for val in arr: 10 | if val < minimum: 11 | return False 12 | 13 | while len(stack) != 0 and stack[-1] < val: 14 | minimum = stack.pop() 15 | 16 | stack.append(val) 17 | 18 | return True 19 | 20 | 21 | if __name__ == '__main__': 22 | pre_order = [40, 30, 35, 80, 100] 23 | print("Valid Preorder" if check_pre_order(pre_order) else "Invalid Preorder") 24 | pre_order = [40, 30, 35, 20, 80, 100] 25 | print("Valid Preorder" if check_pre_order(pre_order) else "Invalid Preorder") 26 | 27 | 28 | -------------------------------------------------------------------------------- /Tree/BinarySearchTree/InOrder_Ancestor.py: -------------------------------------------------------------------------------- 1 | # find the in-order ancestor of a given node in BST 2 | 3 | 4 | # A Binary Search Tree node 5 | class Node: 6 | # Constructor to initialise node 7 | def __init__(self, data, parent=None): 8 | self.data = data 9 | self.left = None 10 | self.right = None 11 | self.parent = parent 12 | 13 | 14 | def findInOrderAncestor(n): 15 | if n.right is not None: 16 | return findMinKeyWithinTree(n.right) 17 | 18 | ancestor = n.parent 19 | child = n 20 | while ancestor is not None and child == ancestor.right: 21 | child = ancestor 22 | ancestor = child.parent 23 | return ancestor 24 | 25 | 26 | def findMinKeyWithinTree(root): 27 | while root.left is not None: 28 | root = root.left 29 | return root 30 | 31 | 32 | if __name__ == '__main__': 33 | root = Node(4) 34 | root.left = Node(2, root) 35 | root.right = Node(6, root) 36 | root.left.left = Node(1, root.left) 37 | root.left.right = Node(3, root.left) 38 | successor = findInOrderAncestor(root.left.right) 39 | 40 | if successor is not None: 41 | print(successor.data) 42 | else: 43 | print("No in order successor") 44 | -------------------------------------------------------------------------------- /Tree/BinarySearchTree/Lowest_Common_Ancestor.py: -------------------------------------------------------------------------------- 1 | # Find the Lowest Common Ancestor (LCA) in a Binary Search Tree 2 | 3 | 4 | # A Binary Search Tree node 5 | class Node: 6 | # Constructor to initialise node 7 | def __init__(self, data): 8 | self.data = data 9 | self.left = None 10 | self.right = None 11 | 12 | 13 | class BST: 14 | def __init__(self): 15 | self.root = None 16 | 17 | def insert_node(self, data): 18 | if self.root is None: 19 | self.root = Node(data) 20 | else: 21 | self._insert(data, self.root) 22 | 23 | def _insert(self, data, current_node): 24 | if data <= current_node.data: 25 | if current_node.left is not None: 26 | self._insert(data, current_node.left) 27 | else: 28 | current_node.left = Node(data) 29 | else: 30 | if current_node.right is not None: 31 | self._insert(data, current_node.right) 32 | else: 33 | current_node.right = Node(data) 34 | 35 | def inorder(self): 36 | current_node = self.root 37 | self._inorder(current_node) 38 | print('End') 39 | 40 | def _inorder(self, current_node): 41 | if current_node is None: 42 | return 43 | self._inorder(current_node.left) 44 | print(current_node.data, " -> ", end='') 45 | self._inorder(current_node.right) 46 | 47 | 48 | # assuming both nodes are present in the tree 49 | def lca_bst(root, value1, value2): 50 | while root is not None: 51 | if value2 > root.data < value1: 52 | root = root.right 53 | elif value2 < root.data > value1: 54 | root = root.left 55 | else: 56 | return root.data 57 | 58 | 59 | if __name__ == '__main__': 60 | tree = BST() 61 | tree.insert_node(6) 62 | tree.insert_node(8) 63 | tree.insert_node(9) 64 | tree.insert_node(6) 65 | tree.insert_node(5) 66 | tree.insert_node(7) 67 | tree.insert_node(3) 68 | tree.insert_node(2) 69 | tree.insert_node(4) 70 | print(lca_bst(tree.root, 4, 2)) 71 | 72 | """ 73 | given tree: 74 | 6 75 | 6 8 76 | 5 7 9 77 | 3 78 | 2 4 79 | """ 80 | -------------------------------------------------------------------------------- /Tree/BinarySearchTree/Minimal_Tree.py: -------------------------------------------------------------------------------- 1 | # Given a sorted array, create a binary search tree with minimal height 2 | 3 | 4 | # A Binary Tree node 5 | class Node: 6 | # Constructor to initialise node 7 | def __init__(self, data): 8 | self.data = data 9 | self.left = None 10 | self.right = None 11 | 12 | 13 | def make_minimal_bst(arr, start, end): 14 | if end < start: 15 | return None 16 | mid = int((start + end) / 2) 17 | root = Node(arr[mid]) 18 | 19 | root.left = make_minimal_bst(arr, start, mid-1) 20 | root.right = make_minimal_bst(arr, mid+1, end) 21 | 22 | return root 23 | 24 | 25 | def in_order(root): 26 | if root is None: 27 | return 28 | in_order(root.left) 29 | print(root.data, end=' -> ') 30 | in_order(root.right) 31 | 32 | if __name__ == '__main__': 33 | arr = [1, 2, 3, 4, 5, 6, 7, 8] 34 | root = make_minimal_bst(arr, 0, len(arr)-1) 35 | in_order(root) 36 | print('end') 37 | -------------------------------------------------------------------------------- /Tree/BinaryTree/Bottom_View.py: -------------------------------------------------------------------------------- 1 | # Print Nodes in Bottom View of Binary Tree 2 | from collections import deque 3 | 4 | 5 | class Node: 6 | def __init__(self, data): 7 | self.data = data 8 | self.left = None 9 | self.right = None 10 | 11 | 12 | def bottom_view(root): 13 | if root is None: 14 | return 15 | 16 | # make an empty queue for BFS 17 | q = deque() 18 | 19 | # dict to store bottom view keys 20 | bottomview = {} 21 | 22 | # append root in the queue with horizontal distance as 0 23 | q.append((root, 0)) 24 | 25 | while q: 26 | # get the element and horizontal distance 27 | elem, hd = q.popleft() 28 | 29 | # update the last seen hd element 30 | bottomview[hd] = elem.data 31 | 32 | # add left and right child in the queue with hd - 1 and hd + 1 33 | if elem.left is not None: 34 | q.append((elem.left, hd - 1)) 35 | if elem.right is not None: 36 | q.append((elem.right, hd + 1)) 37 | 38 | # return the bottomview 39 | return bottomview 40 | 41 | 42 | if __name__ == '__main__': 43 | root = Node(20) 44 | root.left = Node(8) 45 | root.right = Node(22) 46 | root.left.left = Node(5) 47 | root.left.right = Node(3) 48 | root.right.left = Node(4) 49 | root.right.right = Node(25) 50 | root.left.right.left = Node(10) 51 | root.left.right.right = Node(14) 52 | 53 | bottomview = bottom_view(root) 54 | 55 | for i in sorted(bottomview): 56 | print(bottomview[i], end=' ') 57 | -------------------------------------------------------------------------------- /Tree/BinaryTree/Check_Balanced.py: -------------------------------------------------------------------------------- 1 | # Check if a binary tree is height balanced 2 | # abs(height[leftTree] - height[rightTree]) <= 1 3 | 4 | 5 | # A Binary Tree node 6 | class Node: 7 | # Constructor to initialise node 8 | def __init__(self, data): 9 | self.data = data 10 | self.left = None 11 | self.right = None 12 | 13 | 14 | def check_height(root): 15 | if root is None: 16 | return -1 17 | left_height = check_height(root.left) 18 | if left_height is float('inf'): 19 | return float('inf') 20 | 21 | right_height = check_height(root.right) 22 | if right_height is float('inf'): 23 | return float('inf') 24 | 25 | height = abs(left_height - right_height) 26 | if height > 1: 27 | return float('inf') 28 | else: 29 | return max(left_height, right_height) + 1 30 | 31 | 32 | def isBalanced(root): 33 | return check_height(root) != float('inf') 34 | 35 | if __name__ == '__main__': 36 | root = Node(1) 37 | root.left = Node(2) 38 | root.right = Node(3) 39 | root.left.left = Node(4) 40 | root.left.right = Node(5) 41 | 42 | if isBalanced(root): 43 | print("Yes! the tree is balanced") 44 | else: 45 | print("No! the tree is not balanced") -------------------------------------------------------------------------------- /Tree/BinaryTree/Check_Full_BinaryTree.py: -------------------------------------------------------------------------------- 1 | # Check whether a binary tree is a full binary tree or not 2 | 3 | 4 | class Node: 5 | def __init__(self, data): 6 | self.data = data 7 | self.left = None 8 | self.right = None 9 | 10 | 11 | def check_full_bt(root): 12 | # If tree is empty 13 | if root is None: 14 | return True 15 | 16 | # if both child are None 17 | if root.left is None and root.right is None: 18 | return True 19 | 20 | # if the node has both children and both sub tree are full binary trees 21 | if root.left is not None and root.right is not None: 22 | return check_full_bt(root.left) and check_full_bt(root.right) 23 | 24 | return False 25 | 26 | if __name__ == '__main__': 27 | root = Node(10) 28 | root.left = Node(20) 29 | root.right = Node(30) 30 | 31 | root.left.right = Node(40) 32 | root.left.left = Node(50) 33 | root.right.left = Node(60) 34 | root.right.right = Node(70) 35 | 36 | root.left.left.left = Node(80) 37 | root.left.left.right = Node(90) 38 | root.left.right.left = Node(80) 39 | root.left.right.right = Node(90) 40 | root.right.left.left = Node(80) 41 | root.right.left.right = Node(90) 42 | root.right.right.left = Node(80) 43 | root.right.right.right = Node(90) 44 | 45 | if check_full_bt(root): 46 | print('Yes, given binary tree is Full BT') 47 | else: 48 | print('No, given binary tree is not Full BT') 49 | -------------------------------------------------------------------------------- /Tree/BinaryTree/Is_SubTree.py: -------------------------------------------------------------------------------- 1 | # Given two binary trees, check if the first tree is subtree of the second one. 2 | 3 | 4 | # A Binary Tree node 5 | class Node: 6 | # Constructor to initialise node 7 | def __init__(self, data): 8 | self.data = data 9 | self.left = None 10 | self.right = None 11 | 12 | 13 | def store_in_order(root, arr): 14 | if root is None: 15 | arr.append('$') 16 | return 17 | store_in_order(root.left, arr) 18 | arr.append(root.data) 19 | store_in_order(root.right, arr) 20 | 21 | 22 | def store_pre_order(root, arr): 23 | if root is None: 24 | arr.append('$') 25 | return 26 | store_pre_order(root.left, arr) 27 | store_pre_order(root.right, arr) 28 | arr.append(root.data) 29 | 30 | 31 | def isSubTree(t1, t2): 32 | order_t1 = [] 33 | order_t2 = [] 34 | 35 | store_in_order(t1, order_t1) 36 | store_in_order(t2, order_t2) 37 | if ''.join(order_t1).find(''.join(order_t2)) == -1: 38 | return False 39 | 40 | order_t1 = [] 41 | order_t2 = [] 42 | 43 | store_pre_order(t1, order_t1) 44 | store_pre_order(t2, order_t2) 45 | if ''.join(order_t1).find(''.join(order_t2)) == -1: 46 | return False 47 | 48 | return True 49 | 50 | 51 | T = Node('a') 52 | T.left = Node('b') 53 | T.right = Node('d') 54 | T.left.left = Node('c') 55 | T.left.right = Node('e') 56 | 57 | S = Node('b') 58 | S.left = Node('c') 59 | S.right = Node('e') 60 | 61 | if isSubTree(T, S): 62 | print('Yes, S is a subtree of T') 63 | else: 64 | print('No, S is not a subtree of T') 65 | -------------------------------------------------------------------------------- /Tree/BinaryTree/List_Of_Depths.py: -------------------------------------------------------------------------------- 1 | # Create a list of all nodes at each depth 2 | 3 | # A Binary Tree node 4 | class Node: 5 | # Constructor to initialise node 6 | def __init__(self, data): 7 | self.data = data 8 | self.left = None 9 | self.right = None 10 | 11 | 12 | def list_of_depths(root): 13 | if root is None: 14 | return [] 15 | depths = [] 16 | q = [] 17 | q.append(root) 18 | 19 | while q: 20 | parents = q 21 | depths.append(q) 22 | q = [] 23 | for parent in parents: 24 | if parent.left is not None: 25 | q.append(parent.left) 26 | if parent.right is not None: 27 | q.append(parent.right) 28 | 29 | return depths 30 | 31 | if __name__ == '__main__': 32 | root = Node(1) 33 | root.left = Node(2) 34 | root.right = Node(3) 35 | root.left.left = Node(4) 36 | root.left.right = Node(5) 37 | 38 | for depth, list_nodes in enumerate(list_of_depths(root)): 39 | print('Depth', depth, end=': ') 40 | for n in list_nodes: 41 | print(n.data, end=' -> ') 42 | print('end') 43 | -------------------------------------------------------------------------------- /Tree/BinaryTree/Lowest_Common_Ancestor.py: -------------------------------------------------------------------------------- 1 | """ Program to find LCA of n1 and n2 using one traversal of 2 | Binary tree 3 | """ 4 | 5 | 6 | # A binary tree node 7 | class Node: 8 | # Constructor to create a new node 9 | def __init__(self, key): 10 | self.key = key 11 | self.left = None 12 | self.right = None 13 | 14 | 15 | # This function returns reference to LCA of two given values n1 and n2 16 | # v1 is set as true by this function if n1 is found 17 | # v2 is set as true by this function if n2 is found 18 | def findLCAUtil(root, n1, n2, v): 19 | # Base Case 20 | if root is None: 21 | return None 22 | 23 | # IF either n1 or n2 matches ith root's key, report 24 | # the presence by setting v1 or v2 as true and return 25 | # root 26 | if root.key == n1: 27 | v[0] = True 28 | return root 29 | 30 | if root.key == n2: 31 | v[1] = True 32 | return root 33 | 34 | # Look for keys in left and right subtree 35 | left_lca = findLCAUtil(root.left, n1, n2, v) 36 | right_lca = findLCAUtil(root.right, n1, n2, v) 37 | 38 | # if one key is present in left subtree and other is present in other, 39 | # So this node is the LCA 40 | if left_lca and right_lca: 41 | return root 42 | 43 | # Otherwise check if left subtree or right subtree is LCA 44 | return left_lca if left_lca is not None else right_lca 45 | 46 | 47 | def find(root, k): 48 | # Base Case 49 | if root is None: 50 | return False 51 | 52 | # If key is present at root, or if left subtree or right 53 | # subtree , return true 54 | if (root.key == k or find(root.left, k) or 55 | find(root.right, k)): 56 | return True 57 | 58 | # Else return false 59 | return False 60 | 61 | 62 | # This function returns LCA of n1 and n2 only if both 63 | # n1 and n2 are present in tree, otherwise returns None 64 | def findLCA(root, n1, n2): 65 | # Initialize n1 and n2 as not visited 66 | v = [False, False] 67 | 68 | # Find lca of n1 and n2 69 | lca = findLCAUtil(root, n1, n2, v) 70 | 71 | # Returns LCA only if both n1 and n2 are present in tree 72 | if v[0] and v[1] or v[0] and find(lca, n2) or v[1] and find(lca, n1): 73 | return lca 74 | 75 | # Else return None 76 | return None 77 | 78 | 79 | # Driver program to test above function 80 | root = Node(1) 81 | root.left = Node(2) 82 | root.right = Node(3) 83 | root.left.left = Node(4) 84 | root.left.right = Node(5) 85 | root.right.left = Node(6) 86 | root.right.right = Node(7) 87 | 88 | lca = findLCA(root, 4, 5) 89 | 90 | if lca is not None: 91 | print("LCA(4, 5) = ", lca.key) 92 | else: 93 | print("Keys are not present") 94 | 95 | lca = findLCA(root, 4, 10) 96 | if lca is not None: 97 | print("LCA(4,10) = ", lca.key) 98 | else: 99 | print("Keys are not present") 100 | -------------------------------------------------------------------------------- /Tree/BinaryTree/Max_Path_Sum.py: -------------------------------------------------------------------------------- 1 | # find the maximum path sum. The path may start and end at any node in the tree. 2 | 3 | class Node: 4 | def __init__(self, data): 5 | self.data = data 6 | self.left = None 7 | self.right = None 8 | 9 | 10 | def max_sum_path(root): 11 | max_sum_path_util.res = -float('inf') 12 | 13 | max_sum_path_util(root) 14 | return max_sum_path_util.res 15 | 16 | 17 | def max_sum_path_util(root): 18 | if root is None: 19 | return 0 20 | # find max sum in left and right sub tree 21 | left_sum = max_sum_path_util(root.left) 22 | right_sum = max_sum_path_util(root.right) 23 | 24 | # if current node is one of the nodes in the path above for max 25 | # it can either be alone, or with left sub tree or right sub tree 26 | max_single = max(max(left_sum, right_sum) + root.data, root.data) 27 | 28 | # if the current root itself is considered as top node of the max path 29 | max_parent = max(left_sum + right_sum + root.data, max_single) 30 | 31 | # store the maximum result 32 | max_sum_path_util.res = max(max_sum_path_util.res, max_parent) 33 | 34 | # return the max_single for upper nodes calculation 35 | return max_single 36 | 37 | 38 | if __name__ == '__main__': 39 | root = Node(10) 40 | root.left = Node(2) 41 | root.right = Node(10) 42 | root.left.left = Node(20) 43 | root.left.right = Node(1) 44 | root.right.right = Node(-25) 45 | root.right.right.left = Node(3) 46 | root.right.right.right = Node(4) 47 | 48 | print('max path sum is:', max_sum_path(root)) 49 | 50 | 51 | -------------------------------------------------------------------------------- /Tree/BinaryTree/Minimum_height.py: -------------------------------------------------------------------------------- 1 | # Find minimum depth of a binary tree 2 | from collections import deque 3 | 4 | 5 | # A Binary Tree node 6 | class Node: 7 | # Constructor to initialise node 8 | def __init__(self, data): 9 | self.data = data 10 | self.left = None 11 | self.right = None 12 | 13 | 14 | def get_min_depth(root): 15 | if root is None: 16 | return 0 17 | 18 | queue = deque() 19 | queue.append((root, 1)) 20 | 21 | while queue: 22 | node, height = queue.popleft() 23 | if node.left is None and node.right is None: 24 | return height 25 | 26 | else: 27 | if node.left is not None: 28 | queue.append((node.left, height + 1)) 29 | if node.right is not None: 30 | queue.append((node.right, height + 1)) 31 | 32 | 33 | if __name__ == '__main__': 34 | root = Node(1) 35 | root.left = Node(2) 36 | root.right = Node(3) 37 | root.left.left = Node(4) 38 | root.left.right = Node(5) 39 | 40 | print(get_min_depth(root)) 41 | -------------------------------------------------------------------------------- /Tree/BinaryTree/Remove_Path_Less_Than_K.py: -------------------------------------------------------------------------------- 1 | # Remove nodes on root to leaf paths of length < K 2 | 3 | 4 | class Node: 5 | def __init__(self, data): 6 | self.data = data 7 | self.left = None 8 | self.right = None 9 | 10 | 11 | def remove_path_less_than(root, k): 12 | return remove_path_util(root, 1, k) 13 | 14 | 15 | def remove_path_util(root, level, k): 16 | if root is None: 17 | return None 18 | 19 | root.left = remove_path_util(root.left, level+1, k) 20 | root.right = remove_path_util(root.right, level+1, k) 21 | 22 | if root.left is None and root.right is None and level < k: 23 | del root 24 | return None 25 | 26 | return root 27 | 28 | 29 | def in_order(root): 30 | if root is None: 31 | return 32 | in_order(root.left) 33 | print(root.data, end=' ') 34 | in_order(root.right) 35 | 36 | 37 | if __name__ == '__main__': 38 | root = Node(1) 39 | root.left = Node(2) 40 | root.right = Node(3) 41 | root.left.left = Node(4) 42 | root.left.right = Node(5) 43 | root.left.left.left = Node(7) 44 | root.right.right = Node(6) 45 | root.right.right.left = Node(8) 46 | in_order(root) 47 | print() 48 | root = remove_path_less_than(root, 4) 49 | in_order(root) 50 | -------------------------------------------------------------------------------- /Tree/BinaryTree/Reverse_Alternate_Levels_PBT.py: -------------------------------------------------------------------------------- 1 | # Given a Perfect Binary Tree, reverse the alternate level nodes of the binary tree 2 | 3 | 4 | class Node: 5 | def __init__(self, data): 6 | self.data = data 7 | self.left = None 8 | self.right = None 9 | 10 | 11 | def reverse_alt_levels(root): 12 | pre_order_rev(root.left, root.right, 0) 13 | 14 | 15 | def pre_order_rev(root_left, root_right, level): 16 | # Base case 17 | if (root_left or root_right) is None: 18 | return 19 | 20 | # swap the data of nodes if at an alternate level 21 | if level % 2 == 0: 22 | root_left.data, root_right.data = root_right.data, root_left.data 23 | 24 | # go to the next level with left of left root and right of right root 25 | # and vice versa 26 | pre_order_rev(root_left.left, root_right.right, level+1) 27 | pre_order_rev(root_left.right, root_right.left, level+1) 28 | 29 | 30 | def in_order(root): 31 | if root is None: 32 | return 33 | in_order(root.left) 34 | print(root.data, end=' -> ') 35 | in_order(root.right) 36 | 37 | 38 | if __name__ == '__main__': 39 | root = Node('a') 40 | root.left = Node('b') 41 | root.right = Node('c') 42 | root.left.left = Node('d') 43 | root.left.right = Node('e') 44 | root.right.left = Node('f') 45 | root.right.right = Node('g') 46 | root.left.left.left = Node('h') 47 | root.left.left.right = Node('i') 48 | root.left.right.left = Node('j') 49 | root.left.right.right = Node('k') 50 | root.right.left.left = Node('l') 51 | root.right.left.right = Node('m') 52 | root.right.right.left = Node('n') 53 | root.right.right.right = Node('o') 54 | 55 | print('Before Reversal:') 56 | in_order(root) 57 | print() 58 | 59 | # Call the reverse alternate levels function 60 | reverse_alt_levels(root) 61 | 62 | print('After Reversal:') 63 | in_order(root) 64 | print() 65 | -------------------------------------------------------------------------------- /Tree/BinaryTree/Top_View.py: -------------------------------------------------------------------------------- 1 | # Print Nodes in Top View of Binary Tree 2 | from collections import deque 3 | 4 | 5 | class Node: 6 | def __init__(self, data): 7 | self.data = data 8 | self.left = None 9 | self.right = None 10 | 11 | 12 | def top_view(root): 13 | if root is None: 14 | return 15 | 16 | # make an empty queue for BFS 17 | q = deque() 18 | 19 | # empty set 20 | sets = set({}) 21 | 22 | # list to store top view keys 23 | topview = [] 24 | 25 | # append root in the queue with horizontal distance as 0 26 | q.append((root, 0)) 27 | 28 | while q: 29 | # get the element and horizontal distance 30 | elem, hd = q.popleft() 31 | 32 | # if the hd is seen first time it will be top view 33 | if hd not in sets: 34 | topview.append((elem.data, hd)) 35 | sets.add(hd) 36 | 37 | # add left and right child in the queue with hd - 1 and hd + 1 38 | if elem.left is not None: 39 | q.append((elem.left, hd - 1)) 40 | if elem.right is not None: 41 | q.append((elem.right, hd + 1)) 42 | 43 | # return the sorted topview on the basis of hd 44 | return sorted(topview, key=lambda x: x[1]) 45 | 46 | 47 | if __name__ == '__main__': 48 | root = Node(1) 49 | root.left = Node(2) 50 | root.right = Node(3) 51 | root.left.right = Node(4) 52 | root.left.right.right = Node(5) 53 | root.left.right.right.right = Node(6) 54 | 55 | for i in top_view(root): 56 | print(i[0], end=' ') 57 | -------------------------------------------------------------------------------- /Tree/Trie/Trie.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implementation of Trie data structure. 3 | """ 4 | 5 | 6 | class Node: 7 | def __init__(self, value=None, isComplete=False): 8 | self.isComplete = isComplete 9 | self.children = {} 10 | self.value = value 11 | self.isPrefixOf = 0 12 | 13 | 14 | class Trie: 15 | def __init__(self): 16 | self.root = Node() 17 | 18 | def add_word(self, word): 19 | """ 20 | Add the given word into the trie 21 | :param word: A String (word) to be added in the trie 22 | """ 23 | chars = list(word) 24 | 25 | curr_node = self.root 26 | 27 | for ch in chars: 28 | # The substring till this node will now become a prefix of newly added word 29 | curr_node.isPrefixOf += 1 30 | 31 | if ch in curr_node.children: 32 | curr_node = curr_node.children[ch] 33 | else: 34 | new_node = Node(value=ch) 35 | curr_node.children[ch] = new_node 36 | curr_node = new_node 37 | 38 | curr_node.isComplete = True 39 | 40 | def search(self, word): 41 | """ 42 | Searches if the word is present in the Trie or not 43 | :param word: String (word) to be searched in the trie 44 | :return: last Node of the searched word if present else None 45 | """ 46 | chars = list(word) 47 | 48 | curr_node = self.root 49 | 50 | for ch in chars: 51 | if ch in curr_node.children: 52 | curr_node = curr_node.children[ch] 53 | else: 54 | return None 55 | 56 | if curr_node.isComplete is True: 57 | return curr_node 58 | 59 | return None 60 | 61 | def delete(self, word): 62 | """ 63 | Deletes the given String (word) from the trie 64 | :param word: Word (String) to be deleted 65 | :return: True is deleted, False if word not present in the Trie 66 | """ 67 | chars = list(word) 68 | n = len(chars) 69 | 70 | val = self._delete(self.root, word) 71 | return True if val == 1 or val == 0 else False 72 | 73 | def _delete(self, node, chars): 74 | """ 75 | Recursive Helper function to delete the word and decreement the isPrefix of values 76 | :param node: current node looking at 77 | :param chars: array of characters to look for 78 | :return: 1 is word is deleted, 0 if word is deleted and 79 | """ 80 | 81 | # if the chars array is empty 82 | if len(chars) == 0: 83 | # check if the word is present in the trie 84 | if node.isComplete: 85 | node.isComplete = False 86 | 87 | # check if the word was a prefix of any other words in trie 88 | # if so, decrement isPrefixOf and return 0, as no deletions are required 89 | if len(node.children.keys()) > 0: 90 | node.isPrefixOf -= 1 91 | return 0 92 | 93 | # if word was not a prefix then we need to go up in the trie 94 | # and find the lowest parent which forms a new word in trie 95 | return 1 96 | # if word is not present in the trie 97 | return -1 98 | 99 | # check if the character is present in current node's children 100 | if chars[0] in node.children: 101 | # recursive call for remaining characters in the respective child 102 | val = self._delete(node.children[chars[0]], chars[1:]) 103 | 104 | # if word was found but lowest parent which forms new word is not found 105 | if val == 1: 106 | if node.isComplete or len(node.children.keys()) > 1: 107 | del node.children[chars[0]] 108 | node.isPrefixOf -= 1 109 | val = 0 110 | # if word was found and lowest parent which forms new word was also found 111 | # simply reduce the isPrefixOf value of the node 112 | elif val == 0: 113 | node.isPrefixOf -= 1 114 | return val 115 | 116 | return -1 117 | 118 | 119 | trie = Trie() 120 | trie.add_word("anubhav") 121 | trie.add_word("anubshrimal") 122 | trie.add_word("anubhavshrimal") 123 | trie.add_word("data_structures") 124 | 125 | if trie.search("anubhav") is not None: 126 | print("anubhav is present in the Trie") 127 | else: 128 | print("anubhav is NOT present in the Trie") 129 | 130 | trie.delete("anubhav") 131 | 132 | if trie.search("anubhav") is not None: 133 | print("anubhav is present in the Trie") 134 | else: 135 | print("anubhav is NOT present in the Trie") 136 | 137 | print("Number of words in trie:", trie.root.isPrefixOf) 138 | --------------------------------------------------------------------------------