├── .gitattributes ├── .project ├── .pydevproject ├── .vscode ├── launch.json └── settings.json ├── AlgorithmsChapters ├── BT │ ├── GraphColouring.py │ ├── NQueen.py │ ├── Permutations.py │ ├── SubsetSum.py │ ├── TOH.py │ └── TSP.py ├── CA │ └── IsPrime.py ├── DAC │ ├── ClosestPair.py │ └── NutsAndBolts.py ├── DP │ ├── ALS.py │ ├── CoinChange.py │ ├── DiceThrow.py │ ├── EditDist.py │ ├── Fibo.py │ ├── FloydWarshall.py │ ├── GridMinCost.py │ ├── GridUniqueWays.py │ ├── HouseRobber.py │ ├── JobScheduling.py │ ├── Knapsack.py │ ├── LargestBitonicSubseq.py │ ├── LargestIncreasingSubseq.py │ ├── LargestPalindromicSubsequence.py │ ├── LargestPalindromicSubstr.py │ ├── LongestCommonSubseq.py │ ├── MatrixCM.py │ ├── MinCostBinaryTree.py │ ├── MinStairCost.py │ ├── OptimalBST.py │ ├── StairUniqueWays.py │ ├── StockBuySell.py │ ├── Vacation.py │ ├── WildCharMatch.py │ ├── catalan.py │ └── gen.py └── Greedy │ ├── 01Knapsack.py │ ├── ActivitySelection.py │ ├── ChotaBhim.py │ ├── FractionalKnapsack.py │ ├── HuffmanTree.py │ ├── JobSequencing.py │ ├── JoinRopes.py │ ├── MultipleStageGraph.py │ └── OptimalMergePattern.py ├── Collections ├── Basics │ ├── Bulb.py │ ├── Bulb2.py │ ├── Bulb3.py │ ├── BulbEnum.py │ ├── BulbInterface.py │ ├── Calculator.py │ ├── Circle.py │ ├── HelloWorld.py │ ├── Incriment.py │ ├── LinkedList.py │ ├── Loops.py │ ├── MinMaxValue.py │ ├── ModuleTest.py │ ├── ModuleUse.py │ ├── OuterClass.py │ ├── Rectangle.py │ ├── Shape.py │ ├── ShapeDemo.py │ ├── Tree.py │ ├── __pycache__ │ │ ├── Circle.cpython-36.pyc │ │ ├── ModuleTest.cpython-38.pyc │ │ ├── Rectangle.cpython-36.pyc │ │ └── Shape.cpython-36.pyc │ ├── minmaxlimit.py │ └── type.py ├── Counter.py ├── Dictionary.py ├── Heap.py ├── List.py ├── ModuleTest2.py ├── Queue.py ├── Set.py ├── Stack.py └── __pycache__ │ └── ModuleTest2.cpython-38.pyc ├── Graph ├── GraphAdjList.py └── GraphAdjMatrix.py ├── HashTable ├── HTSCKeyValue.py ├── HashTableExercise.py └── HashTableLP.py ├── Heap ├── Heap.py ├── HeapExercise.py └── MedianHeap.py ├── Introduction ├── Ackermann.py ├── Analysis.py ├── Introduction.py └── __pycache__ │ └── ModuleTest.cpython-38.pyc ├── LinkedList ├── CircularLinkedList.py ├── DoublyCircularLinkedList.py ├── DoublyLinkedList.py ├── LinkedList.py └── Poly.py ├── Queue ├── Queue.py ├── QueueArr.py ├── QueueExercise.py ├── QueueList.py ├── QueueUsingStack.py └── Stack.py ├── README.md ├── Searching ├── BitManipulation.py ├── FenwicTree.py └── Searching.py ├── Sorting ├── BubbleSort.py ├── BucketSort.py ├── CountSort.py ├── InsertionSort.py ├── MergeSort.py ├── QuickSelect.py ├── QuickSort.py ├── RadixSort.py ├── SelectionSort.py ├── ShellSort.py └── SortingEx.py ├── Stack ├── StackExercise.py ├── StackLinkedList.py ├── StackList.py └── TwoStack.py ├── String ├── StringClass.py ├── StringCompare.py ├── StringEx.py ├── StringTree.py ├── TST.py └── Trie.py └── Tree ├── AVLTree.py ├── BTree.py ├── BinaryIndexTree.py ├── BinarySearchTree.py ├── RBTree.py ├── RangeMaxST.py ├── RmqST.py ├── SPLAYTree.py └── SegmentTree.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | Problem-Solving-in-Data-Structures-Algorithms-using-Python 4 | 5 | 6 | 7 | 8 | 9 | org.python.pydev.PyDevBuilder 10 | 11 | 12 | 13 | 14 | 15 | org.python.pydev.pythonNature 16 | 17 | 18 | -------------------------------------------------------------------------------- /.pydevproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | Default 4 | python interpreter 5 | 6 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Python: Current File", 9 | "type": "python", 10 | "request": "launch", 11 | "program": "${file}" 12 | }, 13 | { 14 | "name": "Python: Attach", 15 | "type": "python", 16 | "request": "attach", 17 | "localRoot": "${workspaceFolder}", 18 | "remoteRoot": "${workspaceFolder}", 19 | "port": 3000, 20 | "secret": "my_secret", 21 | "host": "localhost" 22 | }, 23 | { 24 | "name": "Python: Terminal (integrated)", 25 | "type": "python", 26 | "request": "launch", 27 | "program": "${file}", 28 | "console": "integratedTerminal" 29 | }, 30 | { 31 | "name": "Python: Terminal (external)", 32 | "type": "python", 33 | "request": "launch", 34 | "program": "${file}", 35 | "console": "externalTerminal" 36 | }, 37 | { 38 | "name": "Python: Django", 39 | "type": "python", 40 | "request": "launch", 41 | "program": "${workspaceFolder}/manage.py", 42 | "args": [ 43 | "runserver", 44 | "--noreload", 45 | "--nothreading" 46 | ], 47 | "debugOptions": [ 48 | "RedirectOutput", 49 | "Django" 50 | ] 51 | }, 52 | { 53 | "name": "Python: Flask (0.11.x or later)", 54 | "type": "python", 55 | "request": "launch", 56 | "module": "flask", 57 | "env": { 58 | "FLASK_APP": "${workspaceFolder}/app.py" 59 | }, 60 | "args": [ 61 | "run", 62 | "--no-debugger", 63 | "--no-reload" 64 | ] 65 | }, 66 | { 67 | "name": "Python: Module", 68 | "type": "python", 69 | "request": "launch", 70 | "module": "module.name" 71 | }, 72 | { 73 | "name": "Python: Pyramid", 74 | "type": "python", 75 | "request": "launch", 76 | "args": [ 77 | "${workspaceFolder}/development.ini" 78 | ], 79 | "debugOptions": [ 80 | "RedirectOutput", 81 | "Pyramid" 82 | ] 83 | }, 84 | { 85 | "name": "Python: Watson", 86 | "type": "python", 87 | "request": "launch", 88 | "program": "${workspaceFolder}/console.py", 89 | "args": [ 90 | "dev", 91 | "runserver", 92 | "--noreload=True" 93 | ] 94 | }, 95 | { 96 | "name": "Python: All debug Options", 97 | "type": "python", 98 | "request": "launch", 99 | "python": "${command:python.interpreterPath}", 100 | "program": "${file}", 101 | "module": "module.name", 102 | "env": { 103 | "VAR1": "1", 104 | "VAR2": "2" 105 | }, 106 | "envFile": "${workspaceFolder}/.env", 107 | "args": [ 108 | "arg1", 109 | "arg2" 110 | ], 111 | "debugOptions": [ 112 | "RedirectOutput" 113 | ] 114 | } 115 | ] 116 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.formatting.provider": "autopep8", 3 | "cSpell.words": [ 4 | "atoi", 5 | "bhim", 6 | "bitonic", 7 | "chota", 8 | "coeff", 9 | "coeffs", 10 | "curr", 11 | "currsum", 12 | "expn", 13 | "heapify", 14 | "heapq", 15 | "infi", 16 | "Kdistance", 17 | "klargest", 18 | "kruskal", 19 | "ksmallest", 20 | "maxofmin", 21 | "minofmax", 22 | "mycounter", 23 | "outsrt", 24 | "powm", 25 | "segarray", 26 | "segtree", 27 | "sortk", 28 | "strcmp", 29 | "treversal" 30 | ] 31 | } -------------------------------------------------------------------------------- /AlgorithmsChapters/BT/GraphColouring.py: -------------------------------------------------------------------------------- 1 | # Check if the whole graph is coloured properly. 2 | def is_safe2(graph, colour, V) : 3 | for i in range(V) : 4 | for j in range(i+1, V): 5 | if (graph[i][j] and colour[j] == colour[i]) : 6 | return False 7 | return True 8 | 9 | def graph_colouring_util2(graph, V, m, colour, i) : 10 | if (i == V) : 11 | if (is_safe2(graph, colour, V)) : 12 | print("Assigned colours are::", colour) 13 | return True 14 | return False 15 | 16 | # Assign each colour from 1 to m 17 | for j in range(1, m+1): 18 | colour[i] = j 19 | if (graph_colouring_util2(graph, V, m, colour, i + 1)) : 20 | return True 21 | return False 22 | 23 | def graph_colouring2(graph, V, m) : 24 | colour = [0] * V 25 | if (graph_colouring_util2(graph, V, m, colour, 0)) : 26 | return True 27 | return False 28 | 29 | # Is it safe to colour vth vertice with c colour. 30 | def is_safe(graph, V, colour, v, c) : 31 | i = 0 32 | for i in range(0, V) : 33 | if (graph[v][i] == True and c == colour[i]) : 34 | return False 35 | return True 36 | 37 | def graph_colouring_util(graph, V, m, colour, i) : 38 | if (i == V) : 39 | print("Assigned colours are::", colour) 40 | return True 41 | for j in range(1, m+1): 42 | if (is_safe(graph, V, colour, i, j)) : 43 | colour[i] = j 44 | if (graph_colouring_util(graph, V, m, colour, i + 1)) : 45 | return True 46 | return False 47 | 48 | def graph_colouring(graph, V, m) : 49 | colour = [0] * V 50 | if (graph_colouring_util(graph, V, m, colour, 0)) : 51 | return True 52 | return False 53 | 54 | # Testing Code. 55 | graph = [[False, True, False, False, True], 56 | [True, False, True, False, True], 57 | [False, True, False, True, True], 58 | [False, False, True, False, True], 59 | [True, True, True, True, False]] 60 | 61 | V = 5 # Number of vertices 62 | m = 4 # Number of colours 63 | 64 | if (not graph_colouring(graph, V, m)) : 65 | print("Solution does not exist") 66 | if (not graph_colouring2(graph, V, m)) : 67 | print("Solution does not exist") 68 | 69 | """ 70 | Assigned colours are:: [1, 2, 1, 2, 3] 71 | Assigned colours are:: [1, 2, 1, 2, 3] 72 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/BT/NQueen.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | def feasible(Q, k) : 4 | for i in range(k) : 5 | if (Q[k] == Q[i] or abs(Q[i] - Q[k]) == abs(i - k)) : 6 | return False 7 | return True 8 | 9 | def nqueens(Q, k, n) : 10 | if (k == n) : 11 | print(Q) 12 | return 13 | for i in range(n) : 14 | Q[k] = i 15 | if (feasible(Q, k)) : 16 | nqueens(Q, k + 1, n) 17 | 18 | # Testing Code. 19 | Q = [0] * (8) 20 | nqueens(Q, 0, 8) 21 | 22 | """ 23 | [0, 4, 7, 5, 2, 6, 1, 3] 24 | [0, 5, 7, 2, 6, 3, 1, 4] 25 | . 26 | . 27 | . 28 | [7, 2, 0, 5, 1, 4, 6, 3] 29 | [7, 3, 0, 2, 5, 1, 6, 4] 30 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/BT/Permutations.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | def permutation(arr, i, length) : 4 | if (length == i) : 5 | print(arr) 6 | return 7 | 8 | for j in range(i, length) : 9 | arr[i], arr[j] = arr[j], arr[i] # Swap 10 | permutation(arr, i + 1, length) 11 | arr[i], arr[j] = arr[j], arr[i] # Swap 12 | 13 | def isValid(arr, n) : 14 | for j in range(1, n) : 15 | if (abs(arr[j] - arr[j - 1]) < 2) : 16 | return False 17 | return True 18 | 19 | def permutation2(arr, i, length) : 20 | if (length == i) : 21 | if (isValid(arr, length)) : 22 | print(arr) 23 | return 24 | 25 | for j in range(i, length) : 26 | arr[i], arr[j] = arr[j], arr[i] # Swap 27 | permutation2(arr, i + 1, length) 28 | arr[i], arr[j] = arr[j], arr[i] # Swap 29 | 30 | def isValid2(arr, i) : 31 | if (i < 1 or abs(arr[i] - arr[i - 1]) >= 2) : 32 | return True 33 | return False 34 | 35 | def permutation3(arr, i, length) : 36 | if (length == i) : 37 | print(arr) 38 | return 39 | 40 | for j in range(i, length) : 41 | arr[i], arr[j] = arr[j], arr[i] # Swap 42 | if (isValid2(arr, i)) : 43 | permutation3(arr, i + 1, length) 44 | arr[i], arr[j] = arr[j], arr[i] # Swap 45 | 46 | # Testing code 47 | arr = list(range(1, 5)) 48 | permutation(arr, 0, 4) 49 | print() 50 | permutation2(arr, 0, 4) 51 | print() 52 | permutation3(arr, 0, 4) 53 | 54 | """ 55 | [1, 2, 3, 4] 56 | [1, 2, 4, 3] 57 | ..... 58 | [4, 1, 3, 2] 59 | [4, 1, 2, 3] 60 | """ 61 | """ 62 | [2, 4, 1, 3] 63 | [3, 1, 4, 2] 64 | 65 | [2, 4, 1, 3] 66 | [3, 1, 4, 2] 67 | """ 68 | -------------------------------------------------------------------------------- /AlgorithmsChapters/BT/SubsetSum.py: -------------------------------------------------------------------------------- 1 | 2 | def print_subset(flags, arr, size) : 3 | for i in range (0, size) : 4 | if (flags[i]) : 5 | print(str(arr[i]), end =" ") 6 | print() 7 | 8 | def subset_sum(arr, n, target) : 9 | flags = [False] * n 10 | subset_sum_util(arr, n, flags, 0, 0, target) 11 | 12 | def subset_sum_util(arr, n, flags, sum, curr, target) : 13 | if (target == sum) : # Solution found. 14 | print_subset(flags, arr, n) 15 | return 16 | 17 | if (curr >= n or sum > target) : # constraint check 18 | return # Backtracking. 19 | 20 | 21 | flags[curr] = True # Current element included. 22 | subset_sum_util(arr, n, flags, sum + arr[curr], curr + 1, target) 23 | flags[curr] = False # Current element excluded. 24 | subset_sum_util(arr, n, flags, sum, curr + 1, target) 25 | 26 | 27 | 28 | # Testing code 29 | arr = [15, 22, 14, 26, 32, 9, 16, 8] 30 | target = 53 31 | subset_sum(arr, len(arr), target) 32 | 33 | """ 34 | 15 22 16 35 | 15 14 16 8 36 | 22 14 9 8 37 | """ 38 | -------------------------------------------------------------------------------- /AlgorithmsChapters/BT/TOH.py: -------------------------------------------------------------------------------- 1 | def toh_util(num, src, dst, temp) : 2 | if (num < 1) : 3 | return 4 | toh_util(num - 1, src, temp, dst) 5 | print("Move disk " + str(num) + " src peg " + str(src) + " to peg " + str(dst)) 6 | toh_util(num - 1, temp, dst, src) 7 | 8 | def toh(num) : 9 | print("The sequence of moves involved in the Tower of Hanoi are :") 10 | toh_util(num, 'A', 'C', 'B') 11 | 12 | # Testing Code 13 | toh(3) 14 | 15 | 16 | """ 17 | sequence of moves involved in the Tower of Hanoi are : 18 | Move disk 1 src peg A to peg C 19 | Move disk 2 src peg A to peg B 20 | Move disk 1 src peg C to peg B 21 | Move disk 3 src peg A to peg C 22 | Move disk 1 src peg B to peg A 23 | Move disk 2 src peg B to peg C 24 | Move disk 1 src peg A to peg C 25 | """ 26 | -------------------------------------------------------------------------------- /AlgorithmsChapters/BT/TSP.py: -------------------------------------------------------------------------------- 1 | import math 2 | import sys 3 | 4 | def tsp(graph, n) : 5 | visited = [False] * n 6 | path = [0] * (n+1) 7 | visited[0] = True 8 | ans = [0]*2 9 | ans[0] = sys.maxsize # Path cost. 10 | tsp_util(graph, n, path, 1, 0, visited, ans) 11 | return ans 12 | 13 | def tsp_util(graph, n, path, path_size, path_cost, visited, ans) : 14 | if ans[0] <= path_cost : # Ignore useless paths. 15 | return; 16 | 17 | curr = path[path_size - 1] 18 | if path_size == n : 19 | if graph[curr][0] > 0 and ans[0] > path_cost + graph[curr][0] : 20 | path[path_size] = 0 21 | ans[0] = path_cost + graph[curr][0] 22 | ans[1] = list_to_string(path) 23 | return; 24 | 25 | for i in range(0, n): 26 | if (visited[i] == False and graph[curr][i] > 0) : 27 | visited[i] = True 28 | path[path_size] = i 29 | tsp_util(graph, n, path, path_size + 1, path_cost + graph[curr][i], visited, ans) 30 | visited[i] = False 31 | 32 | def list_to_string(lst): 33 | str1 = "" 34 | for ele in lst: 35 | str1 += str(ele) 36 | str1 += " " 37 | return str1 38 | 39 | # Testing Code 40 | n = 4 41 | graph = [[0, 10, 15, 20], [10, 0, 35, 25], [15, 35, 0, 30], [20, 25, 30, 0]] 42 | ans = tsp(graph, n) 43 | print(f"TSP path: {ans[1]}, cost: {ans[0]}") 44 | 45 | """ 46 | TSP path: 0 1 3 2 0 , cost: 80 47 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/CA/IsPrime.py: -------------------------------------------------------------------------------- 1 | def is_prime(n) : 2 | answer = True if (n > 1) else False 3 | i = 2 4 | while (i * i <= n) : 5 | if (n % i == 0) : 6 | answer = False 7 | break 8 | i += 1 9 | return answer 10 | 11 | # Testing Code 12 | print( is_prime(7)) 13 | 14 | -------------------------------------------------------------------------------- /AlgorithmsChapters/DAC/ClosestPair.py: -------------------------------------------------------------------------------- 1 | import math 2 | import sys 3 | 4 | def closestPairBF(arr) : 5 | n = len(arr) 6 | dmin = sys.maxsize 7 | for i in range (0, n - 1) : 8 | for j in range(i+1, n) : 9 | d = math.sqrt((arr[i][0] - arr[j][0]) * (arr[i][0] - arr[j][0]) + (arr[i][1] - arr[j][1]) * (arr[i][1] - arr[j][1])) 10 | if (d < dmin) : 11 | dmin = d 12 | return dmin 13 | 14 | 15 | class Point : 16 | def __init__(self, a, b) : 17 | self.x = a 18 | self.y = b 19 | 20 | def distance(a, b) : 21 | return math.sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)) 22 | 23 | def stripMin(q, n, d) : 24 | min = d 25 | # Find the distance between all the points in the strip. 26 | # Array q is sorted according to the y axis coordinate. 27 | # The inner loop will run at most 6 times for each point. 28 | for i in range (0, n) : 29 | j = i + 1 30 | while (j < n and (q[j].y - q[i].y) < min) : 31 | d = distance(q[i], q[j]) 32 | if (d < min) : 33 | min = d 34 | j += 1 35 | return min 36 | 37 | 38 | def closestPairDCUtil(p, start, stop, q, n) : 39 | if (stop - start < 1) : 40 | return sys.maxsize 41 | if (stop - start == 1) : 42 | return distance(p[start], p[stop]) 43 | 44 | mid = (start + stop) // 2 # Find the middle point 45 | dl = closestPairDCUtil(p, start, mid, q, n) 46 | dr = closestPairDCUtil(p, mid + 1, stop, q, n) 47 | d = min(dl,dr) 48 | 49 | # Build an list strip[] that contains points whose x axis coordinate 50 | # in the range p[mid]-d and p[mid]+d 51 | # Points are already sorted according to y axis. 52 | strip = [None] * n 53 | j = 0 54 | for i in range (0, n) : 55 | if (abs(q[i].x - p[mid].x) < d) : 56 | strip[j] = q[i] 57 | j += 1 58 | 59 | # Find the closest points in strip and compare with d. 60 | return min(d,stripMin(strip, j, d)) 61 | 62 | 63 | def closestPairDC(arr) : 64 | n = len(arr) 65 | p = [None] * n 66 | for i in range(0, n) : 67 | p[i] = Point(arr[i][0], arr[i][1]) 68 | 69 | p.sort(key = lambda a : a.x)# Sort according to x axis. 70 | q = p.copy() 71 | q.sort(key = lambda a : a.y) # Sort according to y axis. 72 | return closestPairDCUtil(p, 0, n - 1, q, n) 73 | 74 | # Testing Code 75 | arr = [[648, 896], [269, 879], [250, 922], [453, 347], [213, 17]] 76 | print("Smallest distance is:", closestPairBF(arr)) 77 | print("Smallest distance is:", closestPairDC(arr)) 78 | 79 | """ 80 | Smallest distance is: 47.01063709417264 81 | Smallest distance is: 47.01063709417264 82 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/DAC/NutsAndBolts.py: -------------------------------------------------------------------------------- 1 | def make_pairs(nuts, bolts) : 2 | make_pairs_util(nuts, bolts, 0, len(nuts) - 1) 3 | print("Matched nuts and bolts are : ", nuts, "&", bolts) 4 | 5 | # Quick sort kind of approach. 6 | def make_pairs_util(nuts, bolts, low, high) : 7 | if (low < high) : 8 | # Choose first element of bolts list as pivot to partition nuts. 9 | pivot = partition(nuts, low, high, bolts[low]) 10 | # Using nuts[pivot] as pivot to partition bolts. 11 | partition(bolts, low, high, nuts[pivot]) 12 | # Recursively lower and upper half of nuts and bolts are matched. 13 | make_pairs_util(nuts, bolts, low, pivot - 1) 14 | make_pairs_util(nuts, bolts, pivot + 1, high) 15 | 16 | # Partition method similar to quick sort algorithm. 17 | def partition(arr, low, high, pivot) : 18 | i, j = low, low 19 | while (j < high) : 20 | if (arr[j] < pivot) : 21 | arr[i], arr[j] = arr[j], arr[i] # Swap 22 | i += 1 23 | elif(arr[j] == pivot) : 24 | arr[high], arr[j] = arr[j], arr[high] # Swap 25 | j -= 1 26 | j += 1 27 | arr[i], arr[high] = arr[high], arr[i] # Swap 28 | return i 29 | 30 | # Testing Code 31 | nuts = [1, 2, 6, 5, 4, 3] 32 | bolts = [6, 4, 5, 1, 3, 2] 33 | make_pairs(nuts, bolts) 34 | 35 | """ 36 | Matched nuts and bolts are : [1, 2, 3, 4, 5, 6] & [1, 2, 3, 4, 5, 6] 37 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/ALS.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | def als_fastest_way_bu2(a, t, e, x, n) : 4 | f1 = [0] * n 5 | f2 = [0] * n 6 | # Time taken to leave first station. 7 | f1[0] = e[0] + a[0][0] 8 | f2[0] = e[1] + a[1][0] 9 | 10 | # Fill the tables f1[] and f2[] using bottom up approach. 11 | for i in range(1, n) : 12 | f1[i] = min(f1[i - 1] + a[0][i],f2[i - 1] + t[1][i - 1] + a[0][i]) 13 | f2[i] = min(f2[i - 1] + a[1][i],f1[i - 1] + t[0][i - 1] + a[1][i]) 14 | 15 | # Consider exit times and return minimum. 16 | return min(f1[n - 1] + x[0],f2[n - 1] + x[1]) 17 | 18 | def als_fastest_way_bu(a, t, e, x, n) : 19 | f = [[0] * n for _ in range(2)] 20 | 21 | # Time taken to leave first station. 22 | f[0][0] = e[0] + a[0][0] 23 | f[1][0] = e[1] + a[1][0] 24 | 25 | # Fill the tables f1[] and f2[] using bottom up approach. 26 | for i in range(1, n) : 27 | f[0][i] = min(f[0][i - 1] + a[0][i],f[1][i - 1] + t[1][i - 1] + a[0][i]) 28 | f[1][i] = min(f[1][i - 1] + a[1][i],f[0][i - 1] + t[0][i - 1] + a[1][i]) 29 | 30 | # Consider exit times and return minimum. 31 | return min(f[0][n - 1] + x[0],f[1][n - 1] + x[1]) 32 | 33 | def als_fastest_way_td(a, t, e, x, n) : 34 | f = [[0] * n for _ in range(2)] 35 | 36 | # Time taken to leave first station. 37 | f[0][0] = e[0] + a[0][0] 38 | f[1][0] = e[1] + a[1][0] 39 | 40 | als_fastest_way_td_util(f, a, t, n - 1) 41 | return min(f[0][n - 1] + x[0],f[1][n - 1] + x[1]) 42 | 43 | def als_fastest_way_td_util(f, a, t, i) : 44 | if (i == 0) : 45 | return 46 | als_fastest_way_td_util(f, a, t, i - 1) 47 | # Fill the tables f1[] and f2[] using top-down approach. 48 | f[0][i] = min(f[0][i - 1] + a[0][i],f[1][i - 1] + t[1][i - 1] + a[0][i]) 49 | f[1][i] = min(f[1][i - 1] + a[1][i],f[0][i - 1] + t[0][i - 1] + a[1][i]) 50 | 51 | # Testing code 52 | a = [[7, 9, 3, 4, 8, 4], [8, 5, 6, 4, 5, 7]] 53 | t = [[2, 3, 1, 3, 4], [2, 1, 2, 2, 1]] 54 | e = [2, 4] 55 | x = [3, 2] 56 | n = 6 57 | print("ALS fastest way cost:", als_fastest_way_bu2(a, t, e, x, n)) 58 | print("ALS fastest way cost:", als_fastest_way_bu(a, t, e, x, n)) 59 | print("ALS fastest way cost:", als_fastest_way_td(a, t, e, x, n)) 60 | 61 | """ 62 | ALS fastest way cost: 38 63 | ALS fastest way cost: 38 64 | ALS fastest way cost: 38 65 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/CoinChange.py: -------------------------------------------------------------------------------- 1 | import math 2 | import sys 3 | 4 | def min_coins(d, n, val) : # Greedy may be wrong. 5 | if (val <= 0) : 6 | return 0 7 | count = 0 8 | d.sort() 9 | i = n - 1 10 | while (i >= 0 and val > 0) : 11 | if (d[i] <= val) : 12 | count += 1 13 | val -= d[i] 14 | else : 15 | i -= 1 16 | 17 | return count if (val == 0) else -1 18 | 19 | 20 | def min_coins2(d, n, val) : # Brute force. 21 | if (val == 0) : 22 | return 0 23 | 24 | count = sys.maxsize 25 | for i in range (0, n) : 26 | if (d[i] <= val) : 27 | sub_count = min_coins2(d, n, val - d[i]) 28 | if (sub_count != -1) : 29 | count = min(count, sub_count + 1) 30 | 31 | return count if (count != sys.maxsize) else -1 32 | 33 | def min_coins_td(d, n, val) : # DP top down approach. 34 | coins = [sys.maxsize] * (val + 1) 35 | return min_coins_td_util(coins, d, n, val) 36 | 37 | def min_coins_td_util(coins, d, n, val) : 38 | # Base Case 39 | if (val == 0) : 40 | return 0 41 | 42 | if (coins[val] != sys.maxsize) : 43 | return coins[val] 44 | 45 | # Recursion 46 | for i in range(0, n) : 47 | if (d[i] <= val) : # check validity of a sub-problem 48 | sub_count = min_coins_td_util(coins, d, n, val - d[i]) 49 | if (sub_count != sys.maxsize) : 50 | coins[val] = min(coins[val], sub_count + 1) 51 | return coins[val] 52 | 53 | def min_coins_bu(d, n, val) : # DP bottom up approach. 54 | # coins[i] used to store number of coins required to make sum i 55 | coins = [sys.maxsize] * (val + 1) 56 | coins[0] = 0 # Base value. 57 | 58 | for i in range (1, val+1) : 59 | for j in range (0, n) : 60 | if (d[j] <= i) : # For all coins smaller than or equal to i. 61 | if (coins[i - d[j]] != sys.maxsize) : 62 | coins[i] = min(coins[i], coins[i - d[j]] + 1) 63 | return coins[val] if (coins[val] != sys.maxsize) else -1 64 | 65 | 66 | def min_coins_bu2(d, n, val) : # DP bottom up approach. 67 | # coins[i] used to store number of coins required to make sum i 68 | coins = [sys.maxsize] * (val + 1) 69 | deno = [sys.maxsize] * (val + 1) 70 | coins[0] = 0 # Base value. 71 | 72 | for i in range (1, val+1) : 73 | for j in range (0, n) : 74 | # For all coins smaller than or equal to i. 75 | if d[j] <= i and coins[i - d[j]] != sys.maxsize and coins[i] > coins[i - d[j]] + 1: 76 | coins[i] = coins[i - d[j]] + 1 77 | deno[i] = d[j] 78 | 79 | print_coins(deno, val) 80 | return coins[val] if (coins[val] != sys.maxsize) else -1 81 | 82 | def print_coins_util(deno, val) : 83 | if val > 0 : 84 | print_coins_util(deno, val - deno[val]) 85 | print(deno[val], end=" ") 86 | 87 | def print_coins(deno, val) : 88 | print("Coins are : ", end="") 89 | print_coins_util(deno, val) 90 | print() 91 | 92 | # Testing code 93 | d = [1, 4, 6, 9, 12] 94 | value = 15 95 | n = len(d) 96 | print("Coins count :" + str(min_coins(d, n, value))) 97 | print("Coins count :" + str(min_coins2(d, n, value))) 98 | print("Coins count :" + str(min_coins_bu(d, n, value))) 99 | print("Coins count :" + str(min_coins_bu2(d, n, value))) 100 | print("Coins count :" + str(min_coins_td(d, n, value))) 101 | 102 | """ 103 | Coins count :-1 104 | Coins count :3 105 | Coins count :3 106 | Coins are : 6 5 5 107 | Coins count :3 108 | Coins count :3 109 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/DiceThrow.py: -------------------------------------------------------------------------------- 1 | def find_ways(n, m, V) : 2 | dp = [[0] * (V + 1) for _ in range(n + 1)] 3 | # Table entries for only one dice. 4 | j = 1 5 | while (j <= m and j <= V) : 6 | dp[1][j] = 1 7 | j += 1 8 | 9 | # i is number of dice, j is Value, k value of dice. 10 | for i in range(2, n+1) : 11 | for j in range(1, V+1) : 12 | k = 1 13 | while (k <= j and k <= m) : 14 | dp[i][j] += dp[i - 1][j - k] 15 | k += 1 16 | return dp[n][V] 17 | 18 | # Testing code. 19 | for i in range(1, 7) : 20 | print(find_ways(i, 6, 6), end=" ") 21 | 22 | """ 23 | 1 5 10 10 5 1 24 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/EditDist.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | def edit_dist(str1, str2) : 4 | return edit_dist_util(str1, str2, len(str1), len(str2)) 5 | 6 | def edit_dist_util (str1, str2, m, n) : 7 | if (m == 0 or n == 0) : # If any one string is empty, then empty the other string. 8 | return m + n 9 | # If last characters of both strings are same, ignore last characters. 10 | if (str1[m - 1] == str2[n - 1]) : 11 | return edit_dist_util (str1, str2, m - 1, n - 1) 12 | # If last characters are not same, 13 | # then consider all three operations: 14 | # Insert last char of second into first. 15 | # Remove last char of first. 16 | # Replace last char of first with second. 17 | return 1 + min(edit_dist_util (str1, str2, m, n - 1), 18 | edit_dist_util(str1, str2, m - 1, n), 19 | edit_dist_util(str1, str2, m - 1, n - 1)) 20 | 21 | def edit_dist_dp(str1, str2) : 22 | m = len(str1) 23 | n = len(str2) 24 | dp = [[0] * (n + 1) for _ in range(m + 1)] 25 | # Fill dp[][] in bottom up manner. 26 | for i in range(0, m+1) : 27 | for j in range(0, n+1) : 28 | # If any one string is empty, then empty the other string. 29 | if (i == 0 or j == 0) : 30 | dp[i][j] = (i + j) 31 | elif (str1[i - 1] == str2[j - 1]) : 32 | dp[i][j] = dp[i - 1][j - 1] 33 | else : 34 | dp[i][j] = 1 + min( dp[i][j - 1], dp[i - 1][j], dp[i - 1][j - 1]) 35 | return dp[m][n] 36 | 37 | # Testing code 38 | str1 = "sunday" 39 | str2 = "saturday" 40 | print("Edit distance is:", edit_dist(str1, str2)) 41 | print("Edit distance is:", edit_dist_dp(str1, str2)) 42 | 43 | """ 44 | Edit distance is: 3 45 | Edit distance is: 3 46 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/Fibo.py: -------------------------------------------------------------------------------- 1 | def fibonacci(n) : 2 | if n < 2 : 3 | return n 4 | 5 | return fibonacci(n - 1) + fibonacci(n - 2) 6 | 7 | def fibonacci_series(n) : 8 | for i in range(0, n) : 9 | arr[i] = fibonacci(i) 10 | print(arr) 11 | 12 | def fibonacci_bu(n) : 13 | if n < 2 : 14 | return n 15 | 16 | dp = [0]*(n+1) 17 | dp[0] = 0 18 | dp[1] = 1 19 | 20 | for i in range(2, n+1) : 21 | dp[i] = dp[i-1] + dp[i-2] 22 | 23 | return dp[n] 24 | 25 | 26 | 27 | def fibonacci_td(n) : 28 | dp = [0] * (n+1) 29 | fibonacci_td_util(n, dp) 30 | return dp[n] 31 | 32 | def fibonacci_td_util(n, dp) : 33 | if n < 2 : 34 | dp[n] = n 35 | return n 36 | 37 | if dp[n] == 0: 38 | dp[n] = fibonacci_td_util(n - 1, dp) + fibonacci_td_util(n - 2, dp) 39 | 40 | return dp[n] 41 | 42 | # Testing code 43 | print(fibonacci(10)) 44 | print(fibonacci_bu(10)) 45 | print(fibonacci_td(10)) 46 | print(fibonacci(1)) 47 | print(fibonacci_bu(1)) 48 | print(fibonacci_td(1)) 49 | """ 50 | 55 51 | 55 52 | 55 53 | """ 54 | -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/FloydWarshall.py: -------------------------------------------------------------------------------- 1 | import math 2 | import sys 3 | 4 | INF = sys.maxsize 5 | 6 | def floyd_warshall(graph, V) : 7 | dist = [[0] * V for _ in range(V)] 8 | for i in range(0, V) : 9 | for j in range(0, V) : 10 | dist[i][j] = graph[i][j] 11 | 12 | # Pick intermediate vertices. 13 | for k in range(0, V) : 14 | # Pick source vertices one by one. 15 | for i in range(0, V) : 16 | # Pick destination vertices. 17 | for j in range(0, V) : 18 | # If we have shorter path from i to j via k. 19 | # then update dist[i][j] 20 | if (dist[i][k] != INF and dist[k][j] != INF and dist[i][k] + dist[k][j] < dist[i][j]) : 21 | dist[i][j] = dist[i][k] + dist[k][j] 22 | 23 | print_solution(dist, V) # Print the shortest distance matrix 24 | 25 | def print_solution(dist, V) : 26 | for i in range(0, V) : 27 | for j in range(0, V) : 28 | if (dist[i][j] == INF) : 29 | print("INF", end =" ") 30 | else : 31 | print(dist[i][j], end =" ") 32 | print() 33 | 34 | # Testing code 35 | graph = [ 36 | [0, 2, 4, INF, INF, INF, INF], 37 | [2, 0, 4, 1, INF, INF, INF], 38 | [4, 4, 0, 2, 8, 4, INF], 39 | [INF, 1, 2, 0, 3, INF, 6], 40 | [INF, INF, 6, 4, 0, 3, 1], 41 | [INF, INF, 4, INF, 4, 0, 2], 42 | [INF, INF, INF, 4, 2, 3, 0]] 43 | 44 | floyd_warshall(graph, 7) 45 | 46 | """ 47 | 0 2 4 3 6 8 7 48 | 2 0 3 1 4 7 5 49 | 4 3 0 2 5 4 6 50 | 3 1 2 0 3 6 4 51 | 7 5 6 4 0 3 1 52 | 8 7 4 6 4 0 2 53 | 7 5 6 4 2 3 0 54 | """ 55 | -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/GridMinCost.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | def min_cost(cost, m, n) : 4 | if (m == 0 or n == 0) : 5 | return 99999 6 | 7 | if (m == 1 and n == 1) : 8 | return cost[0][0] 9 | 10 | return cost[m-1][n-1] + min(min_cost(cost, m-1, n-1), 11 | min_cost(cost, m-1, n), 12 | min_cost(cost, m, n-1)) 13 | 14 | def min_cost_bu(cost, m, n) : 15 | tc = [[0] * n for _ in range(m)] 16 | tc[0][0] = cost[0][0] 17 | 18 | # Initialize first column. 19 | for i in range(1, m) : 20 | tc[i][0] = tc[i-1][0] + cost[i][0] 21 | 22 | # Initialize first row. 23 | for j in range(1, n) : 24 | tc[0][j] = tc[0][j-1] + cost[0][j] 25 | 26 | for i in range(1, m) : 27 | for j in range(1, n) : 28 | tc[i][j] = cost[i][j] + min(tc[i-1][j-1], tc[i-1][j], tc[i][j-1]) 29 | 30 | return tc[m-1][n-1] 31 | 32 | # Testing code 33 | cost = [[1, 3, 4], [4, 7, 5], [1, 5, 3]] 34 | print("Min cost :", min_cost(cost, 3, 3)) 35 | print("Min cost :", min_cost_bu(cost, 3, 3)) 36 | 37 | """ 38 | Min cost : 11 39 | Min cost : 11 40 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/GridUniqueWays.py: -------------------------------------------------------------------------------- 1 | 2 | def unique_ways(m, n) : 3 | dp = [[0] * n for _ in range(m)] 4 | dp[0][0] = 1 5 | 6 | # Initialize first column. 7 | for i in range(1, m) : 8 | dp[i][0] = dp[i - 1][0] 9 | 10 | # Initialize first row. 11 | for j in range(1, n) : 12 | dp[0][j] = dp[0][j - 1] 13 | 14 | for i in range(1, m) : 15 | for j in range(1, n) : 16 | dp[i][j] = dp[i - 1][j] + dp[i][j - 1] 17 | 18 | return dp[m - 1][n - 1] 19 | 20 | # Diagonal movement allowed. 21 | def unique_3ways(m, n) : 22 | dp = [[0] * n for _ in range(m)] 23 | dp[0][0] = 1 24 | 25 | # Initialize first column. 26 | for i in range(1, m) : 27 | dp[i][0] = dp[i - 1][0] 28 | 29 | # Initialize first row. 30 | for j in range(1, n) : 31 | dp[0][j] = dp[0][j - 1] 32 | 33 | for i in range(1, m) : 34 | for j in range(1, n) : 35 | dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j] + dp[i][j - 1] 36 | 37 | return dp[m - 1][n - 1] 38 | 39 | # Testing code 40 | print(unique_ways(3, 3)) 41 | print(unique_3ways(3, 3)) 42 | 43 | """ 44 | 6 45 | 13 46 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/HouseRobber.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | def max_robbery(house) : 4 | n = len(house) 5 | dp = [0] * n 6 | 7 | #Base case 8 | dp[0] = house[0] 9 | dp[1] = house[1] 10 | dp[2] = dp[0] + house[2] 11 | 12 | for i in range(3, n) : 13 | dp[i] = max(dp[i - 2],dp[i - 3]) + house[i] 14 | 15 | return max(dp[n - 1],dp[n - 2]) 16 | 17 | 18 | def max_robbery2(house) : 19 | n = len(house) 20 | dp = [[0] * (2) for _ in range(n)] 21 | dp[0][1] = house[0] 22 | dp[0][0] = 0 23 | for i in range(1, n) : 24 | dp[i][1] = max(dp[i - 1][0] + house[i],dp[i - 1][1]) 25 | dp[i][0] = dp[i - 1][1] 26 | 27 | return max(dp[n - 1][1],dp[n - 1][0]) 28 | 29 | # Testing code 30 | arr = [10, 12, 9, 23, 25, 55, 49, 70] 31 | print("Total cash: " + str(max_robbery(arr))) 32 | print("Total cash: " + str(max_robbery2(arr))) 33 | 34 | """ 35 | Total cash: 160 36 | Total cash: 160 37 | """ 38 | -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/JobScheduling.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | # Also known as Activity Selection Weighted. 4 | 5 | class Job : 6 | def __init__(self, s, f, v) : 7 | self.start = s 8 | self.stop = f 9 | self.value = v 10 | 11 | def max_value_jobs_util(arr, n) : 12 | # Base case 13 | if (n == 1) : 14 | return arr[0].value 15 | # Find Value when current job is included 16 | incl = arr[n - 1].value 17 | for j in range(n-1, -1, -1) : # n-1 to 0 18 | if (arr[j].stop <= arr[n - 1].start) : 19 | incl += max_value_jobs_util(arr, j + 1) 20 | break 21 | # Find Value when current job is excluded 22 | excl = max_value_jobs_util(arr, n - 1) 23 | return max(incl,excl) 24 | 25 | def max_value_jobs(s, f, v, n) : 26 | act = [None] * n 27 | for i in range(0, n) : 28 | act[i] = Job(s[i], f[i], v[i]) 29 | 30 | act.sort(key = lambda a : a.stop) # sort according to finish time. 31 | return max_value_jobs_util(act, n) 32 | 33 | def max_value_jobs_td_util(dp, arr, n) : 34 | # Base case 35 | if (n == 0) : 36 | return 0 37 | 38 | if (dp[n - 1] != 0) : 39 | return dp[n - 1] 40 | 41 | # Find Value when current job is included 42 | incl = arr[n - 1].value 43 | for j in range(n-2, -1, -1) : # n-1 to 0 44 | if (arr[j].stop <= arr[n - 1].start) : 45 | incl += max_value_jobs_td_util(dp, arr, j + 1) 46 | break 47 | # Find Value when current job is excluded 48 | excl = max_value_jobs_td_util(dp, arr, n - 1) 49 | dp[n - 1] = max(incl,excl) 50 | return dp[n - 1] 51 | 52 | def max_value_jobs_td(s, f, v, n) : 53 | act = [None] * n 54 | for i in range(0, n) : 55 | act[i] = Job(s[i], f[i], v[i]) 56 | act.sort(key = lambda a : a.stop) # sort according to finish time. 57 | dp = [0] * n 58 | return max_value_jobs_td_util(dp, act, n) 59 | 60 | def max_value_jobs_bu(s, f, v, n) : 61 | act = [None] * n 62 | for i in range(0, n) : 63 | act[i] = Job(s[i], f[i], v[i]) 64 | 65 | act.sort(key = lambda a : a.stop) # sort according to finish time. 66 | dp = [0] * n 67 | dp[0] = act[0].value 68 | for i in range(1, n) : 69 | incl = act[i].value 70 | for j in range(i - 1, -1, -1) : # i-1 to 0 71 | if (act[j].stop <= act[i].start) : 72 | incl += dp[j] 73 | break 74 | dp[i] = max(incl,dp[i - 1]) 75 | return dp[n - 1] 76 | 77 | # Testing code 78 | start = [1, 5, 0, 3, 5, 6, 8] 79 | finish = [2, 6, 5, 4, 9, 7, 9] 80 | value = [2, 2, 4, 3, 10, 2, 8] 81 | n = len(start) 82 | print(max_value_jobs(start, finish, value, n)) 83 | print(max_value_jobs_td(start, finish, value, n)) 84 | print(max_value_jobs_bu(start, finish, value, n)) 85 | 86 | """ 87 | 17 88 | 17 89 | 17 90 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/Knapsack.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | def max_cost01(wt, cost, capacity) : 4 | return max_cost01_util(wt, cost, len(wt), capacity) 5 | 6 | def max_cost01_util(wt, cost, n, capacity) : 7 | # Base Case 8 | if (n == 0 or capacity == 0) : 9 | return 0 10 | # Return the maximum of two cases: 11 | # (1) nth item is included 12 | # (2) nth item is not included 13 | first = 0 14 | if (wt[n - 1] <= capacity) : 15 | first = cost[n - 1] + max_cost01_util(wt, cost, n - 1, capacity - wt[n - 1]) 16 | second = max_cost01_util(wt, cost, n - 1, capacity) 17 | return max(first, second) 18 | 19 | def max_cost01_td(wt, cost, capacity) : 20 | n = len(wt) 21 | dp = [[0] * (n + 1) for _ in range(capacity + 1)] 22 | return max_cost01_td_util(dp, wt, cost, n, capacity) 23 | 24 | def max_cost01_td_util(dp, wt, cost, i, w) : 25 | if (w == 0 or i == 0) : 26 | return 0 27 | if (dp[w][i] != 0) : 28 | return dp[w][i] 29 | # Their are two cases: 30 | # (1) ith item is included 31 | # (2) ith item is not included 32 | first = 0 33 | if (wt[i - 1] <= w) : 34 | first = max_cost01_td_util(dp, wt, cost, i - 1, w - wt[i - 1]) + cost[i - 1] 35 | second = max_cost01_td_util(dp, wt, cost, i - 1, w) 36 | dp[w][i] = max(first, second) 37 | return dp[w][i] 38 | 39 | def max_cost01_bu(wt, cost, capacity) : 40 | n = len(wt) 41 | dp = [[0] * (n + 1) for _ in range(capacity + 1)] 42 | # Build table dp[][] in bottom up approach. 43 | # Weights considered against capacity. 44 | for w in range(1, capacity+1) : 45 | for i in range (1, n+1) : 46 | # Their are two cases: 47 | # (1) ith item is included 48 | # (2) ith item is not included 49 | first = 0 50 | if (wt[i - 1] <= w) : 51 | first = dp[w - wt[i-1]][i - 1] + cost[i - 1] 52 | second = dp[w][i - 1] 53 | dp[w][i] = max(first,second) 54 | 55 | print_items(dp, wt, cost, n, capacity); 56 | return dp[capacity][n] 57 | 58 | def print_items(dp, wt, cost, n, capacity) : 59 | total_profit = dp[capacity][n] 60 | print("Selected items are:", end =" ") 61 | for i in range(n-1, -1, -1) : 62 | if (total_profit != dp[capacity][i - 1]) : 63 | print("(wt:" + str(wt[i]) + ", profit:" + str(cost[i]) + ")", end ="") 64 | capacity -= wt[i] 65 | total_profit -= cost[i] 66 | 67 | def knapsack01_unbound_bu(wt, cost, capacity) : 68 | n = len(wt) 69 | dp = [0] * (capacity + 1) 70 | # Build table dp[] in bottom up approach. 71 | # Weights considered against capacity. 72 | for w in range(1, capacity+1) : 73 | for i in range(1, n + 1) : 74 | # Their are two cases: 75 | # (1) ith item is included 76 | # (2) ith item is not included 77 | if (wt[i - 1] <= w) : 78 | dp[w] = max(dp[w],dp[w - wt[i - 1]] + cost[i - 1]) 79 | 80 | #print_items(dp, wt, cost, n, capacity); 81 | return dp[capacity] 82 | 83 | 84 | # Testing code. 85 | wt = [10, 40, 20, 30] 86 | cost = [60, 40, 90, 120] 87 | capacity = 50 88 | print("Maximum cost obtained = ", max_cost01(wt, cost, capacity)) 89 | print("Maximum cost obtained = ", max_cost01_bu(wt, cost, capacity)) 90 | print("Maximum cost obtained = ", max_cost01_td(wt, cost, capacity)) 91 | 92 | print("Maximum cost obtained = ", knapsack01_unbound_bu(wt, cost, capacity)) 93 | 94 | 95 | """ 96 | Maximum cost obtained = 210 97 | Selected items are: (wt:30, profit:120)(wt:20, profit:90)Maximum cost obtained = 210 98 | Maximum cost obtained = 210 99 | Maximum cost obtained = 300 100 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/LargestBitonicSubseq.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | def largest_bitonic_subseq(arr) : 4 | n = len(arr) 5 | lis = [1] * n # Initialize LIS values for all indexes as 1. 6 | lds = [1] * n # Initialize LDS values for all indexes as 1. 7 | # Populating LIS values in bottom up manner. 8 | for i in range(0, n) : 9 | for j in range(0, i) : 10 | if (arr[j] < arr[i] and lis[i] < lis[j] + 1) : 11 | lis[i] = lis[j] + 1 12 | 13 | # Populating LDS values in bottom up manner. 14 | for i in range(n-1, 0, -1) : 15 | for j in range(n-1, i, -1) : 16 | if (arr[j] < arr[i] and lds[i] < lds[j] + 1) : 17 | lds[i] = lds[j] + 1 18 | mx = 0 19 | for i in range(0, n) : 20 | mx = max(mx, lis[i] + lds[i] - 1) 21 | return mx 22 | 23 | # Testing Code 24 | arr = [1, 6, 3, 11, 1, 9, 5, 12, 3, 14, 6, 17, 3, 19, 2, 19] 25 | print("Length of largest bitonic subseq is ", largest_bitonic_subseq(arr)) 26 | 27 | """ 28 | Length of largest bitonic subseq is 8 29 | """ 30 | -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/LargestIncreasingSubseq.py: -------------------------------------------------------------------------------- 1 | def largest_increasing_subseq(arr) : 2 | n = len(arr) 3 | lis = [0] * n 4 | mx = 0 5 | # Populating LIS values in bottom up manner. 6 | for i in range(n) : 7 | lis[i] = 1 8 | # Initialize LIS values for all indexes as 1. 9 | for j in range(i) : 10 | if (arr[j] < arr[i] and lis[i] < lis[j] + 1) : 11 | lis[i] = lis[j] + 1 12 | 13 | mx = max ( mx, lis[i]) 14 | 15 | return mx 16 | 17 | # Testing Code 18 | arr = [10, 12, 9, 23, 25, 55, 49, 70] 19 | print("Length of lis is ", str(largest_increasing_subseq(arr))) 20 | 21 | """ 22 | Length of lis is 6 23 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/LargestPalindromicSubsequence.py: -------------------------------------------------------------------------------- 1 | import math 2 | # Palindromic Subsequence 3 | def largest_palindromic_subsequence(str) : 4 | n = len(str) 5 | dp = [[0] * n for _ in range(n)] 6 | for i in range(n) : 7 | dp[i][i] = 1 # each char is itself palindromic with length 1 8 | 9 | for l in range(1, n) : 10 | i = 0 11 | for j in range (l, n) : 12 | if (str[i] == str[j]) : 13 | dp[i][j] = dp[i + 1][j - 1] + 2 14 | else : 15 | dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]) 16 | i += 1 17 | 18 | return dp[0][n - 1] 19 | 20 | # Testing Code 21 | str = "ABCAUCBCxxCBA" 22 | print("Max Palindromic Subsequence length: ", largest_palindromic_subsequence(str)) 23 | 24 | """ 25 | Max Palindromic Subsequence length: 9 26 | """ 27 | -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/LargestPalindromicSubstr.py: -------------------------------------------------------------------------------- 1 | # Palindromic Substrings 2 | def largest_palindromic_substring(str) : 3 | n = len(str) 4 | dp = [[0] * n for _ in range(n)] 5 | for i in range(n) : 6 | dp[i][i] = 1 7 | 8 | mx = 1 9 | start = 0 10 | for l in range(1, n) : 11 | i = 0 12 | for j in range(l, n) : 13 | if (str[i] == str[j] and dp[i + 1][j - 1] == j - i - 1) : 14 | dp[i][j] = dp[i + 1][j - 1] + 2 15 | if (dp[i][j] > mx) : 16 | mx = dp[i][j] 17 | # Keeping track of mx length and 18 | start = i 19 | else : 20 | dp[i][j] = 0 21 | i += 1 22 | print("Max Length Palindromic Substrings : " + str[start:start + mx]) 23 | return mx 24 | 25 | # Testing Code 26 | str = "ABCAUCBCxxCBA" 27 | print("Max Palindromic Substrings len: ", largest_palindromic_substring(str)) 28 | 29 | """ 30 | Max Length Palindromic Substrings : BCxxCB 31 | Max Palindromic Substrings len: 6 32 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/LongestCommonSubseq.py: -------------------------------------------------------------------------------- 1 | 2 | def longest_common_subseq(X, Y) : 3 | m = len(X) 4 | n = len(Y) 5 | dp = [[0] * (n + 1) for _ in range(m + 1)] # Dynamic programming array. 6 | p = [[0] * (n + 1) for _ in range(m + 1)] # For printing the substring. 7 | 8 | # Fill dp list in bottom up fashion. 9 | for i in range(1, m+1) : 10 | for j in range(1, n+1) : 11 | if (X[i - 1] == Y[j - 1]) : 12 | dp[i][j] = dp[i - 1][j - 1] + 1 13 | p[i][j] = 0 14 | else : 15 | dp[i][j] = dp[i - 1][j] if (dp[i - 1][j] > dp[i][j - 1]) else dp[i][j - 1] 16 | p[i][j] = 1 if (dp[i - 1][j] > dp[i][j - 1]) else 2 17 | 18 | print_LCS(p, X, m, n) 19 | return dp[m][n] 20 | 21 | def print_LCS(p, X, i, j) : 22 | if (i == 0 or j == 0) : 23 | return 24 | if (p[i][j] == 0) : 25 | print_LCS(p, X, i - 1, j - 1) 26 | print(X[i - 1], end ="") 27 | elif (p[i][j] == 1) : 28 | print_LCS(p, X, i - 1, j) 29 | else : 30 | print_LCS(p, X, i, j - 1) 31 | 32 | # Testing Code 33 | X = "carpenter" 34 | Y = "sharpener" 35 | print("\nLongest common subseq length:", longest_common_subseq(X, Y)) 36 | 37 | """ 38 | arpener 39 | Longest common subseq length: 7 40 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/MatrixCM.py: -------------------------------------------------------------------------------- 1 | import math 2 | import sys 3 | 4 | def matrix_chain_mul_bruteforce(p, n) : 5 | return matrix_chain_mul_bruteforce_util(p, 1, n-1) 6 | 7 | def matrix_chain_mul_bruteforce_util(p, i, j) : # Brute force. 8 | if (i == j) : 9 | return 0 10 | 11 | min_val = sys.maxsize 12 | 13 | # Place parenthesis at different places between first and last matrix, 14 | # recursively calculate value of multiplications for each parenthesis 15 | # placement and return the minimum value. 16 | for k in range(i, j) : 17 | count = matrix_chain_mul_bruteforce_util(p, i, k) + matrix_chain_mul_bruteforce_util(p, k+1, j) + p[i-1]*p[k]*p[j] 18 | min_val = min(min_val, count) 19 | 20 | return min_val 21 | 22 | 23 | def matrix_chain_mul_TD(p, n) : 24 | dp = [[sys.maxsize] * n for _ in range(n)] 25 | return matrix_chain_mul_TDUtil(dp, p, 1, n-1) 26 | 27 | # Function for matrix chain multiplication 28 | def matrix_chain_mul_TDUtil(dp, p, i, j) : 29 | # Base Case 30 | if (i == j) : 31 | return 0 32 | 33 | if (dp[i][j] != sys.maxsize) : 34 | return dp[i][j] 35 | 36 | for k in range(i, j) : 37 | dp[i][j] = min(dp[i][j],matrix_chain_mul_TDUtil(dp, p, i, k) + matrix_chain_mul_TDUtil(dp, p, k+1, j) + p[i-1]*p[k]*p[j]) 38 | 39 | return dp[i][j] 40 | 41 | def matrix_chain_mul_BU(p, n) : 42 | dp = [[sys.maxsize] * n for _ in range(n)] 43 | 44 | for i in range(1, n) : 45 | dp[i][i] = 0 46 | 47 | for l in range(1, n) : # l is length of range. 48 | i = 1 49 | j = l + 1 50 | while j < n : 51 | for k in range(i, j) : 52 | dp[i][j] = min(dp[i][j], dp[i][k] + p[i-1]*p[k]*p[j] + dp[k+1][j]) 53 | i += 1 54 | j += 1 55 | return dp[0][n - 1] 56 | 57 | def matrix_chain_mul_BU(p, n) : 58 | dp = [[sys.maxsize] * n for _ in range(n)] 59 | pos = [[sys.maxsize] * n for _ in range(n)] 60 | 61 | for i in range(0, n) : 62 | dp[i][i] = 0 63 | pos[i][i] = i 64 | 65 | for l in range(1, n) : # l is length of range. 66 | i = 1 67 | j = l + 1 68 | while j < n : 69 | for k in range(i, j) : 70 | new_val = dp[i][k] + p[i-1]*p[k]*p[j] + dp[k+1][j] 71 | if dp[i][j] > new_val : 72 | dp[i][j] = new_val 73 | pos[i][j] = k 74 | i += 1 75 | j += 1 76 | 77 | Print_optimal_parenthesis(pos, 1, n-1) 78 | print() 79 | return dp[1][n - 1] 80 | 81 | def Print_optimal_parenthesis(pos, i, j) : 82 | if i == j : 83 | print ("M"+str(pos[i][i]), end=" ") 84 | else : 85 | print("(", end=" ") 86 | Print_optimal_parenthesis(pos, i, pos[i][j]) 87 | Print_optimal_parenthesis(pos, pos[i][j]+1, j) 88 | print (")", end=" ") 89 | 90 | 91 | # Testing Code. 92 | arr = [40, 10, 50, 20, 15] 93 | n = len(arr) 94 | print("Matrix Chain Multiplication is:", matrix_chain_mul_bruteforce(arr, n)) 95 | print("Matrix Chain Multiplication is:", matrix_chain_mul_TD(arr, n)) 96 | print("Matrix Chain Multiplication is:", matrix_chain_mul_BU(arr, n)) 97 | 98 | """ 99 | Matrix Chain Multiplication is: 19000 100 | Matrix Chain Multiplication is: 19000 101 | ( M1 ( ( M2 M3 ) M4 ) ) 102 | Matrix Chain Multiplication is: 19000 103 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/MinCostBinaryTree.py: -------------------------------------------------------------------------------- 1 | import math 2 | import sys 3 | 4 | def maxVal(mx, i, j) : 5 | if (mx[i][j] != -sys.maxsize) : 6 | return mx[i][j] 7 | 8 | for k in range(i, j) : 9 | mx[i][j] = max(mx[i][j], maxVal(mx, i, k), maxVal(mx, k + 1, j)) 10 | return mx[i][j] 11 | 12 | def min_cost_binary_tree_td_util(dp, mx, i, j, arr) : 13 | if (j <= i) : 14 | return 0 15 | 16 | if (dp[i][j] != sys.maxsize) : 17 | return dp[i][j] 18 | 19 | for k in range(i, j) : 20 | dp[i][j] = min(dp[i][j], 21 | min_cost_binary_tree_td_util(dp, mx, i, k, arr) + 22 | min_cost_binary_tree_td_util(dp, mx, k + 1, j, arr) + 23 | maxVal(mx, i, k) * maxVal(mx, k + 1, j)) 24 | return dp[i][j] 25 | 26 | def min_cost_binary_tree_td(arr) : 27 | n = len(arr) 28 | dp = [[sys.maxsize] * n for _ in range(n)] 29 | mx = [[-sys.maxsize] * n for _ in range(n)] 30 | 31 | for i in range(n) : 32 | mx[i][i] = arr[i] 33 | 34 | return min_cost_binary_tree_td_util(dp, mx, 0, n - 1, arr) 35 | 36 | def min_cost_binary_tree_bu(arr) : 37 | n = len(arr) 38 | dp = [[0] * n for _ in range(n)] 39 | mx = [[0] * n for _ in range(n)] 40 | for i in range(n) : 41 | mx[i][i] = arr[i] 42 | 43 | for l in range(1, n) : # l is length of range. 44 | i = 0 45 | j = l 46 | while j < n : 47 | dp[i][j] = sys.maxsize 48 | for k in range(i, j) : 49 | dp[i][j] = min(dp[i][j],dp[i][k] + dp[k + 1][j] + mx[i][k] * mx[k + 1][j]) 50 | mx[i][j] = max(mx[i][k],mx[k + 1][j]) 51 | i += 1 52 | j += 1 53 | return dp[0][n - 1] 54 | 55 | # Testing Code 56 | arr = [6, 2, 4] 57 | print("Total cost: ", min_cost_binary_tree_td(arr)) 58 | print("Total cost: ", min_cost_binary_tree_bu(arr)) 59 | 60 | """ 61 | Total cost: 32 62 | Total cost: 32 63 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/MinStairCost.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | def min_stair_cost(costs): 4 | n = len(costs) 5 | # base case 6 | if (n == 1) : 7 | return costs[0] 8 | 9 | dp = [0] * n 10 | dp[0] = costs[0] 11 | dp[1] = costs[1] 12 | 13 | for i in range(2, n) : 14 | dp[i] = min(dp[i - 1], dp[i - 2]) + costs[i] 15 | 16 | return min(dp[n - 2], dp[n - 1]) 17 | 18 | # Testing Code 19 | costs = [1, 5, 6, 3, 4, 7, 9, 1, 2, 11] 20 | print("Min stair cost :", min_stair_cost(costs)) 21 | 22 | """ 23 | Min stair cost : 18 24 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/OptimalBST.py: -------------------------------------------------------------------------------- 1 | import math 2 | import sys 3 | 4 | def optimal_bst_cost_util(freq, i, j) : 5 | if (i > j) : 6 | return 0 7 | if (j == i) : # one element in this subarray 8 | return freq[i] 9 | 10 | minVal = sys.maxsize 11 | 12 | for r in range(i, j+1) : 13 | minVal = min(minVal,optimal_bst_cost_util(freq, i, r - 1) + optimal_bst_cost_util(freq, r + 1, j)) 14 | 15 | return minVal + sum(freq, i, j) 16 | 17 | def optimal_bst_cost(keys, freq) : 18 | return optimal_bst_cost_util(freq, 0, len(freq) - 1) 19 | 20 | def optimal_bst_cost_td(keys, freq) : 21 | n = len(freq) 22 | cost = [[sys.maxsize] * n for _ in range(n)] 23 | 24 | for i in range(n) : 25 | cost[i][i] = freq[i] 26 | 27 | return optimal_bst_cost_td_util(freq, cost, 0, n - 1) 28 | 29 | def optimal_bst_cost_td_util(freq, cost, i, j) : 30 | if (i > j) : 31 | return 0 32 | 33 | if (cost[i][j] != sys.maxsize) : 34 | return cost[i][j] 35 | 36 | s = sum(freq, i, j) 37 | for r in range(i, j+1) : 38 | cost[i][j] = min(cost[i][j],optimal_bst_cost_td_util(freq, cost, i, r - 1) + optimal_bst_cost_td_util(freq, cost, r + 1, j) + s) 39 | 40 | return cost[i][j] 41 | 42 | def sum(freq, i, j) : 43 | s = 0 44 | for k in range(i, j+1) : 45 | s += freq[k] 46 | return s 47 | 48 | def sum_init(freq, n) : 49 | sum = [0] * n 50 | sum[0] = freq[0] 51 | 52 | for i in range(1, n) : 53 | sum[i] = sum[i - 1] + freq[i] 54 | return sum 55 | 56 | def sum_range(sum, i, j) : 57 | if (i == 0) : 58 | return sum[j] 59 | return sum[j] - sum[i - 1] 60 | 61 | def optimal_bst_cost_bu(keys, freq) : 62 | n = len(freq) 63 | cost = [[sys.maxsize] * n for _ in range(n)] 64 | 65 | for i in range(n) : 66 | cost[i][i] = freq[i] 67 | 68 | for l in range(1, n) : # l is length of range. 69 | i = 0 70 | j = l 71 | for j in range(l, n) : 72 | sm = sum(freq, i, j) 73 | for r in range(i, j+1) : 74 | cost[i][j] = min(cost[i][j],sm + 75 | (cost[i][r - 1] if (r - 1 >= i) else 0) + 76 | (cost[r + 1][j] if (r + 1 <= j) else 0)) 77 | i += 1 78 | return cost[0][n - 1] 79 | 80 | def optimal_bst_cost_bu2(keys, freq) : 81 | n = len(freq) 82 | cost = [[sys.maxsize] * n for _ in range(n)] 83 | sumArr = sum_init(freq, n) 84 | for i in range(0, n) : 85 | cost[i][i] = freq[i] 86 | 87 | sm = 0 88 | for l in range(1, n) : # l is length of range. 89 | i = 0 90 | for j in range(l, n) : 91 | sm = sum_range(sumArr, i, j) 92 | r = i 93 | for r in range(i, j+1) : 94 | cost[i][j] = min(cost[i][j],sm + 95 | (cost[i][r - 1] if (r - 1 >= i) else 0) + 96 | (cost[r + 1][j] if (r + 1 <= j) else 0)) 97 | i += 1 98 | return cost[0][n - 1] 99 | 100 | # Testing Code 101 | keys = [9, 15, 25] 102 | freq = [30, 10, 40] 103 | print("OBST cost:", optimal_bst_cost(keys, freq)) 104 | print("OBST cost:", optimal_bst_cost_td(keys, freq)) 105 | print("OBST cost:", optimal_bst_cost_bu(keys, freq)) 106 | print("OBST cost:", optimal_bst_cost_bu2(keys, freq)) 107 | 108 | """ 109 | OBST cost: 130 110 | OBST cost: 130 111 | OBST cost: 130 112 | OBST cost: 130 113 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/StairUniqueWays.py: -------------------------------------------------------------------------------- 1 | 2 | def stair_unique_ways_bu(n) : 3 | if (n <= 2) : 4 | return n 5 | 6 | first = 1 7 | second = 2 8 | temp = 0 9 | for _ in range(2, n) : 10 | temp = first + second 11 | first = second 12 | second = temp 13 | return temp 14 | 15 | def stair_unique_ways_bu2(n) : 16 | if (n < 2) : 17 | return n 18 | 19 | ways = [0] * n 20 | ways[0] = 1 21 | ways[1] = 2 22 | for i in range(2, n) : 23 | ways[i] = ways[i - 1] + ways[i - 2] 24 | 25 | return ways[n - 1] 26 | 27 | # Testing Code 28 | print("Unique way to reach top:: ", stair_unique_ways_bu(4)) 29 | print("Unique way to reach top:: ", stair_unique_ways_bu2(4)) 30 | 31 | """ 32 | Unique way to reach top:: 5 33 | Unique way to reach top:: 5 34 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/StockBuySell.py: -------------------------------------------------------------------------------- 1 | 2 | def stock_buy_sell_profit(arr) : 3 | buy_profit = -arr[0] # Buy stock profit 4 | sell_profit = 0 # Sell stock profit 5 | n = len(arr) 6 | for i in range(1, n) : 7 | new_buy_profit = (sell_profit - arr[i]) if ((sell_profit - arr[i]) > buy_profit) else buy_profit 8 | new_sell_profit = (buy_profit + arr[i]) if ((buy_profit + arr[i]) > sell_profit) else sell_profit 9 | 10 | buy_profit = new_buy_profit 11 | sell_profit = new_sell_profit 12 | 13 | return sell_profit 14 | 15 | def stock_buy_sell_profit_tc(arr, t) : 16 | buy_profit = -arr[0] 17 | sell_profit = 0 18 | n = len(arr) 19 | 20 | for i in range(1, n) : 21 | new_buy_profit = (sell_profit - arr[i]) if ((sell_profit - arr[i]) > buy_profit) else buy_profit 22 | new_sell_profit = (buy_profit + arr[i] - t) if ((buy_profit + arr[i] - t) > sell_profit) else sell_profit 23 | buy_profit = new_buy_profit 24 | sell_profit = new_sell_profit 25 | 26 | return sell_profit 27 | 28 | def stock_buy_sell_profit2(arr) : 29 | n = len(arr) 30 | dp = [[0] * (2) for _ in range(n)] 31 | dp[0][0] = -arr[0] # Buy stock profit 32 | dp[0][1] = 0 # Sell stock profit 33 | 34 | for i in range(1, n) : 35 | dp[i][0] = dp[i - 1][1] - arr[i] if (dp[i - 1][1] - arr[i] > dp[i - 1][0]) else dp[i - 1][0] 36 | dp[i][1] = dp[i - 1][0] + arr[i] if (dp[i - 1][0] + arr[i] > dp[i - 1][1]) else dp[i - 1][1] 37 | 38 | return dp[n - 1][1] 39 | 40 | def stock_buy_sell_profit_tc2(arr, t) : 41 | n = len(arr) 42 | dp = [[0] * (2) for _ in range(n)] 43 | dp[0][0] = -arr[0] 44 | dp[0][1] = 0 45 | 46 | for i in range(1, n) : 47 | dp[i][0] = (dp[i - 1][1] - arr[i]) if ((dp[i - 1][1] - arr[i]) > dp[i - 1][0]) else dp[i - 1][0] 48 | dp[i][1] = (dp[i - 1][0] + arr[i] - t) if ((dp[i - 1][0] + arr[i] - t) > dp[i - 1][1]) else dp[i - 1][1] 49 | 50 | return dp[n - 1][1] 51 | 52 | # Testing Code 53 | arr = [10, 12, 9, 23, 25, 55, 49, 70] 54 | print("Total profit: ", stock_buy_sell_profit(arr)) 55 | print("Total profit: ", stock_buy_sell_profit2(arr)) 56 | print("Total profit: ", stock_buy_sell_profit_tc(arr, 2)) 57 | print("Total profit: ", stock_buy_sell_profit_tc2(arr, 2)) 58 | 59 | """ 60 | Total profit: 69 61 | Total profit: 69 62 | Total profit: 63 63 | Total profit: 63 64 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/Vacation.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | # days are must travel days, costs are cost of tickets. 4 | def vacation_min_cost(days, costs) : 5 | n = len(days) 6 | mx = days[n - 1] 7 | dp = [0] * (mx + 1) 8 | 9 | j = 0 10 | for i in range (1, mx+1) : 11 | if (days[j] == i) : # That days is definitely travelled. 12 | j += 1 13 | dp[i] = min(dp[i-1] + costs[0], dp[max(0, i - 7)] + costs[1], dp[max(0, i - 30)] + costs[2]) 14 | else : 15 | dp[i] = dp[i-1] 16 | 17 | return dp[mx] 18 | 19 | # Testing Code 20 | days = [1, 3, 5, 7, 12, 20, 30] 21 | costs = [2, 7, 30] 22 | print("Min cost is:" , vacation_min_cost(days, costs)) 23 | 24 | """ 25 | Min cost is: 13 26 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/WildCharMatch.py: -------------------------------------------------------------------------------- 1 | def wild_char_match(exp, str) : 2 | return wild_char_match_util(exp, str, 0, 0) 3 | 4 | def wild_char_match_util(exp, str, m, n) : 5 | if (m == len(exp) and (n == len(str) or exp[m - 1] == '*')) : 6 | return True 7 | 8 | if ((m == len(exp) and n != len(str)) or (m != len(exp) and n == len(str))) : 9 | return False 10 | 11 | if (exp[m] == '?' or exp[m] == str[n]) : 12 | return wild_char_match_util(exp, str, m + 1, n + 1) 13 | 14 | if (exp[m] == '*') : 15 | return wild_char_match_util(exp, str, m + 1, n) or wild_char_match_util(exp, str, m, n + 1) 16 | 17 | return False 18 | 19 | def wild_char_match_dp(exp, str) : 20 | return wild_char_match_dp_util(exp, str, len(exp), len(str)) 21 | 22 | def wild_char_match_dp_util(exp, str, m, n) : 23 | lookup = [[False] * (n + 1) for _ in range(m + 1)] 24 | lookup[0][0] = True 25 | # empty exp and empty str match. 26 | # 0 row will remain all false. empty exp can't match any str. 27 | # '*' can match with empty string, column 0 update. 28 | for i in range(1, m+1) : 29 | if (exp[i - 1] == '*') : 30 | lookup[i][0] = lookup[i - 1][0] 31 | else : 32 | break 33 | 34 | # Fill the table in bottom-up fashion 35 | for i in range(1, m+1) : 36 | for j in range(1, n+1) : 37 | # If we see a '*' in pattern: 38 | # 1) We ignore '*' character and consider next character in the pattern. 39 | # 2) We ignore one character in the input str and consider next character. 40 | if (exp[i - 1] == '*') : 41 | lookup[i][j] = lookup[i - 1][j] or lookup[i][j - 1] 42 | elif (exp[i - 1] == '?' or str[j - 1] == exp[i - 1]) : 43 | lookup[i][j] = lookup[i - 1][j - 1] 44 | else : 45 | lookup[i][j] = False 46 | return lookup[m][n] 47 | 48 | # Testing Code 49 | print(wild_char_match("*llo,?World?", "Hello, World!")) 50 | print(wild_char_match_dp("*llo,?World?", "Hello, World!")) 51 | 52 | """ 53 | True 54 | True 55 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/catalan.py: -------------------------------------------------------------------------------- 1 | # recursive solution 2 | def catalan(n): 3 | if n < 1 : 4 | return 1 5 | 6 | catn = 0 7 | for i in range(n): 8 | catn += catalan(i) * catalan(n-i-1) 9 | return catn 10 | 11 | print (catalan(11)) 12 | 13 | # dynamic programming solution 14 | def catalan2(n): 15 | catn = [0]*(n + 1) 16 | catn[0] = 1 # Base case 17 | 18 | # recursion 19 | for i in range(1, n + 1): 20 | for j in range(i): 21 | catn[i] += catn[j] * catn[i-j-1] 22 | return catn[n] 23 | 24 | print(catalan2(11)) 25 | 26 | """ 27 | 58786 28 | 58786 29 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/DP/gen.py: -------------------------------------------------------------------------------- 1 | int TopDownFunction(int dp[], int ways[], int target ) { 2 | // Base Case 3 | if(target == 0) 4 | return 0; 5 | 6 | if (dp[target] != INVALID) { 7 | return dp[target]; 8 | } 9 | 10 | // Recursion 11 | for (int i = 0; i < ways.length; i++) { 12 | dp[target] = min(dp[target], TopDownFunction(dp, ways, target - ways[i]) + cost); 13 | } 14 | return dp[target]; 15 | } 16 | 17 | int TopDownFunction(int ways[], int target ) { 18 | int dp[target]; 19 | fill dp[] with value INVALID; 20 | return TopDownFunction(dp, ways, target); 21 | } 22 | 23 | int BottomUpFunction( int ways[], int target ) { 24 | int dp[target]; 25 | fill dp[] array with value INVALID; 26 | dp[0] = 0; // Base value. 27 | 28 | for (int i = 1; i <= target; i++) { 29 | for (int j = 0; j < ways.length; j++) { 30 | // For all fusible ways. 31 | dp[i] = min(dp[i], dp[i - ways[j]] + cost); 32 | } 33 | } 34 | 35 | return dp[target]; 36 | } 37 | 38 | 39 | int TopDownFunction(int dp[], int ways[], int target ) { 40 | // Base Case 41 | if(target == 0) 42 | return 0; 43 | 44 | if (dp[target] != 0) { 45 | return dp[target]; 46 | } 47 | 48 | // Recursion 49 | for (int i = 0; i < ways.length && ways[i] <= i; i++) { 50 | // For all fusible ways. 51 | dp[target] += TopDownFunction(dp, ways, target - ways[i]); 52 | } 53 | return dp[target]; 54 | } 55 | 56 | int TopDownFunction(int ways[], int target ) { 57 | int dp[target]; 58 | return TopDownFunction(dp, ways, target); 59 | } 60 | 61 | 62 | int BottomUpFunction( int ways[], int target ) { 63 | int dp[target]; 64 | 65 | for (int i = 1; i <= target; i++) { 66 | for (int j = 0; j < ways.length && ways[i] <= i ; j++) { 67 | // For all fusible ways. 68 | dp[i] += dp[i - ways[j]]; 69 | } 70 | } 71 | return dp[target]; 72 | } 73 | 74 | int TopDownFunction(int costs[]) { 75 | int n = costs.length; 76 | int dp[n][n]; 77 | for (int[] row : dp) 78 | fill row[] array with value INVALID; 79 | 80 | return TopDownFunction(dp, costs, 0, n-1); 81 | } 82 | 83 | int TopDownFunction(int dp[][], int costs[], int i, int j ) { 84 | // Base Case 85 | if(i == j) 86 | return 0; 87 | 88 | if (dp[i][j] != INVALID) { 89 | return dp[i][j]; 90 | } 91 | 92 | // Recursion 93 | for (int k = i; k < j; k++) { 94 | dp[i][j] = Min (dp[i][j], TopDownFunction(dp, costs, i, k) + costs[k] + TopDownFunction(dp, costs, k+1, j)); 95 | } 96 | return dp[i][j]; 97 | } 98 | 99 | int BottomUpFunction(int costs[]) { 100 | int n = costs.length; 101 | int dp[n][n]; 102 | for (int row : dp) 103 | fill array row[] with value INVALID; 104 | 105 | for(int l = 1; l 0) : 20 | if (capacity - items[i].wt >= 0) : 21 | capacity -= items[i].wt 22 | profit += items[i].cost 23 | i += 1 24 | 25 | return profit 26 | 27 | # Testing Code 28 | wt = [10, 40, 20, 30] 29 | cost = [60, 40, 90, 120] 30 | capacity = 50 31 | maxCost = knapsack_max_cost_greedy(wt, cost, capacity) 32 | print("Maximum cost obtained = ", maxCost) 33 | 34 | """ 35 | Maximum cost obtained = 150 36 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/Greedy/ActivitySelection.py: -------------------------------------------------------------------------------- 1 | class Activity : 2 | def __init__(self, s, f) : 3 | self.start = s 4 | self.stop = f 5 | 6 | def maxActivities(s, f) : 7 | n = len(s) 8 | act = [None] * n 9 | 10 | for i in range(n) : 11 | act[i] = Activity(s[i], f[i]) 12 | 13 | act.sort(key = lambda k : k.stop) # sort according to finish time. 14 | i = 0 # The first activity at index 0 is always gets selected. 15 | print("Activities are : (" + str(act[i].start) + "," + str(act[i].stop) + ")", end ="") 16 | 17 | for j in range(n) : 18 | # Find next activity whose start time is greater than or equal 19 | # to the finish time of previous activity. 20 | if (act[j].start >= act[i].stop) : 21 | print(", (" + str(act[j].start) + "," + str(act[j].stop) + ")", end ="") 22 | i = j 23 | 24 | # Testing Code 25 | s = [1, 5, 0, 3, 5, 6, 8] 26 | f = [2, 6, 5, 4, 9, 7, 9] 27 | maxActivities(s, f) 28 | 29 | """ 30 | Activities are : (1,2), (3,4), (5,6), (6,7), (8,9) 31 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/Greedy/ChotaBhim.py: -------------------------------------------------------------------------------- 1 | import heapq 2 | import math 3 | 4 | def chota_bhim_max_drink(cups, attempts) : 5 | size = len(cups) 6 | cups.sort(key = lambda a : -a) # sort decreasing order. 7 | total = 0 8 | for _ in range(attempts): 9 | total += cups[0] 10 | cups[0] = cups[0] // 2 11 | index = 0 12 | temp = cups[0] 13 | while (index < size - 1 and temp < cups[index + 1]) : 14 | cups[index] = cups[index + 1] 15 | index += 1 16 | cups[index] = temp 17 | 18 | print("Total : ", total) 19 | return total 20 | 21 | def max_heap_push(hp, value): 22 | heapq.heappush(hp, -1 * value) 23 | 24 | def max_heap_pop(hp): 25 | return -1 * heapq.heappop(hp) 26 | 27 | def chota_bhim_max_drink2(cups, attempts) : 28 | size = len(cups) 29 | hp = [] 30 | for i in range(size) : 31 | max_heap_push(hp, cups[i]) 32 | 33 | total = 0 34 | for _ in range(attempts): 35 | value = max_heap_pop(hp) 36 | total += value 37 | value = value // 2 38 | max_heap_push(hp, value) 39 | print("Total : ", total) 40 | return total 41 | 42 | # Testing Code 43 | cups = [20, 10, 70, 40, 20] 44 | chota_bhim_max_drink(cups, 5) 45 | cups2 = [20, 10, 70, 40, 20] 46 | chota_bhim_max_drink2(cups2, 5) 47 | 48 | """ 49 | Total : 185 50 | Total : 185 51 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/Greedy/FractionalKnapsack.py: -------------------------------------------------------------------------------- 1 | 2 | class Items: 3 | def __init__(self, w, c) : 4 | self.wt = w 5 | self.cost = c 6 | self.density = c // w 7 | 8 | def max_cost_fractional_knapsack(wt, cost, capacity) : 9 | n = len(wt) 10 | itemList = [None] * n 11 | for i in range(n) : 12 | itemList[i] = Items(wt[i], cost[i]) 13 | 14 | itemList.sort(key = lambda k : - k.density) # Sort decreasing. 15 | totalCost = 0 16 | for i in range(n) : 17 | if (capacity - itemList[i].wt >= 0) : 18 | capacity -= itemList[i].wt 19 | totalCost += itemList[i].cost 20 | else : 21 | totalCost += (itemList[i].density * capacity) 22 | break 23 | 24 | return totalCost 25 | 26 | # Testing Code 27 | wt = [10, 40, 20, 30] 28 | cost = [60, 40, 90, 120] 29 | capacity = 50 30 | maxCost = max_cost_fractional_knapsack(wt, cost, capacity) 31 | print("Maximum cost obtained = ", maxCost) 32 | 33 | """ 34 | Maximum cost obtained = 230 35 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/Greedy/HuffmanTree.py: -------------------------------------------------------------------------------- 1 | import heapq 2 | 3 | class HuffmanTree : 4 | class Node : 5 | def __init__(self, ch, fr, l, r) : 6 | self.c = ch 7 | self.freq = fr 8 | self.left = l 9 | self.right = r 10 | 11 | def __lt__(self, other): 12 | return (self.freq < other.freq) 13 | 14 | def __init__(self, arr, freq) : 15 | n = len(arr) 16 | hp = [] 17 | 18 | for i in range(n) : 19 | heapq.heappush(hp, self.Node(arr[i], freq[i], None, None)) 20 | 21 | while (len(hp) > 1) : 22 | lt = heapq.heappop(hp) 23 | rt = heapq.heappop(hp) 24 | heapq.heappush(hp, self.Node('+', lt.freq + rt.freq, lt, rt)) 25 | 26 | self.root = hp[0] 27 | 28 | def printUtil(self, root, s) : 29 | if (root.left == None and root.right == None and root.c != '+') : 30 | print(root.c, "=", s) 31 | return 32 | self.printUtil(root.left, s + "0") 33 | self.printUtil(root.right, s + "1") 34 | 35 | def print(self) : 36 | print("Char = Huffman code") 37 | self.printUtil(self.root, "") 38 | 39 | # Testing Code 40 | ar = ['A', 'B', 'C', 'D', 'E'] 41 | fr = [30, 25, 21, 14, 10] 42 | hf = HuffmanTree(ar, fr) 43 | hf.print() 44 | 45 | """ 46 | Char = Huffman code 47 | C = 00 48 | E = 010 49 | D = 011 50 | B = 10 51 | A = 11 52 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/Greedy/JobSequencing.py: -------------------------------------------------------------------------------- 1 | class Job : 2 | def __init__(self, id, deadline, profit) : 3 | self.id = id 4 | self.deadline = deadline 5 | self.profit = profit 6 | 7 | def job_sequencing(ids, deadlines, profits, n) : 8 | maxDL = deadlines[0] 9 | for i in range(n) : 10 | if (deadlines[i] > maxDL) : 11 | maxDL = deadlines[i] 12 | 13 | jobs = [None] * n 14 | for i in range(n) : 15 | jobs[i] = Job(ids[i], deadlines[i], profits[i]) 16 | jobs.sort(key = lambda j : -j.profit) # decreasing profit. 17 | 18 | job = [-1] * maxDL # job id -1 indicate no job selected for this slot. 19 | profit = 0 20 | 21 | for i in range(n) : # Iterate through all given jobs 22 | for j in range(jobs[i].deadline - 1, -1, -1) : 23 | if (job[j] == -1) : 24 | job[j] = jobs[i].id # Slot booked 25 | profit += jobs[i].profit 26 | break 27 | 28 | print("Profit is ::", profit) 29 | print("Jobs selected are::", end =" ") 30 | for i in range(maxDL) : 31 | if (job[i] != -1) : 32 | print(job[i], end =" ") 33 | 34 | # Testing Code 35 | id = ['a', 'b', 'c', 'd', 'e', 'f'] 36 | deadline = [3, 1, 2, 4, 4, 1] 37 | profit = [50, 40, 27, 31, 30, 60] 38 | js = job_sequencing(id, deadline, profit, 6) 39 | 40 | """ 41 | Profit is :: 171 42 | Jobs selected are:: f e a d 43 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/Greedy/JoinRopes.py: -------------------------------------------------------------------------------- 1 | import heapq 2 | 3 | def join_ropes(ropes, size) : 4 | ropes.sort(key = lambda x: -x) 5 | total = 0 6 | while (size > 1) : 7 | value = ropes[size - 1] + ropes[size - 2] 8 | total += value 9 | index = size - 2 10 | while (index > 0 and ropes[index - 1] < value) : 11 | ropes[index] = ropes[index - 1] 12 | index -= 1 13 | ropes[index] = value 14 | size -= 1 15 | print("Total : ", total) 16 | return total 17 | 18 | def join_ropes2(ropes, size) : 19 | hp = [] 20 | for i in range(size) : 21 | heapq.heappush(hp, ropes[i]) 22 | 23 | total = 0 24 | while (len(hp) > 1) : 25 | value = heapq.heappop(hp) 26 | value += heapq.heappop(hp) 27 | heapq.heappush(hp, value) 28 | total += value 29 | print("Total : ", total) 30 | return total 31 | 32 | # Testing Code 33 | ropes = [4, 3, 2, 6] 34 | join_ropes(ropes, len(ropes)) 35 | rope2 = [4, 3, 2, 6] 36 | join_ropes2(rope2, len(rope2)) 37 | 38 | """ 39 | Total : 29 40 | Total : 29 41 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/Greedy/MultipleStageGraph.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | 4 | INF = 99999 5 | 6 | # Returns shortest distance from 0 to N-1. 7 | def graph_shortest_dist(graph, n) : 8 | # dist[i] is going to store shortest 9 | # distance from node i to node n-1. 10 | dist = [INF] * n 11 | path = [0] * n 12 | dist[0] = 0 13 | path[0] = -1 14 | 15 | # Calculating shortest path for the nodes 16 | for i in range(n) : # Check all nodes of next 17 | for j in range(i, n) : 18 | if (graph[i][j] == INF) : # Reject if no edge exists 19 | j += 1 20 | continue 21 | value = graph[i][j] + dist[i] 22 | if (dist[j] > value) : 23 | dist[j] = value 24 | path[j] = i 25 | 26 | value = n - 1 27 | print("Path:", end =" ") 28 | while (value != -1) : 29 | print(str(value), end =" ") 30 | value = path[value] 31 | print() 32 | return dist[n - 1] 33 | 34 | # Testing Code 35 | # Graph stored in the form of an adjacency Matrix 36 | graph = [[INF, 1, 2, 5, INF, INF, INF, INF], 37 | [INF, INF, INF, INF, 4, 11, INF, INF], 38 | [INF, INF, INF, INF, 9, 5, 16, INF], 39 | [INF, INF, INF, INF, INF, INF, 2, INF], 40 | [INF, INF, INF, INF, INF, INF, INF, 18], 41 | [INF, INF, INF, INF, INF, INF, INF, 13], 42 | [INF, INF, INF, INF, INF, INF, INF, 2], 43 | [INF, INF, INF, INF, INF, INF, INF, INF]] 44 | print("Shortest Distance:", graph_shortest_dist(graph, 8)) 45 | 46 | """ 47 | Path: 7 6 3 0 48 | Shortest Distance: 9 49 | """ -------------------------------------------------------------------------------- /AlgorithmsChapters/Greedy/OptimalMergePattern.py: -------------------------------------------------------------------------------- 1 | import heapq 2 | 3 | def optimal_merge_pattern(arr, size) : 4 | hp = [] 5 | for i in range(size) : 6 | heapq.heappush(hp, arr[i]) 7 | 8 | total = 0 9 | while (len(hp) > 1) : 10 | value = heapq.heappop(hp) 11 | value += heapq.heappop(hp) 12 | heapq.heappush(hp, value) 13 | total += value 14 | return total 15 | 16 | # Testing Code 17 | arr = [4, 3, 2, 6] 18 | print("Total :", optimal_merge_pattern(arr, len(arr))) 19 | 20 | """ 21 | Total : 29 22 | """ -------------------------------------------------------------------------------- /Collections/Basics/Bulb.py: -------------------------------------------------------------------------------- 1 | class Bulb(object): 2 | def __init__(self): # Constructor 3 | self.isOn = False # Instance Variable 4 | 5 | def turnOn(self): # Instance Method 6 | self.isOn = True 7 | 8 | def turnOff(self): # Instance Method 9 | self.isOn = False 10 | 11 | def isOnFun(self): # Instance Method 12 | return self.isOn 13 | 14 | 15 | b = Bulb() 16 | print(("bulb is on return : " , b.isOnFun())) 17 | b.turnOn() 18 | print(("bulb is on return : " , b.isOnFun())) 19 | 20 | c = Bulb() 21 | print(("bulb c is on return : " , c.isOnFun())) 22 | 23 | -------------------------------------------------------------------------------- /Collections/Basics/Bulb2.py: -------------------------------------------------------------------------------- 1 | class Bulb(object): 2 | 3 | # Class Variables 4 | TotalBulbCount = 0 5 | 6 | # Constructor 7 | def __init__(self): 8 | Bulb.TotalBulbCount += 1 9 | self.isOn = False # Instance Variable 10 | 11 | # Class Method 12 | @classmethod 13 | def getBulbCount(cls): 14 | return Bulb.TotalBulbCount 15 | 16 | # Instance Method 17 | def turnOn(self): 18 | self.isOn = True 19 | 20 | # Instance Method 21 | def turnOff(self): 22 | self.isOn = False 23 | 24 | # Instance Method 25 | def isOnFun(self): 26 | return self.isOn 27 | 28 | 29 | b = Bulb() 30 | print(("bulb is on return : " , b.isOnFun())) 31 | b.turnOn() 32 | print(("bulb is on return : " , b.isOnFun())) 33 | print((Bulb.getBulbCount())) 34 | -------------------------------------------------------------------------------- /Collections/Basics/Bulb3.py: -------------------------------------------------------------------------------- 1 | class Bulb(object): 2 | TotalBulbCount = 0 # Class Variables 3 | 4 | def __init__(self): # Constructor 5 | Bulb.TotalBulbCount += 1 6 | self.isOn = False # Instance Variables 7 | 8 | @classmethod 9 | def getBulbCount(cls): 10 | return cls.TotalBulbCount 11 | 12 | def turnOn(self): # Instance Method 13 | self.isOn = True 14 | 15 | def turnOff(self): # Instance Method 16 | self.isOn = False 17 | 18 | def isOnFun(self): # Instance Method 19 | return self.isOn 20 | 21 | 22 | class AdvanceBulb(Bulb): 23 | def __init__(self): # Constructor 24 | self.intensity = 0 # Instance Variables 25 | Bulb.__init__(self) 26 | 27 | def setIntersity(self, i): # Instance Method 28 | self.intensity = i 29 | 30 | def getIntersity(self, i): # Instance Method 31 | return self.intensity 32 | 33 | 34 | 35 | # b = Bulb() 36 | c = AdvanceBulb() 37 | print((Bulb.getBulbCount())) 38 | print((c.isOnFun())) 39 | -------------------------------------------------------------------------------- /Collections/Basics/BulbEnum.py: -------------------------------------------------------------------------------- 1 | class Bulb(object): 2 | class BulbSize: 3 | SMALL = 'SMALL' 4 | MEDIUM = 'MEDIUM' 5 | LARGE = 'LARGE' 6 | 7 | # Constructor 8 | def __init__(self): 9 | self.isOn = False # Instance Variables 10 | self.size = Bulb.BulbSize.MEDIUM 11 | 12 | # Instance Method 13 | def turnOn(self): 14 | self.isOn = True 15 | 16 | # Instance Method 17 | def turnOff(self): 18 | self.isOn = False 19 | 20 | # Instance Method 21 | def isOnFun(self): 22 | return self.isOn 23 | 24 | def getBulbSize(self): 25 | return self.size 26 | 27 | def setBulbSize(self, value): 28 | self.size = value 29 | 30 | 31 | b = Bulb() 32 | print(("Bulb Size : " + b.getBulbSize())) 33 | -------------------------------------------------------------------------------- /Collections/Basics/BulbInterface.py: -------------------------------------------------------------------------------- 1 | from abc import ABCMeta 2 | from abc import abstractmethod 3 | 4 | class BulbInterface(object, metaclass=ABCMeta): 5 | @abstractmethod 6 | def turnOn(self): 7 | pass 8 | 9 | @abstractmethod 10 | def turnOff(self): 11 | pass 12 | 13 | @abstractmethod 14 | def isOnFun(self): 15 | pass 16 | 17 | # implements BulbInterface 18 | class Bulb(BulbInterface): 19 | class BulbSize: 20 | SMALL = 'SMALL' 21 | MEDIUM = 'MEDIUM' 22 | LARGE = 'LARGE' 23 | 24 | # Class Variables 25 | TotalBulbCount = 0 26 | 27 | # Constructor 28 | def __init__(self): 29 | Bulb.TotalBulbCount += 1 30 | self.isOn = False # Instance Variables 31 | self.size = Bulb.BulbSize.MEDIUM 32 | 33 | # Class Method 34 | @classmethod 35 | def getBulbCount(cls): 36 | return cls.TotalBulbCount 37 | 38 | # Instance Method 39 | def turnOn(self): 40 | self.isOn = True 41 | 42 | # Instance Method 43 | def turnOff(self): 44 | self.isOn = False 45 | 46 | # Instance Method 47 | def isOnFun(self): 48 | return self.isOn 49 | 50 | def getBulbSize(self): 51 | return self.size 52 | 53 | class AdvanceBulb(Bulb): 54 | # Constructor 55 | def __init__(self): 56 | self.intensity = 0 # Instance Variables 57 | Bulb.__init__(self) 58 | 59 | # Instance Method 60 | def setIntersity(self, i): 61 | self.intensity = i 62 | 63 | # Instance Method 64 | def getIntersity(self, i): 65 | return self.intensity 66 | 67 | 68 | b = Bulb() 69 | print(("Bulb Size : " + b.getBulbSize())) 70 | print(("bulb is on return : " , b.isOnFun())) 71 | b.turnOn() 72 | print(("bulb is on return : " , b.isOnFun())) 73 | 74 | -------------------------------------------------------------------------------- /Collections/Basics/Calculator.py: -------------------------------------------------------------------------------- 1 | class Calculator(object): 2 | def __init__(self, value=0): 3 | self.value = value 4 | 5 | def reset(self): 6 | self.value = 0 7 | 8 | def getValue(self): 9 | return self.value 10 | 11 | def add(self, data): 12 | self.value = self.value + data 13 | 14 | def increment(self): 15 | self.value += 1 16 | 17 | def subtract(self, data): 18 | self.value = self.value - data 19 | 20 | def decrement(self): 21 | self.value -= 1 22 | -------------------------------------------------------------------------------- /Collections/Basics/Circle.py: -------------------------------------------------------------------------------- 1 | from Shape import Shape 2 | import math 3 | class Circle(Shape): 4 | def __init__(self, r=1): 5 | self.radius = r 6 | 7 | def setRadius(self, r): 8 | self.radius = r 9 | 10 | def area(self): 11 | return math.pi * math.pow(self.radius, 2) 12 | 13 | def perimeter(self): 14 | return 2 * math.pi * self.radius 15 | -------------------------------------------------------------------------------- /Collections/Basics/HelloWorld.py: -------------------------------------------------------------------------------- 1 | print("Hello, World!") -------------------------------------------------------------------------------- /Collections/Basics/Incriment.py: -------------------------------------------------------------------------------- 1 | def increment1(var): 2 | var += 1 3 | 4 | def main1(): 5 | var = 1 6 | print(("Value before increment :" , var)) 7 | increment1(var) 8 | print(("Value after increment :" , var)) 9 | 10 | class MyInt(object): 11 | def __init__(self): 12 | self.value = 1 13 | 14 | def increment2(value): 15 | value.value += 1 16 | 17 | def main2(): 18 | var = MyInt() 19 | print(("Value before increment :" , var.value)) 20 | increment2(var) 21 | print(("Value after increment :" , var.value)) 22 | 23 | main1() 24 | main2() -------------------------------------------------------------------------------- /Collections/Basics/LinkedList.py: -------------------------------------------------------------------------------- 1 | class LinkedList(object): 2 | class Node(object): 3 | def __init__(self, v, n=None): 4 | self.value = v 5 | self.next = n 6 | 7 | 8 | def __init__(self): 9 | self.head = None 10 | -------------------------------------------------------------------------------- /Collections/Basics/Loops.py: -------------------------------------------------------------------------------- 1 | text = "Hello, World!" 2 | PI = 3.141592653589793 3 | 4 | def main1(): 5 | numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 6 | totalsum = 0 7 | for n in numbers: 8 | totalsum += n 9 | print("Sum is :: " , totalsum) 10 | 11 | def main2(): 12 | numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 13 | totalsum = 0 14 | i = 0 15 | while i < len(numbers): 16 | totalsum += numbers[i] 17 | i += 1 18 | print("Sum is :: " , totalsum) 19 | 20 | def main3(): 21 | numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 22 | totalsum = 0 23 | i = 0 24 | while True: 25 | totalsum += numbers[i] 26 | i += 1 27 | if i >= len(numbers): 28 | break 29 | print("Sum is :: " , totalsum) 30 | 31 | 32 | main1() 33 | main2() 34 | main3() 35 | 36 | """ 37 | Sum is :: 55 38 | Sum is :: 55 39 | Sum is :: 55 40 | """ -------------------------------------------------------------------------------- /Collections/Basics/MinMaxValue.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | maxInt = sys.maxsize 4 | maxUCode = sys.maxunicode 5 | floatmax = sys.float_info.max 6 | floatmin = sys.float_info.min 7 | infi = float("inf") 8 | print(infi) 9 | print((maxInt , maxUCode)) 10 | print(floatmax) 11 | print(floatmin) 12 | 13 | 14 | -------------------------------------------------------------------------------- /Collections/Basics/ModuleTest.py: -------------------------------------------------------------------------------- 1 | def demo_function(a = 1): 2 | print(a) 3 | 4 | -------------------------------------------------------------------------------- /Collections/Basics/ModuleUse.py: -------------------------------------------------------------------------------- 1 | import ModuleTest as mt 2 | 3 | mt.demo_function(10) 4 | 5 | import sys 6 | sys.path.append('/home/hemant/Documents/Github/Problem-Solving-in-Data-Structures-Algorithms-using-Python/Collections/') 7 | import ModuleTest2 as mt2 8 | 9 | mt2.function2() -------------------------------------------------------------------------------- /Collections/Basics/OuterClass.py: -------------------------------------------------------------------------------- 1 | class OuterClass(object): 2 | """ Documentation of OuterClass """ 3 | class NestedClass(object): 4 | """ Documentation of NestedClass """ 5 | # NestedClass fields and methods. 6 | 7 | # OuterClass fields and methods. 8 | -------------------------------------------------------------------------------- /Collections/Basics/Rectangle.py: -------------------------------------------------------------------------------- 1 | from Shape import Shape 2 | class Rectangle(Shape): 3 | def __init__(self, w=1, l=1): 4 | self.width = w 5 | self.length = l 6 | 7 | def setWidth(self, w): 8 | self.width = w 9 | 10 | def setLength(self, l): 11 | self.length = l 12 | 13 | def area(self): 14 | return self.width * self.length # Area = width * length 15 | 16 | def perimeter(self): 17 | return 2 * (self.width + self.length) # Perimeter = 2(width + length) 18 | 19 | -------------------------------------------------------------------------------- /Collections/Basics/Shape.py: -------------------------------------------------------------------------------- 1 | from abc import ABCMeta 2 | from abc import abstractmethod 3 | 4 | # Abstract Class 5 | class Shape(object, metaclass=ABCMeta): 6 | @abstractmethod 7 | def area(self): 8 | pass 9 | 10 | @abstractmethod 11 | def perimeter(self): 12 | pass 13 | -------------------------------------------------------------------------------- /Collections/Basics/ShapeDemo.py: -------------------------------------------------------------------------------- 1 | from Circle import Circle 2 | from Rectangle import Rectangle 3 | 4 | width = 2 5 | length = 3 6 | rectangle = Rectangle(width, length) 7 | print(("Rectangle width:" , width , "and length:" , length , "Area:" , rectangle.area() , "Perimeter:" , rectangle.perimeter())) 8 | 9 | radius = 10 10 | circle = Circle(radius) 11 | print(("Circle radius:" , radius, "Area:" , circle.area(), "Perimeter:" , circle.perimeter())) 12 | 13 | -------------------------------------------------------------------------------- /Collections/Basics/Tree.py: -------------------------------------------------------------------------------- 1 | class Tree(object): 2 | class Node(object): 3 | def __init__(self, v, l=None, r=None): 4 | self.value = v 5 | self.lChild = l 6 | self.rChild = r 7 | # Nested Class Node other fields and methods. 8 | 9 | def __init__(self): 10 | self.root = None 11 | # Outer Class Tree other fields and methods. 12 | -------------------------------------------------------------------------------- /Collections/Basics/__pycache__/Circle.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hemant-Jain-Author/Problem-Solving-in-Data-Structures-Algorithms-using-Python/2db1ceb8c9502942692dbf94853119d2ba3c1e11/Collections/Basics/__pycache__/Circle.cpython-36.pyc -------------------------------------------------------------------------------- /Collections/Basics/__pycache__/ModuleTest.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hemant-Jain-Author/Problem-Solving-in-Data-Structures-Algorithms-using-Python/2db1ceb8c9502942692dbf94853119d2ba3c1e11/Collections/Basics/__pycache__/ModuleTest.cpython-38.pyc -------------------------------------------------------------------------------- /Collections/Basics/__pycache__/Rectangle.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hemant-Jain-Author/Problem-Solving-in-Data-Structures-Algorithms-using-Python/2db1ceb8c9502942692dbf94853119d2ba3c1e11/Collections/Basics/__pycache__/Rectangle.cpython-36.pyc -------------------------------------------------------------------------------- /Collections/Basics/__pycache__/Shape.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hemant-Jain-Author/Problem-Solving-in-Data-Structures-Algorithms-using-Python/2db1ceb8c9502942692dbf94853119d2ba3c1e11/Collections/Basics/__pycache__/Shape.cpython-36.pyc -------------------------------------------------------------------------------- /Collections/Basics/minmaxlimit.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | maxInt = sys.maxsize 4 | minInt = -sys.maxsize 5 | 6 | longstart = maxInt + 1 7 | floatvalue = 0.1 8 | str = "hello, world!" 9 | 10 | print(("type of maxint" , type(maxInt) , "value : " , maxInt)) 11 | print(("type of minInt" , type(minInt) , "value : " , minInt)) 12 | print(("type of longstart" , type(longstart) , "value : " , longstart)) 13 | print(("type of floatvalue" , type(floatvalue) , "value : " , floatvalue)) 14 | print(("type of str" , type(str) , "value : " , str)) 15 | 16 | 17 | """ 18 | ('type of maxint', , 'value : ', 9223372036854775807) 19 | ('type of minInt', , 'value : ', -9223372036854775808) 20 | ('type of longstart', , 'value : ', 9223372036854775808) 21 | ('type of floatvalue', , 'value : ', 0.1) 22 | ('type of str', , 'value : ', 'hello, world!') 23 | """ 24 | 25 | 26 | -------------------------------------------------------------------------------- /Collections/Basics/type.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | value1 = sys.maxsize 4 | value2 = value1 + 1 5 | value3 = 13.05 6 | value4 = 3.14j 7 | value5 = "hello, world!" 8 | print((type(value1),value2, type(value2), type(value3), type(value4),type(value5), value5)) 9 | 10 | # Parameter Passing 11 | def Change1(B): 12 | B = 2 13 | 14 | A = 1 15 | Change1(A) 16 | print(A) 17 | 18 | # Parameter Passing 2 19 | def Change2(B): 20 | B.append(2) 21 | 22 | A = [1] 23 | Change2(A) 24 | print(A) -------------------------------------------------------------------------------- /Collections/Counter.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | seq = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4] 4 | ctr = Counter(seq) 5 | print(ctr) 6 | print(ctr.get(3)) 7 | print(4 in ctr) 8 | ctr.pop(4) 9 | print(ctr) 10 | print(4 in ctr) 11 | ctr[5] += 1 12 | ctr[3] -= 1 13 | print(ctr) 14 | 15 | """ 16 | Counter({4: 4, 3: 3, 2: 2, 1: 1}) 17 | 3 18 | True 19 | Counter({3: 3, 2: 2, 1: 1}) 20 | False 21 | Counter({2: 2, 3: 2, 1: 1, 5: 1}) 22 | """ 23 | -------------------------------------------------------------------------------- /Collections/Dictionary.py: -------------------------------------------------------------------------------- 1 | a = {} 2 | a["mango"] = 20 3 | a["apple"] = 40 4 | a["banana"] = 10 5 | 6 | print(a) 7 | print(a["mango"]) 8 | print(a.get("mango")) 9 | print("apple" in a) 10 | 11 | """ 12 | {'mango': 20, 'apple': 40, 'banana': 10} 13 | 20 14 | 20 15 | True 16 | """ 17 | 18 | a = dict() 19 | a["mango"] = 20 20 | a["apple"] = 40 21 | a["banana"] = 10 22 | 23 | print(a) 24 | print(a["mango"]) 25 | print(a.get("mango")) 26 | print("apple" in a) 27 | 28 | """ 29 | {'mango': 20, 'apple': 40, 'banana': 10} 30 | 20 31 | 20 32 | True 33 | """ 34 | 35 | # from 3.7 dict will also keep the elements in order. 36 | # effectively dict and ordereddict are same. 37 | from collections import OrderedDict 38 | 39 | b = OrderedDict() 40 | b["apple"] = 40 41 | b["mango"] = 20 42 | b["banana"] = 10 43 | 44 | print(b) 45 | print(b["mango"]) 46 | print(b.get("mango")) 47 | print("banana" in b) 48 | 49 | """ 50 | OrderedDict([('apple', 40), ('mango', 20), ('banana', 10)]) 51 | 20 52 | 20 53 | True 54 | """ -------------------------------------------------------------------------------- /Collections/Heap.py: -------------------------------------------------------------------------------- 1 | import heapq 2 | 3 | hp = [6,2,3] # creates heap from list. 4 | heapq.heapify(hp) 5 | print(hp) 6 | 7 | heapq.heappush(hp, 1) # pushes a new item on the heap 8 | heapq.heappush(hp, 5) 9 | print(hp) 10 | 11 | print("Length:", len(hp)) 12 | print("Top:", hp[0]) # peek the smallest element of the heap. 13 | print("Pop:", heapq.heappop(hp)) # pops the smallest item from the heap 14 | print(hp) 15 | 16 | """ 17 | [2, 6, 3] 18 | [1, 2, 3, 6, 5] 19 | Length: 5 20 | Top: 1 21 | Pop: 1 22 | [2, 5, 3, 6] 23 | """ -------------------------------------------------------------------------------- /Collections/List.py: -------------------------------------------------------------------------------- 1 | def main1(): 2 | numbers = [0] * 100 3 | numbers[1] = 2 4 | print(numbers[1]) 5 | 6 | 7 | def main2() : 8 | al = [] 9 | al.append(1) # add 1 to the end of the list 10 | al.append(2) # add 2 to the end of the list 11 | print("Contents of List :", al) 12 | print("List Size :", len(al)) 13 | print("List IsEmpty :", (len(al) == 0)) 14 | del al[- 1] # last element of list is removed. 15 | al = [] # all the elements of list are removed. 16 | print("List IsEmpty :", (len(al) == 0)) 17 | 18 | 19 | lst = [1, 2, 3] 20 | print(lst) 21 | 22 | lst.append(4) 23 | print(lst) 24 | 25 | print(len(lst)) 26 | 27 | lst.remove(4) 28 | print(lst) 29 | 30 | print(lst.pop()) 31 | print(lst.pop()) 32 | print(lst) 33 | 34 | lst.sort() 35 | print(lst) 36 | lst.reverse() 37 | print(lst) 38 | 39 | """ 40 | [1, 2, 3] 41 | [1, 2, 3, 4] 42 | 4 43 | 44 | [1, 2, 3] 45 | 3 46 | 2 47 | [1] 48 | [1] 49 | [1] 50 | """ -------------------------------------------------------------------------------- /Collections/ModuleTest2.py: -------------------------------------------------------------------------------- 1 | def function2(): 2 | print("hello, world!") -------------------------------------------------------------------------------- /Collections/Queue.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | 3 | que = deque([]) 4 | que.append(1) 5 | que.append(2) 6 | que.append(3) 7 | print("Queue : ", que) 8 | print("Queue size : ", len(que)) 9 | print("Queue peek : ", que[0]) 10 | print("Queue remove : ", que.popleft()) 11 | print("Queue : ", que) 12 | print("Queue isEmpty : ", (len(que) == 0)) 13 | 14 | 15 | """ 16 | Queue : deque([1, 2, 3]) 17 | Queue size : 3 18 | Queue peek : 1 19 | Queue remove : 1 20 | Queue : deque([2, 3]) 21 | Queue isEmpty : False 22 | """ -------------------------------------------------------------------------------- /Collections/Set.py: -------------------------------------------------------------------------------- 1 | 2 | hs = set() # Create a set. 3 | 4 | # Add elements to the set. 5 | hs.add("Banana") 6 | hs.add("Apple") 7 | hs.add("Mango") 8 | 9 | print(hs) 10 | print("Apple present : ", "Apple" in hs) 11 | print("Grapes present : ", "Grapes" in hs) 12 | 13 | hs.remove("Apple") 14 | print("Apple present : ", "Apple" in hs) 15 | print(hs) 16 | 17 | 18 | """ 19 | {'Apple', 'Banana', 'Mango'} 20 | Apple present : True 21 | Grapes present : False 22 | Apple present : False 23 | {'Banana', 'Mango'} 24 | """ -------------------------------------------------------------------------------- /Collections/Stack.py: -------------------------------------------------------------------------------- 1 | stk = [] 2 | stk.append(1) 3 | stk.append(2) 4 | stk.append(3) 5 | 6 | print("Stack :", stk) 7 | print("Stack size :", len(stk)) 8 | print("Stack top :", stk[-1]) 9 | print("Stack pop :", stk.pop()) 10 | print("Stack :", stk) 11 | print("Stack isEmpty :", (len(stk) == 0)) 12 | 13 | 14 | 15 | """ 16 | Stack : [1, 2, 3] 17 | Stack size : 3 18 | Stack top : 3 19 | Stack pop : 3 20 | Stack : [1, 2] 21 | Stack isEmpty : False 22 | """ -------------------------------------------------------------------------------- /Collections/__pycache__/ModuleTest2.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hemant-Jain-Author/Problem-Solving-in-Data-Structures-Algorithms-using-Python/2db1ceb8c9502942692dbf94853119d2ba3c1e11/Collections/__pycache__/ModuleTest2.cpython-38.pyc -------------------------------------------------------------------------------- /Graph/GraphAdjMatrix.py: -------------------------------------------------------------------------------- 1 | import heapq 2 | import sys 3 | from collections import deque 4 | 5 | class Graph(object): 6 | def __init__(self, cnt): 7 | self.count = cnt 8 | self.adj = [[0 for _ in range(cnt)] for _ in range(cnt)] 9 | 10 | def add_directed_edge(self, source, destination, cost=1): 11 | self.adj[source][destination] = cost 12 | 13 | def add_undirected_edge(self, source, destination, cost=1): 14 | self.add_directed_edge(source, destination, cost) 15 | self.add_directed_edge(destination, source, cost) 16 | 17 | def print(self): 18 | for i in range(self.count): 19 | print(f"Vertex {i} is connected to:", end=' ') 20 | for j in range(self.count): 21 | if self.adj[i][j] != 0: 22 | print(f"{j}(cost:{self.adj[i][j]})", end =" ") 23 | print() 24 | 25 | def print_path_util(self, previous, source, dest) : 26 | if (dest == source) : 27 | print(source, end="") 28 | else : 29 | self.print_path_util(previous, source, previous[dest]) 30 | print(f"->{dest}", end="") 31 | 32 | def print_path(self, previous, dist, count, source) : 33 | print("Shortest Paths : ", end="") 34 | for i in range(count) : 35 | if (dist[i] == sys.maxsize) : 36 | print(f"({source}->{i} @ Unreachable)", end="") 37 | elif(i != previous[i]) : 38 | print("(", end="") 39 | self.print_path_util(previous, source, i) 40 | print(f" @ {dist[i]}) ", end="") 41 | print() 42 | 43 | def dijkstra(self, source): 44 | previous = [-1] * self.count 45 | dist = [sys.maxsize] * self.count 46 | visited = [False] * self.count 47 | dist[source] = 0 48 | previous[source] = 0 49 | 50 | pq = PriorityQueue() 51 | for i in range(self.count): 52 | pq.add(sys.maxsize, i) 53 | pq.update_key(0, source) 54 | 55 | while pq.size() != 0: 56 | val = pq.pop() 57 | src = val[1] 58 | visited[src] = True 59 | 60 | for dest in range(self.count): 61 | alt = self.adj[src][dest] + dist[src] 62 | if self.adj[src][dest] > 0 and alt < dist[dest] and visited[dest] == False: 63 | dist[dest] = alt 64 | previous[dest] = src 65 | pq.update_key(alt, dest) 66 | 67 | 68 | self.print_path(previous, dist, self.count, source) 69 | 70 | def prims_mst(self): 71 | previous = [-1] * self.count 72 | dist = [sys.maxsize] * self.count 73 | visited = [False] * self.count 74 | source = 0 75 | dist[source] = 0 76 | previous[source] = 0 77 | pq = PriorityQueue() 78 | 79 | for i in range(self.count): 80 | pq.add(sys.maxsize, i) 81 | pq.update_key(0, source) 82 | 83 | while pq.size() != 0: 84 | val = pq.pop() 85 | source = val[1] 86 | visited[source] = True 87 | 88 | for dest in range(self.count): 89 | alt = self.adj[source][dest] 90 | if self.adj[source][dest] > 0 and alt < dist[dest] and visited[dest] == False: 91 | dist[dest] = alt 92 | previous[dest] = source 93 | pq.update_key(alt, dest) 94 | 95 | total_cost = 0 96 | print("Edges are : ", end="") 97 | for i in range(self.count): 98 | if dist[i] == sys.maxsize: 99 | print("(", previous[i], "->", i , "@ Unreachable )", end="") 100 | elif i != previous[i]: 101 | print("(", previous[i], "->", i , "@" , dist[i], ")", end="") 102 | total_cost += dist[i] 103 | print("\nTotal MST cost: ", total_cost) 104 | 105 | 106 | def hamiltonian_cycle_util(self, path, added): 107 | # Base case: full length path is found 108 | # this last check can be modified to make it a path. 109 | if len(path) == self.count: 110 | if self.adj[ path[-1] ][ path[0] ] == 1: 111 | path.append(path[0]) 112 | return True 113 | else: 114 | return False 115 | 116 | for vertex in range(self.count): 117 | # there is a path from last element and next vertex 118 | if self.adj[path[-1]][vertex] == 1 and added[vertex] == False: 119 | path.append(vertex) 120 | added[vertex] = True 121 | if self.hamiltonian_cycle_util(path, added): 122 | return True 123 | # backtracking 124 | path.pop() 125 | added[vertex] = False 126 | return False 127 | 128 | def hamiltonian_cycle(self): 129 | path = [] 130 | path.append(0) 131 | added = [False]*self.count 132 | added[0] = True 133 | if self.hamiltonian_cycle_util(path, added): 134 | print("Hamiltonian Cycle found", path) 135 | return True 136 | print("Hamiltonian Cycle not found") 137 | return False 138 | 139 | def hamiltonian_path_util(self , path, added): 140 | # Base case: full length path is found 141 | if len(path) == self.count: 142 | return True 143 | 144 | for vertex in range(self.count): 145 | # there is a path from last element and next vertex 146 | # and next vertex is not already included in path. 147 | if self.adj[path[-1]][vertex] == 1 and added[vertex] == False: 148 | path.append(vertex) 149 | added[vertex] = True 150 | if self.hamiltonian_path_util(path, added): 151 | return True 152 | # backtracking 153 | path.pop() 154 | added[vertex] = False 155 | return False 156 | 157 | def hamiltonian_path(self): 158 | path = [] 159 | path.append(0) 160 | added = [False]*self.count 161 | added[0] = True 162 | if self.hamiltonian_path_util(path, added): 163 | print("Hamiltonian Path found", path) 164 | return True 165 | print("Hamiltonian Path not found") 166 | return False 167 | 168 | 169 | # Testing code 170 | def test1(): 171 | gph = Graph(4) 172 | gph.add_undirected_edge(0, 1) 173 | gph.add_undirected_edge(0, 2) 174 | gph.add_undirected_edge(1, 2) 175 | gph.add_undirected_edge(2, 3) 176 | gph.print() 177 | 178 | """ 179 | Vertex 0 is connected to: 1(cost:1) 2(cost:1) 180 | Vertex 1 is connected to: 0(cost:1) 2(cost:1) 181 | Vertex 2 is connected to: 0(cost:1) 1(cost:1) 3(cost:1) 182 | Vertex 3 is connected to: 2(cost:1) 183 | """ 184 | 185 | class PriorityQueue(object): 186 | def __init__(self): 187 | self.que = [] 188 | self.count = 0 189 | 190 | def add(self, key, value): 191 | heapq.heappush(self.que, (key, value)) 192 | 193 | def update_key(self, key, value): 194 | heapq.heappush(self.que, (key, value)) 195 | 196 | def pop(self): 197 | val = heapq.heappop(self.que) 198 | return val 199 | 200 | def size(self): 201 | return len(self.que) 202 | 203 | # Testing code 204 | def test2(): 205 | gph = Graph(9) 206 | gph.add_undirected_edge(0, 1, 4) 207 | gph.add_undirected_edge(0, 7, 8) 208 | gph.add_undirected_edge(1, 2, 8) 209 | gph.add_undirected_edge(1, 7, 11) 210 | gph.add_undirected_edge(2, 3, 7) 211 | gph.add_undirected_edge(2, 8, 2) 212 | gph.add_undirected_edge(2, 5, 4) 213 | gph.add_undirected_edge(3, 4, 9) 214 | gph.add_undirected_edge(3, 5, 14) 215 | gph.add_undirected_edge(4, 5, 10) 216 | gph.add_undirected_edge(5, 6, 2) 217 | gph.add_undirected_edge(6, 7, 1) 218 | gph.add_undirected_edge(6, 8, 6) 219 | gph.add_undirected_edge(7, 8, 7) 220 | gph.dijkstra(0) 221 | gph.prims_mst() 222 | 223 | 224 | """ prims_mst 225 | Edges are : ( 0 -> 1 @ 4 )( 1 -> 2 @ 8 )( 2 -> 3 @ 7 )( 3 -> 4 @ 9 )( 2 -> 5 @ 4 )( 5 -> 6 @ 2 )( 6 -> 7 @ 1 )( 2 -> 8 @ 2 ) 226 | Total MST cost: 37 227 | """ 228 | """dijkstra 229 | Shortest Paths : (0->1 @ 4) (0->1->2 @ 12) (0->1->2->3 @ 19) (0->7->6->5->4 @ 21) (0->7->6->5 @ 11) (0->7->6 @ 9) (0->7 @ 8) (0->1->2->8 @ 14) 230 | """ 231 | 232 | # Testing code 233 | def test3(): 234 | gph = Graph(5) 235 | gph.adj = [ [0, 1, 0, 1, 0], 236 | [1, 0, 1, 1, 0], 237 | [0, 1, 0, 0, 1,], 238 | [1, 1, 0, 0, 1], 239 | [0, 1, 1, 1, 0] ] 240 | print(gph.hamiltonian_path()) 241 | 242 | g2 = Graph(5) 243 | g2.adj = [ [0, 1, 0, 1, 0], 244 | [1, 0, 1, 1, 0], 245 | [0, 1, 0, 0, 1,], 246 | [1, 1, 0, 0, 0], 247 | [0, 1, 1, 0, 0] ] 248 | 249 | print(g2.hamiltonian_path()) 250 | 251 | 252 | """ 253 | Hamiltonian Path found [0, 1, 2, 4, 3] 254 | True 255 | Hamiltonian Path found [0, 3, 1, 2, 4] 256 | True 257 | """ 258 | 259 | # Testing code 260 | def test4(): 261 | gph = Graph(5) 262 | gph.adj = [ [0, 1, 0, 1, 0], 263 | [1, 0, 1, 1, 0], 264 | [0, 1, 0, 0, 1], 265 | [1, 1, 0, 0, 1], 266 | [0, 1, 1, 1, 0] ] 267 | print(gph.hamiltonian_cycle()) 268 | 269 | g2 = Graph(5) 270 | g2.adj = [ [0, 1, 0, 1, 0], 271 | [1, 0, 1, 1, 0], 272 | [0, 1, 0, 0, 1], 273 | [1, 1, 0, 0, 0], 274 | [0, 1, 1, 0, 0] ] 275 | 276 | print(g2.hamiltonian_cycle()) 277 | 278 | 279 | """ 280 | Hamiltonian Cycle found [0, 1, 2, 4, 3, 0] 281 | True 282 | Hamiltonian Cycle not found 283 | False 284 | """ 285 | 286 | test1() 287 | test2() 288 | test3() 289 | test4() -------------------------------------------------------------------------------- /HashTable/HTSCKeyValue.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | class HashTableSC(object): 4 | def __init__(self): 5 | self.table_size = 512 6 | self.arr_list = [[] for _ in range(self.table_size)] 7 | 8 | def compute_hash(self, key): 9 | # division method 10 | return key % self.table_size 11 | 12 | def resolver_fun(self, i): 13 | return i 14 | 15 | def resolver_fun2(self, i): 16 | return i * i 17 | 18 | def add(self, key, value): 19 | index = self.compute_hash(key) 20 | self.arr_list[index].append((key, value)) 21 | 22 | def get(self, key): 23 | index = self.compute_hash(key) 24 | for pair in self.arr_list[index]: 25 | if pair[0] == key: 26 | return pair[1] 27 | return sys.maxsize 28 | 29 | def remove(self, key): 30 | index = self.compute_hash(key) 31 | for pair in self.arr_list[index]: 32 | if pair[0] == key: 33 | self.arr_list[index].remove(pair) 34 | return True 35 | return False 36 | 37 | def print(self): 38 | for i in range(self.table_size): 39 | if len(self.arr_list[i]) != 0: 40 | for keyvalue in self.arr_list[i]: 41 | print("Values of key [" , keyvalue[0],"] ::", keyvalue[1]) 42 | 43 | def find(self, key): 44 | index = self.compute_hash(key) 45 | for pair in self.arr_list[index]: 46 | if pair[0] == key: 47 | return True 48 | return False 49 | 50 | # Testing Code 51 | ht = HashTableSC() 52 | ht.add(1, 10) 53 | ht.add(2, 20) 54 | ht.add(3, 30) 55 | ht.print() 56 | print("Find key 2 :", ht.find(2)) 57 | ht.remove(2) 58 | print("After deleting node with key 2.") 59 | print("Find key 2 :", ht.find(2)) 60 | 61 | """ 62 | Values of key [ 1 ] :: 10 63 | Values of key [ 2 ] :: 20 64 | Values of key [ 3 ] :: 30 65 | Find key 2 : True 66 | After deleting node with key 2. 67 | Find key 2 : False 68 | """ -------------------------------------------------------------------------------- /HashTable/HashTableExercise.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | def is_anagram(str1, str2): 4 | size1 = len(str1) 5 | size2 = len(str2) 6 | if size1 != size2: 7 | return False 8 | cm = Counter() 9 | for ch in str1: 10 | cm[ch] += 1 11 | for ch in str2: 12 | if cm[ch] == 0: 13 | return False 14 | else: 15 | cm[ch] -= 1 16 | return True 17 | 18 | # Testing Code 19 | first = "hello" 20 | second = "elloh" 21 | third = "world" 22 | print("is_anagram : " , is_anagram(first, second)) 23 | print("is_anagram : " , is_anagram(first, third)) 24 | 25 | """ 26 | is_anagram : True 27 | is_anagram : False 28 | """ 29 | 30 | def remove_duplicate(exp): 31 | hs = set() 32 | return_exp = "" 33 | for ch in exp: 34 | if (ch in hs) == False: 35 | return_exp += ch 36 | hs.add(ch) 37 | return return_exp 38 | 39 | # Testing Code 40 | first = "hello" 41 | print(remove_duplicate(first)) 42 | 43 | """ 44 | helo 45 | """ 46 | 47 | def find_missing(arr, start, end): 48 | hs = set() 49 | for i in arr: 50 | hs.add(i) 51 | for curr in range(start, end+1): 52 | if (curr in hs) == False: 53 | return curr 54 | return sys.maxsize 55 | 56 | # Testing Code 57 | arr = [1, 2, 3, 5, 6, 7, 8, 9, 10] 58 | print("Missing number :", find_missing(arr, 1, 10)) 59 | 60 | """ 61 | Missing number : 4 62 | """ 63 | 64 | def print_repeating(arr): 65 | hs = set() 66 | print("Repeating elements are:", end=' ') 67 | for val in arr: 68 | if val in hs: 69 | print(val, end=' ') 70 | else: 71 | hs.add(val) 72 | 73 | # Testing Code 74 | arr = [1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 1] 75 | print_repeating(arr) 76 | 77 | """ 78 | Repeating elements are: 4 1 79 | """ 80 | 81 | def print_first_repeating(arr): 82 | size = len(arr) 83 | hs = Counter() 84 | for i in range(size): 85 | hs[arr[i]] += 1 86 | 87 | for i in range(size): 88 | if hs.get(arr[i]) > 1: 89 | print("First Repeating number is :" , arr[i]) 90 | return arr[i] 91 | 92 | # Testing Code 93 | arr = [1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 1] 94 | print_first_repeating(arr) 95 | 96 | """ 97 | First Repeating number is : 1 98 | """ 99 | 100 | def horner_hash(self, key, tableSize): 101 | size = len(key) 102 | h = 0 103 | for i in range(size): 104 | h = (32 * h + key[i]) % tableSize 105 | return h -------------------------------------------------------------------------------- /HashTable/HashTableLP.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | 4 | class HashTable(object): 5 | EMPTY_NODE = -1 6 | LAZY_DELETED = -2 7 | FILLED_NODE = 0 8 | 9 | def __init__(self, tSize): 10 | self.table_size = tSize 11 | self.key_arr = [0] * (tSize + 1) 12 | self.data_arr = [0] * (tSize + 1) 13 | self.flag = [self.EMPTY_NODE] * (tSize + 1) 14 | 15 | def compute_hash(self, key): 16 | return key % self.table_size 17 | 18 | def resolver_fun(self, index): 19 | return index 20 | 21 | def add(self, key, value): 22 | hash_value = self.compute_hash(key) 23 | for i in range(self.table_size): 24 | if self.flag[hash_value] == self.EMPTY_NODE or self.flag[hash_value] == self.LAZY_DELETED: 25 | self.data_arr[hash_value] = value 26 | self.key_arr[hash_value] = key 27 | self.flag[hash_value] = self.FILLED_NODE 28 | return True 29 | elif self.flag[hash_value] == self.FILLED_NODE and self.key_arr[hash_value] == key: 30 | self.data_arr[hash_value] = value 31 | return True 32 | 33 | hash_value += self.resolver_fun(i) 34 | hash_value %= self.table_size 35 | return False 36 | 37 | def find(self, key): 38 | hash_value = self.compute_hash(key) 39 | for i in range(self.table_size): 40 | if self.flag[hash_value] == self.EMPTY_NODE: 41 | return False 42 | if self.flag[hash_value] == self.FILLED_NODE and self.key_arr[hash_value] == key: 43 | return True 44 | hash_value += self.resolver_fun(i) 45 | hash_value %= self.table_size 46 | return False 47 | 48 | def get(self, key): 49 | hash_value = self.compute_hash(key) 50 | for i in range(self.table_size): 51 | if self.flag[hash_value] == self.EMPTY_NODE: 52 | return sys.maxsize 53 | if self.flag[hash_value] == self.FILLED_NODE and self.key_arr[hash_value] == key: 54 | return self.data_arr[hash_value] 55 | hash_value += self.resolver_fun(i) 56 | hash_value %= self.table_size 57 | return sys.maxsize 58 | 59 | def remove(self, key): 60 | hash_value = self.compute_hash(key) 61 | for i in range(self.table_size): 62 | if self.flag[hash_value] == self.EMPTY_NODE: 63 | return False 64 | if self.flag[hash_value] == self.FILLED_NODE and self.key_arr[hash_value] == key: 65 | self.flag[hash_value] = self.LAZY_DELETED 66 | return True 67 | hash_value += self.resolver_fun(i) 68 | hash_value %= self.table_size 69 | return False 70 | 71 | def print(self): 72 | for i in range(self.table_size) : 73 | if self.flag[i] == self.FILLED_NODE: 74 | print("Value for key [", self.key_arr[i] , "] ::", self.data_arr[i]) 75 | 76 | # Testing Code 77 | ht = HashTable(1000) 78 | ht.add(1, 10) 79 | ht.add(2, 20) 80 | ht.add(3, 30) 81 | ht.print() 82 | print("Find key 2 :", ht.find(2)) 83 | ht.remove(2) 84 | print("After deleting node with key 2.") 85 | print("Find key 2 :", ht.find(2)) 86 | 87 | """ 88 | Value at index [ 1 ] :: 10 89 | Value at index [ 2 ] :: 20 90 | Value at index [ 3 ] :: 30 91 | Find key 2 : True 92 | After deleting node with key 2. 93 | Find key 2 : False 94 | """ -------------------------------------------------------------------------------- /Heap/Heap.py: -------------------------------------------------------------------------------- 1 | from heapq import heapify 2 | import math 3 | 4 | def greater(first, second): 5 | return first > second # Min Heap 6 | 7 | def less(first, second): 8 | return first < second # Max Heap 9 | 10 | class Heap: 11 | def __init__(self, array=None, comp = greater): 12 | self.comp = comp 13 | 14 | if array == None: 15 | self.arr = [] 16 | self.size = 0 17 | else: 18 | self.arr = array 19 | self.size = len(array) 20 | self.heapify() 21 | 22 | def heapify(self): 23 | # Build Heap operation over array 24 | i = self.size // 2 25 | while i >= 0: 26 | self.percolate_down(i) 27 | i -= 1 28 | 29 | def print(self): 30 | print(self.arr) 31 | 32 | def is_empty(self): 33 | return (self.size == 0) 34 | 35 | def size(self): 36 | return self.size 37 | 38 | def peek(self): 39 | if self.size() == 0: 40 | raise RuntimeError("Heap is empty.") 41 | return self.arr[0] 42 | 43 | # Other Methods. 44 | 45 | def add(self, value): 46 | self.arr.append(value) 47 | self.size += 1 48 | self.percolate_up(self.size-1) 49 | 50 | def remove(self): 51 | if self.size == 0: 52 | raise RuntimeError("Heap is empty.") 53 | 54 | value = self.arr[0] 55 | self.arr[0] = self.arr[self.size - 1] 56 | self.size -= 1 57 | self.percolate_down(0) 58 | return value 59 | 60 | 61 | def peek(self): 62 | if self.size() == 0: 63 | raise RuntimeError("Heap is empty.") 64 | return self.arr[0] 65 | 66 | def percolate_down(self, parent): 67 | left_child = 2 * parent + 1 68 | right_child = left_child + 1 69 | child = -1 70 | 71 | if left_child < self.size: 72 | child = left_child 73 | 74 | if right_child < self.size and self.comp(self.arr[left_child], self.arr[right_child]): 75 | child = right_child 76 | 77 | if child != -1 and self.comp(self.arr[parent], self.arr[child]): 78 | self.arr[parent], self.arr[child] = self.arr[child], self.arr[parent] 79 | self.percolate_down(child) 80 | 81 | def percolate_up(self, child): 82 | parent = (child - 1)// 2 83 | 84 | if parent < 0: 85 | return 86 | 87 | if self.comp(self.arr[parent], (self.arr[child])): 88 | self.arr[parent], self.arr[child] = self.arr[child], self.arr[parent] 89 | self.percolate_up(parent) 90 | 91 | 92 | # Testing Code 93 | a = [1, 9, 6, 7, 8, 0, 2, 4, 5, 3] 94 | hp2 = Heap() 95 | for i in range(len(a)) : 96 | hp2.add(a[i]) 97 | hp2.print() 98 | 99 | for i in range(len(a)): 100 | print(hp2.remove(), end=' ') 101 | print() 102 | 103 | """ 104 | [0, 3, 1, 5, 4, 6, 2, 9, 7, 8] 105 | 0 1 2 3 4 5 6 7 8 9 106 | """ 107 | 108 | a = [1, 9, 6, 7, 8, 0, 2, 4, 5, 3] 109 | hp = Heap(a, greater) 110 | hp.print() 111 | for i in range(len(a)) : 112 | print(hp.remove(), end=' ') 113 | print("") 114 | """ 115 | [0, 3, 1, 4, 8, 6, 2, 7, 5, 9] 116 | 0 1 2 3 4 5 6 7 8 9 117 | """ 118 | 119 | 120 | a = [1, 9, 6, 7, 8, 0, 2, 4, 5, 3] 121 | hp = Heap(a, less) 122 | hp.print() 123 | for i in range(len(a)) : 124 | print(hp.remove(), end=' ') 125 | print("") 126 | """ 127 | [9, 8, 6, 7, 3, 0, 2, 4, 5, 1] 128 | 9 8 7 6 5 4 3 2 1 0 129 | """ 130 | 131 | def heap_sort(array, is_inc): 132 | if is_inc : 133 | hp = Heap(array, less) # max heap 134 | else: 135 | hp = Heap(array, greater) # min heap 136 | 137 | size = len(array) 138 | for i in range(size): 139 | array[size - i -1] = hp.remove() 140 | 141 | # Testing Code 142 | a = [1, 9, 6, 7, 8, 0, 2, 4, 5, 3] 143 | heap_sort(a, True) 144 | print(a) 145 | 146 | heap_sort(a, False) 147 | print(a) 148 | 149 | """ 150 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 151 | [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] 152 | 153 | """ 154 | 155 | def is_min_heap(arr): 156 | size = len(arr) 157 | for parent in range(size//2 + 1): 158 | left_child = parent * 2 + 1 159 | right_child = parent * 2 + 2 160 | # heap property check. 161 | if (((left_child < size) and (arr[parent] > arr[left_child])) or ((right_child < size) and (arr[parent] > arr[right_child]))): 162 | return False 163 | return True 164 | 165 | # Testing Code 166 | a = [1, 2, 3, 4, 5, 6, 7, 8] 167 | print(is_min_heap(a)) 168 | 169 | """ 170 | True 171 | """ 172 | 173 | def is_max_heap(arr): 174 | size = len(arr) 175 | #last element index size - 1 176 | for parent in range(size//2 + 1): 177 | left_child = parent * 2 + 1 178 | right_child = left_child + 1 179 | # heap property check. 180 | if (((left_child < size) and (arr[parent] < arr[left_child])) or ((right_child < size) and (arr[parent] < arr[right_child]))): 181 | return False 182 | return True 183 | 184 | # Testing Code 185 | b = [8, 7, 6, 5, 4, 3, 2, 1] 186 | print(is_max_heap(b)) 187 | 188 | """ 189 | True 190 | """ -------------------------------------------------------------------------------- /Heap/MedianHeap.py: -------------------------------------------------------------------------------- 1 | import heapq 2 | 3 | class MedianHeap(object): 4 | def __init__(self): 5 | self.minHeap = [] 6 | self.maxHeap = [] 7 | 8 | def min_heap_insert(self, value): 9 | heapq.heappush(self.minHeap, value) 10 | 11 | def max_heap_insert(self, value): 12 | heapq.heappush(self.maxHeap, -1 * value) 13 | 14 | def max_heap_peek(self): 15 | return -1 * self.maxHeap[0] 16 | 17 | def min_heap_peek(self): 18 | return self.minHeap[0] 19 | 20 | def min_heap_remove(self): 21 | return heapq.heappop(self.minHeap) 22 | 23 | def max_heap_remove(self): 24 | return -1 * heapq.heappop(self.maxHeap) 25 | 26 | # Other Methods. 27 | def insert(self, value): 28 | if len(self.maxHeap) == 0 or self.max_heap_peek() >= value: 29 | self.max_heap_insert(value) 30 | else: 31 | self.min_heap_insert(value) 32 | # size balancing 33 | if len(self.maxHeap) > len(self.minHeap) + 1: 34 | value = self.max_heap_remove() 35 | self.min_heap_insert(value) 36 | if len(self.minHeap) > len(self.maxHeap) + 1: 37 | value = self.min_heap_remove() 38 | self.max_heap_insert(value) 39 | 40 | def get_median(self): 41 | if len(self.maxHeap) == 0 and len(self.minHeap) == 0: 42 | return sys.maxsize 43 | if len(self.maxHeap) == len(self.minHeap): 44 | return (self.max_heap_peek() + self.min_heap_peek()) // 2 45 | elif len(self.maxHeap) > len(self.minHeap): 46 | return self.max_heap_peek() 47 | else: 48 | return self.min_heap_peek() 49 | 50 | # Testing Code 51 | arr = [1, 9, 2, 8, 3, 7] 52 | hp = MedianHeap() 53 | for i in range(6) : 54 | hp.insert(arr[i]) 55 | print("Median after insertion of ", arr[i], " is ", hp.get_median()) 56 | 57 | 58 | """ 59 | Median after insertion of 1 is 1 60 | Median after insertion of 9 is 5 61 | Median after insertion of 2 is 2 62 | Median after insertion of 8 is 5 63 | Median after insertion of 3 is 3 64 | Median after insertion of 7 is 5 65 | """ -------------------------------------------------------------------------------- /Introduction/Ackermann.py: -------------------------------------------------------------------------------- 1 | def ackermann(m, n): 2 | if m == 0 : 3 | return n+1 4 | 5 | if (m > 0) and (n == 0) : 6 | return ackermann(m-1, 1) 7 | 8 | if (m > 0) and (n > 0) : 9 | return ackermann(m-1, ackermann(m, n-1)) 10 | 11 | print(ackermann(3, 6)) 12 | 13 | # 509 -------------------------------------------------------------------------------- /Introduction/Analysis.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | def fun1(n): 4 | m = 0 5 | i = 0 6 | while i < n: 7 | m += 1 8 | i += 1 9 | return m 10 | 11 | print("N = 100, Number of instructions in O(n)::", fun1(100)) 12 | 13 | """ 14 | N = 100, Number of instructions in O(n):: 100 15 | """ 16 | 17 | def fun2(n): 18 | m = 0 19 | i = 0 20 | while i < n: 21 | j = 0 22 | while j < n: 23 | m += 1 24 | j += 1 25 | i += 1 26 | return m 27 | 28 | print("N = 100, Number of instructions in O(n^2)::", fun2(100)) 29 | 30 | """ 31 | N = 100, Number of instructions in O(n^2):: 10000 32 | """ 33 | 34 | def fun3(n): 35 | m = 0 36 | i = 0 37 | while i < n: 38 | j = 0 39 | while j < n: 40 | k = 0 41 | while k < n: 42 | m += 1 43 | k += 1 44 | j += 1 45 | i += 1 46 | return m 47 | 48 | print("N = 100, Number of instructions in O(n^3)::", fun3(100)) 49 | 50 | """ 51 | N = 100, Number of instructions in O(n^3):: 1000000 52 | """ 53 | 54 | 55 | def fun4(n): 56 | m = 0 57 | i = 0 58 | while i < n: 59 | j = i 60 | while j < n: 61 | k = j + 1 62 | while k < n: 63 | m += 1 64 | k += 1 65 | j += 1 66 | i += 1 67 | return m 68 | 69 | print("N = 100, Number of instructions in O(n^3)::", fun4(100)) 70 | 71 | """ 72 | N = 100, Number of instructions in O(n^3):: 166650 73 | """ 74 | 75 | 76 | def fun5(n): 77 | m = 0 78 | i = 0 79 | while i < n: 80 | j = 0 81 | while j < i: 82 | m += 1 83 | j += 1 84 | i += 1 85 | return m 86 | 87 | print("N = 100, Number of instructions in O(n^2)::", fun5(100)) 88 | 89 | """ 90 | N = 100, Number of instructions in O(n^2):: 4950 91 | """ 92 | 93 | 94 | def fun6(n): 95 | m = 0 96 | i = 0 97 | while i < n: 98 | j = i 99 | while j > 0: 100 | m += 1 101 | j -= 1 102 | i += 1 103 | return m 104 | 105 | print("N = 100, Number of instructions in O(n^2)::", fun6(100)) 106 | 107 | """ 108 | N = 100, Number of instructions in O(n^2):: 4950 109 | """ 110 | 111 | def fun7(n): 112 | m = 0 113 | i = n 114 | while i > 0: 115 | j = 0 116 | while j < i: 117 | m += 1 118 | j += 1 119 | i //= 2 120 | return m 121 | 122 | print("N = 100, Number of instructions in O(n)::", fun7(100)) 123 | 124 | """ 125 | N = 100, Number of instructions in O(n):: 197 126 | """ 127 | 128 | def fun8(n): 129 | m = 0 130 | i = 1 131 | while i <= n: 132 | j = 0 133 | while j <= i: 134 | m += 1 135 | j += 1 136 | i *= 2 137 | return m 138 | 139 | print("N = 100, Number of instructions in O(n)::", fun8(100)) 140 | 141 | """ 142 | N = 100, Number of instructions in O(n):: 134 143 | """ 144 | 145 | 146 | def fun9(n): 147 | m = 0 148 | i = 1 149 | while i < n: 150 | m += 1 151 | i = i * 2 152 | return m 153 | 154 | print("N = 100, Number of instructions in O(log(n))::", fun9(100)) 155 | 156 | """ 157 | N = 100, Number of instructions in O(log(n)):: 7 158 | """ 159 | 160 | def fun10(n): 161 | m = 0 162 | i = n 163 | while i > 0: 164 | m += 1 165 | i = i // 2 166 | return m 167 | 168 | print("N = 100, Number of instructions in O(log(n))::", fun10(100)) 169 | 170 | """ 171 | N = 100, Number of instructions in O(log(n)):: 7 172 | """ 173 | 174 | 175 | 176 | def fun11(n): 177 | m = 0 178 | i = 0 179 | while i < n: 180 | j = 0 181 | while j < n: 182 | m += 1 183 | j += 1 184 | i += 1 185 | i = 0 186 | while i < n: 187 | k = 0 188 | while k < n: 189 | m += 1 190 | k += 1 191 | i += 1 192 | return m 193 | 194 | print("N = 100, Number of instructions in O(n^2)::", fun11(100)) 195 | 196 | """ 197 | N = 100, Number of instructions in O(n^2):: 20000 198 | """ 199 | 200 | def fun12(n): 201 | m = 0 202 | i = 0 203 | while i < n: 204 | j = 0 205 | while j < math.sqrt(n): 206 | m += 1 207 | j += 1 208 | i += 1 209 | return m 210 | 211 | print("N = 100, Number of instructions in O(n^(3/2))::", fun12(100)) 212 | 213 | """ 214 | N = 100, Number of instructions in O(n^(3/2)):: 1000 215 | """ 216 | 217 | def fun13(n): 218 | m = 0 219 | i = 0 220 | j = 0 221 | while i < n: 222 | while j < n: 223 | m += 1 224 | j += 1 225 | i += 1 226 | return m 227 | 228 | print("N = 100, Number of instructions in O(n)::", fun13(100)) 229 | 230 | """ 231 | N = 100, Number of instructions in O(n):: 100 232 | """ 233 | -------------------------------------------------------------------------------- /Introduction/__pycache__/ModuleTest.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hemant-Jain-Author/Problem-Solving-in-Data-Structures-Algorithms-using-Python/2db1ceb8c9502942692dbf94853119d2ba3c1e11/Introduction/__pycache__/ModuleTest.cpython-38.pyc -------------------------------------------------------------------------------- /LinkedList/CircularLinkedList.py: -------------------------------------------------------------------------------- 1 | class CircularLinkedList(object): 2 | class Node(object): 3 | def __init__(self, v, n=None): 4 | self.value = v 5 | self.next = n 6 | 7 | def __init__(self): 8 | self.tail = None 9 | self.count = 0 10 | 11 | def size(self): 12 | return self.count 13 | 14 | def is_empty(self): 15 | return self.tail == None 16 | 17 | def peek(self): 18 | if self.is_empty(): 19 | raise RuntimeError("EmptyListException") 20 | return self.tail.next.value 21 | 22 | def add_tail(self, value): 23 | temp = self.Node(value, None) 24 | self.count += 1 25 | if self.tail == None: 26 | self.tail = temp 27 | temp.next = temp 28 | else: 29 | temp.next = self.tail.next 30 | self.tail.next = temp 31 | self.tail = temp 32 | 33 | 34 | def add_head(self, value): 35 | temp = self.Node(value, None) 36 | self.count += 1 37 | if self.tail == None: 38 | self.tail = temp 39 | temp.next = temp 40 | else: 41 | temp.next = self.tail.next 42 | self.tail.next = temp 43 | 44 | def remove_head(self): 45 | if self.is_empty(): 46 | raise RuntimeError("EmptyListException") 47 | self.count -= 1 48 | value = self.tail.next.value 49 | if self.tail == self.tail.next: 50 | self.tail = None 51 | else: 52 | self.tail.next = self.tail.next.next 53 | return value 54 | 55 | def remove_node(self, key): 56 | if self.is_empty(): 57 | return False 58 | self.count -= 1 59 | curr = self.tail.next 60 | head = self.tail.next 61 | if curr.value == key: 62 | # head and single node case. 63 | if curr == curr.next: 64 | self.tail = None 65 | else: 66 | self.tail.next = self.tail.next.next 67 | return True 68 | prev = curr 69 | curr = curr.next 70 | while curr != head: 71 | if curr.value == key: 72 | if curr == self.tail: 73 | self.tail = prev 74 | prev.next = curr.next 75 | return True 76 | prev = curr 77 | curr = curr.next 78 | return False 79 | 80 | def copy_list_reversed(self): 81 | cl = CircularLinkedList() 82 | curr = self.tail.next 83 | head = curr 84 | if curr != None: 85 | cl.add_head(curr.value) 86 | curr = curr.next 87 | while curr != head: 88 | cl.add_head(curr.value) 89 | curr = curr.next 90 | return cl 91 | 92 | def copy_list(self): 93 | cl = CircularLinkedList() 94 | curr = self.tail.next 95 | head = curr 96 | if curr != None: 97 | cl.add_tail(curr.value) 98 | curr = curr.next 99 | while curr != head: 100 | cl.add_tail(curr.value) 101 | curr = curr.next 102 | return cl 103 | 104 | def search (self, data): 105 | temp = self.tail 106 | for i in range(self.size()) : 107 | if temp.value == data: 108 | return True 109 | temp = temp.next 110 | return False 111 | 112 | def free(self): 113 | self.tail = None 114 | self.count = 0 115 | 116 | def print(self): 117 | if self.is_empty(): 118 | return 119 | temp = self.tail.next 120 | while temp != self.tail: 121 | print(temp.value, end=' ') 122 | temp = temp.next 123 | print(temp.value) 124 | 125 | 126 | 127 | # Testing Code 128 | def test1(): 129 | ll = CircularLinkedList() 130 | ll.add_head(1) 131 | ll.add_head(2) 132 | ll.add_head(3) 133 | ll.print() 134 | print("Search:", ll.search(2)) 135 | print("Search:", ll.search(4)) 136 | ll.remove_head() 137 | ll.print() 138 | 139 | """ 140 | 3 2 1 141 | Search: True 142 | Search: False 143 | 2 1 144 | """ 145 | 146 | # Testing Code 147 | def test2(): 148 | ll = CircularLinkedList() 149 | ll.add_tail(1) 150 | ll.add_tail(2) 151 | ll.add_tail(3) 152 | ll.print() 153 | 154 | """ 155 | 1 2 3 156 | """ 157 | 158 | 159 | # Testing Code 160 | def test3(): 161 | ll = CircularLinkedList() 162 | ll.add_head(1) 163 | ll.add_head(2) 164 | ll.add_head(3) 165 | ll.print() 166 | ll.remove_node(2) 167 | ll.print() 168 | 169 | 170 | """ 171 | 3 2 1 172 | 3 1 173 | """ 174 | 175 | 176 | # Testing Code 177 | def test4(): 178 | ll = CircularLinkedList() 179 | ll.add_head(1) 180 | ll.add_head(2) 181 | ll.add_head(3) 182 | ll.print() 183 | 184 | ll2 = ll.copy_list() 185 | ll2.print() 186 | 187 | ll3 = ll.copy_list_reversed() 188 | ll3.print() 189 | 190 | """ 191 | 3 2 1 192 | 3 2 1 193 | 1 2 3 194 | """ 195 | test1() 196 | test2() 197 | test3() 198 | test4() -------------------------------------------------------------------------------- /LinkedList/DoublyCircularLinkedList.py: -------------------------------------------------------------------------------- 1 | class DoublyCircularLinkedList(object): 2 | class Node(object): 3 | def __init__(self, v, nxt=None, prv=None): 4 | self.value = v 5 | self.next = nxt 6 | self.prev = prv 7 | 8 | def __init__(self): 9 | self.head = None 10 | self.tail = None 11 | self.count = 0 12 | 13 | def size(self): 14 | return self.count 15 | 16 | def is_empty(self): 17 | return self.head == None 18 | 19 | def peek_head(self): 20 | if self.is_empty(): 21 | raise RuntimeError("EmptyListException") 22 | return self.head.value 23 | 24 | def add_head(self, value): 25 | new_node = self.Node(value, None, None) 26 | self.count += 1 27 | if self.head == None: 28 | self.tail = self.head = new_node 29 | new_node.next = new_node 30 | new_node.prev = new_node 31 | else: 32 | new_node.next = self.head 33 | new_node.prev = self.head.prev 34 | self.head.prev = new_node 35 | new_node.prev.next = new_node 36 | self.head = new_node 37 | 38 | 39 | def add_tail(self, value): 40 | new_node = self.Node(value, None, None) 41 | self.count += 1 42 | if self.head == None: 43 | self.head = self.tail = new_node 44 | new_node.next = new_node 45 | new_node.prev = new_node 46 | else: 47 | new_node.next = self.tail.next 48 | new_node.prev = self.tail 49 | self.tail.next = new_node 50 | new_node.next.prev = new_node 51 | self.tail = new_node 52 | 53 | 54 | def remove_head(self): 55 | if self.head == None: 56 | raise RuntimeError("EmptyListException") 57 | 58 | self.count -= 1 59 | value = self.head.value 60 | 61 | if self.head == self.head.next: 62 | value = self.head.value 63 | self.head = None 64 | self.tail = None 65 | return value 66 | 67 | next_node = self.head.next 68 | next_node.prev = self.tail 69 | self.tail.next = next_node 70 | self.head = next_node 71 | return value 72 | 73 | def remove_tail(self): 74 | if self.count == 0: 75 | raise RuntimeError("EmptyListException") 76 | 77 | self.count -= 1 78 | value = self.tail.value 79 | 80 | if self.count == 0: 81 | self.head = None 82 | self.tail = None 83 | return value 84 | 85 | prev = self.tail.prev 86 | prev.next = self.head 87 | self.head.prev = prev 88 | self.tail = prev 89 | return value 90 | 91 | def search (self, key): 92 | temp = self.head 93 | if self.head == None: 94 | return False 95 | 96 | for i in range(self.size()) : 97 | if temp.value == key: 98 | return True 99 | temp = temp.next 100 | 101 | return False 102 | 103 | def free(self): 104 | self.head = None 105 | self.tail = None 106 | self.count = 0 107 | 108 | def print(self): 109 | if self.is_empty(): 110 | return 111 | temp = self.tail.next 112 | while temp != self.tail: 113 | print(temp.value, end=' ') 114 | temp = temp.next 115 | print(temp.value) 116 | 117 | 118 | # Testing Code 119 | def test1(): 120 | ll = DoublyCircularLinkedList() 121 | ll.add_head(1) 122 | ll.add_head(2) 123 | ll.add_head(3) 124 | print(ll.size()) 125 | ll.print() 126 | 127 | """ 128 | 3 129 | 3 2 1 130 | """ 131 | 132 | def test2(): 133 | ll = DoublyCircularLinkedList() 134 | ll.add_tail(1) 135 | ll.add_tail(2) 136 | ll.add_tail(3) 137 | ll.print() 138 | 139 | """ 140 | 1 2 3 141 | """ 142 | 143 | # Testing Code 144 | def test3(): 145 | ll = DoublyCircularLinkedList() 146 | ll.add_head(1) 147 | ll.add_head(2) 148 | ll.add_head(3) 149 | ll.print() 150 | ll.remove_head() 151 | ll.print() 152 | 153 | """ 154 | 3 2 1 155 | 2 1 156 | """ 157 | 158 | # Testing Code 159 | def test4(): 160 | ll = DoublyCircularLinkedList() 161 | ll.add_head(1) 162 | ll.add_head(2) 163 | ll.add_head(3) 164 | ll.print() 165 | ll.remove_tail() 166 | ll.print() 167 | 168 | """ 169 | 3 2 1 170 | 3 2 171 | """ 172 | 173 | test1() 174 | test2() 175 | test3() 176 | test4() 177 | -------------------------------------------------------------------------------- /LinkedList/DoublyLinkedList.py: -------------------------------------------------------------------------------- 1 | class DoublyLinkedList(object): 2 | class Node(object): 3 | def __init__(self, v, nxt=None, prv=None): 4 | self.value = v 5 | self.next = nxt 6 | self.prev = prv 7 | 8 | def __init__(self): 9 | self.head = None 10 | self.tail = None 11 | self.count = 0 12 | 13 | def size(self): 14 | return self.count 15 | 16 | def is_empty(self): 17 | return self.size() == 0 18 | 19 | def peek(self): 20 | if self.is_empty(): 21 | raise RuntimeError("EmptyListException") 22 | return self.head.value 23 | 24 | def add_head(self, value): 25 | self.count += 1 26 | if self.head == None: 27 | self.tail = self.head = self.Node(value, None, None) 28 | else: 29 | new_node = self.Node(value, self.head, None) 30 | self.head.prev = new_node 31 | self.head = new_node 32 | 33 | 34 | def add_tail(self, value): 35 | new_node = self.Node(value, None, None) 36 | self.count += 1 37 | if self.head == None: 38 | self.head = self.tail = new_node 39 | else: 40 | new_node.prev = self.tail 41 | self.tail.next = new_node 42 | self.tail = new_node 43 | 44 | def remove_head(self): 45 | if self.is_empty(): 46 | raise RuntimeError("EmptyListException") 47 | self.count -= 1 48 | value = self.head.value 49 | self.head = self.head.next 50 | if self.head == None: 51 | self.tail = None 52 | else: 53 | self.head.prev = None 54 | return value 55 | 56 | def remove_node(self, key): 57 | curr = self.head 58 | if curr == None: 59 | return False # empty list 60 | 61 | if curr.value == key: # head is the node with value key. 62 | self.head = self.head.next 63 | if self.head != None: 64 | self.head.prev = None 65 | else : 66 | self.tail = None # only one element in list. 67 | self.count -= 1 68 | return True 69 | 70 | while curr.next != None: 71 | if curr.next.value == key: 72 | curr.next = curr.next.next 73 | if curr.next == None: 74 | self.tail = curr 75 | else: 76 | curr.next.prev = curr 77 | self.count -= 1 78 | return True 79 | curr = curr.next 80 | return False 81 | 82 | def is_present(self, key): 83 | temp = self.head 84 | while temp != None: 85 | if temp.value == key: 86 | return True 87 | temp = temp.next 88 | return False 89 | 90 | def free(self): 91 | self.head = None 92 | self.tail = None 93 | self.count = 0 94 | 95 | def print(self): 96 | temp = self.head 97 | while temp != None: 98 | print(temp.value, end=' ') 99 | temp = temp.next 100 | print("") 101 | 102 | def sorted_insert(self, value): 103 | temp = self.Node(value) 104 | curr = self.head 105 | self.count += 1 106 | if curr == None: 107 | # first element 108 | self.head = temp 109 | self.tail = temp 110 | return 111 | 112 | if curr.value >= value: # at the begining 113 | temp.next = self.head 114 | self.head.prev = temp 115 | self.head = temp 116 | return 117 | 118 | while curr.next != None and curr.next.value < value: # traversal 119 | curr = curr.next 120 | 121 | if curr.next == None: # at the end 122 | self.tail = temp 123 | temp.prev = curr 124 | curr.next = temp 125 | else: # all other 126 | temp.next = curr.next 127 | temp.prev = curr 128 | curr.next = temp 129 | temp.next.prev = temp 130 | 131 | 132 | def reverse_list(self): 133 | curr = self.head 134 | while curr != None: 135 | temp_node = curr.next 136 | curr.next = curr.prev 137 | curr.prev = temp_node 138 | if curr.prev == None: 139 | self.tail = self.head 140 | self.head = curr 141 | return 142 | curr = curr.prev 143 | return 144 | 145 | def remove_duplicate(self): 146 | curr = self.head 147 | while curr != None: 148 | if (curr.next != None) and curr.value == curr.next.value: 149 | curr.next = curr.next.next 150 | if(curr.next != None): 151 | curr.next.prev = curr 152 | else : 153 | self.tail = curr 154 | else: 155 | curr = curr.next 156 | 157 | def copy_list_reversed(self): 158 | dll = DoublyLinkedList() 159 | curr = self.head 160 | while curr != None: 161 | dll.add_head(curr.value) 162 | curr = curr.next 163 | return dll 164 | 165 | def copy_list(self): 166 | dll = DoublyLinkedList() 167 | curr = self.head 168 | while curr != None: 169 | dll.add_tail(curr.value) 170 | curr = curr.next 171 | return dll 172 | 173 | 174 | # Testing Code 175 | def test1(): 176 | ll = DoublyLinkedList() 177 | ll.add_head(1) 178 | ll.add_head(2) 179 | ll.add_head(3) 180 | ll.add_head(4) 181 | ll.print() 182 | ll.remove_head() 183 | ll.print() 184 | ll2 = ll.copy_list() 185 | ll2.print() 186 | ll3 = ll.copy_list_reversed() 187 | ll3.print() 188 | 189 | """ 190 | 4 3 2 1 191 | 3 2 1 192 | 3 2 1 193 | 1 2 3 194 | """ 195 | 196 | def test2(): 197 | ll = DoublyLinkedList() 198 | ll.sorted_insert(2) 199 | ll.sorted_insert(1) 200 | ll.sorted_insert(4) 201 | ll.sorted_insert(3) 202 | ll.print() 203 | 204 | 205 | """ 206 | 1 2 3 4 207 | 208 | """ 209 | 210 | # Testing Code 211 | def test3(): 212 | ll = DoublyLinkedList() 213 | ll.add_head(1) 214 | ll.add_head(2) 215 | ll.add_head(3) 216 | ll.print() 217 | ll.remove_head() 218 | ll.print() 219 | 220 | """ 221 | 3 2 1 222 | 2 1 223 | """ 224 | 225 | # Testing Code 226 | def test4(): 227 | ll = DoublyLinkedList() 228 | ll.add_head(1) 229 | ll.add_head(2) 230 | ll.add_head(3) 231 | ll.print() 232 | ll.remove_node(2) 233 | ll.print() 234 | 235 | 236 | """ 237 | 3 2 1 238 | 2 1 239 | """ 240 | 241 | # Testing Code 242 | def test5(): 243 | ll = DoublyLinkedList() 244 | for i in range(3): 245 | ll.add_head(i) 246 | ll.add_head(i) 247 | ll.print() 248 | ll.remove_duplicate() 249 | ll.print() 250 | 251 | 252 | """ 253 | 2 2 1 1 0 0 254 | 2 1 0 255 | """ 256 | 257 | # Testing Code 258 | def test6(): 259 | ll = DoublyLinkedList() 260 | ll.add_head(1) 261 | ll.add_head(2) 262 | ll.add_head(3) 263 | ll.print() 264 | ll.reverse_list() 265 | ll.print() 266 | 267 | """ 268 | 3 2 1 269 | 1 2 3 270 | """ 271 | 272 | test1() 273 | test2() 274 | test3() 275 | test4() 276 | test5() 277 | test6() 278 | 279 | -------------------------------------------------------------------------------- /LinkedList/Poly.py: -------------------------------------------------------------------------------- 1 | 2 | class Polynomial(object): 3 | # Node class representing elements of linked list. 4 | class Node: 5 | def __init__(self, c, p, n=None): 6 | self.coeff = c 7 | self.pow = p 8 | self.next = n 9 | 10 | # Constructor of Polynomial. 11 | def __init__(self, coeffs=None, pows=None, size=0): 12 | self.head = None 13 | tail=None 14 | temp=None 15 | for i in range(size) : 16 | temp = self.Node(coeffs[i], pows[i]) 17 | if(self.head == None): 18 | self.head = tail = temp 19 | else : 20 | tail.next = temp 21 | tail=tail.next 22 | 23 | def add(self, poly2): 24 | poly = Polynomial() 25 | p1 = self.head 26 | p2 = poly2.head 27 | 28 | while (p1 != None or p2 != None) : 29 | if (p1 == None or (p2 != None and p1.pow < p2.pow)) : 30 | temp = self.Node(p2.coeff, p2.pow) 31 | p2 = p2.next 32 | elif (p2 == None or p1.pow > p2.pow) : 33 | temp = self.Node(p1.coeff, p1.pow) 34 | p1 = p1.next 35 | elif (p1.pow == p2.pow) : 36 | temp = self.Node(p1.coeff + p2.coeff, p1.pow) 37 | p1 = p1.next 38 | p2 = p2.next 39 | 40 | if(poly.head == None): 41 | poly.head = tail = temp 42 | else : 43 | tail.next = temp 44 | tail=tail.next 45 | return poly 46 | 47 | 48 | def print(self) : 49 | head = self.head 50 | while (head != None) : 51 | print(head.coeff, end="") 52 | if(head.pow != 0) : 53 | print("x^"+ str(head.pow), end="") 54 | 55 | if (head.next != None) : 56 | print(" + ", end="") 57 | head = head.next 58 | 59 | 60 | # Testing code. 61 | c1 = [6, 5, 4] 62 | p1 = [2, 1, 0] 63 | s1 = 3 64 | first = Polynomial(c1, p1, s1) 65 | 66 | c2 = [3, 2, 1] 67 | p2 = [3, 1, 0] 68 | s2 = 3 69 | second = Polynomial(c2, p2, s2) 70 | 71 | sum = first.add(second) 72 | sum.print() 73 | 74 | """ 75 | 3x^3 + 6x^2 + 7x^1 + 5 76 | """ -------------------------------------------------------------------------------- /Queue/Queue.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | 3 | que = deque([]) 4 | que.append(1) 5 | que.append(2) 6 | que.append(3) 7 | print("Queue :", que) 8 | print("Queue size :", len(que)) 9 | print("Queue peek :", que[0]) 10 | print("Queue remove :", que.popleft()) 11 | print("Queue :", que) 12 | print("Queue isEmpty :", (len(que) == 0)) 13 | 14 | 15 | """ 16 | Queue : deque([1, 2, 3]) 17 | Queue size : 3 18 | Queue peek : 1 19 | Queue remove : 1 20 | Queue : deque([2, 3]) 21 | Queue isEmpty : False 22 | """ -------------------------------------------------------------------------------- /Queue/QueueArr.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | 3 | class Queue(object): 4 | def __init__(self): 5 | self.data = deque([]) 6 | 7 | def add(self, value): 8 | self.data.append(value) 9 | 10 | def remove(self): 11 | value = self.data.popleft() 12 | return value 13 | 14 | def is_empty(self): 15 | return (len(self.data) == 0) 16 | 17 | def length(self): 18 | return len(self.data) 19 | 20 | def print(self): 21 | print(self.data) 22 | 23 | # Testing Code 24 | que = Queue() 25 | que.add(1) 26 | que.add(2) 27 | que.add(3) 28 | que.print() 29 | print("Queue length:", que.length()) 30 | print("Queue is empty:", que.is_empty()) 31 | print("Queue remove:", que.remove()) 32 | que.print() 33 | 34 | """ 35 | deque([1, 2, 3]) 36 | Queue length: 3 37 | Queue is empty: False 38 | Queue remove: 1 39 | deque([2, 3]) 40 | """ -------------------------------------------------------------------------------- /Queue/QueueList.py: -------------------------------------------------------------------------------- 1 | class Queue(object): 2 | class Node(object): 3 | def __init__(self, v, n=None): 4 | self.value = v 5 | self.next = n 6 | 7 | def __init__(self): 8 | self.head = None 9 | self.tail = None 10 | self.count = 0 11 | 12 | def length(self): 13 | return self.count 14 | 15 | def is_empty(self): 16 | return (self.head == None) 17 | 18 | def peek(self): 19 | if self.is_empty(): 20 | raise RuntimeError("StackEmptyException") 21 | return self.head.value 22 | 23 | def add(self, value): 24 | temp = self.Node(value, None) 25 | self.count += 1 26 | if self.head == None: 27 | self.head = self.tail = temp 28 | else: 29 | self.tail.next = temp 30 | self.tail = temp 31 | 32 | def remove(self): 33 | if self.is_empty(): 34 | raise RuntimeError("StackEmptyException") 35 | self.count -= 1 36 | value = self.head.value 37 | self.head = self.head.next 38 | return value 39 | 40 | def print(self): 41 | temp = self.head 42 | print("Queue:", end=' ') 43 | while temp != None: 44 | print(temp.value, end=' ') 45 | temp = temp.next 46 | print() 47 | 48 | # Testing Code 49 | que = Queue() 50 | que.add(1) 51 | que.add(2) 52 | que.add(3) 53 | que.print() 54 | print("Queue length:", que.length()) 55 | print("Queue is empty:", que.is_empty()) 56 | print("Queue remove:", que.remove()) 57 | que.print() 58 | 59 | """ 60 | Queue: 1 2 3 61 | Queue length: 3 62 | Queue is empty: False 63 | Queue remove: 1 64 | Queue: 2 3 65 | """ 66 | 67 | -------------------------------------------------------------------------------- /Queue/QueueUsingStack.py: -------------------------------------------------------------------------------- 1 | class QueueUsingStack(object): 2 | def __init__(self): 3 | self.stk1 = [] 4 | self.stk2 = [] 5 | 6 | def add(self, value): 7 | self.stk1.append(value) 8 | 9 | def remove(self): 10 | if len(self.stk2) != 0: 11 | return self.stk2.pop() 12 | while len(self.stk1) != 0: 13 | value = self.stk1.pop() 14 | self.stk2.append(value) 15 | return self.stk2.pop() 16 | 17 | def length(self): 18 | return len(self.stk1) + len(self.stk2) 19 | 20 | def is_empty(self): 21 | return len(self.stk1) + len(self.stk2) == 0 22 | 23 | def print(self): 24 | l1 = len(self.stk1) 25 | l2 = len(self.stk2) 26 | print("Queue:", end=' ') 27 | for i in range(l2-1, -1, -1): 28 | print(self.stk2[i], end=" ") 29 | 30 | for i in range(l1): 31 | print(self.stk1[i], end=" ") 32 | print() 33 | 34 | 35 | # Testing Code 36 | que = QueueUsingStack() 37 | que.add(1) 38 | que.add(2) 39 | que.add(3) 40 | que.print() 41 | print("Queue length:", que.length()) 42 | print("Queue is empty:", que.is_empty()) 43 | print("Queue remove:", que.remove()) 44 | que.print() 45 | 46 | """ 47 | Queue: 1 2 3 48 | Queue length: 3 49 | Queue is empty: False 50 | Queue remove: 1 51 | Queue: 2 3 52 | """ -------------------------------------------------------------------------------- /Queue/Stack.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | 3 | class Stack : 4 | def __init__(self): 5 | self.que1 = deque([]) 6 | self.que2 = deque([]) 7 | self.size = 0 8 | 9 | def push(self, value) : 10 | self.que1.append(value) 11 | self.size += 1 12 | 13 | def pop(self) : 14 | value = 0 15 | s = self.size 16 | while (s > 0) : 17 | value = self.que1.popleft() 18 | if (s > 1) : 19 | self.que2.append(value) 20 | s -= 1 21 | self.que1, self.que2 = self.que2 , self.que1 22 | self.size -= 1 23 | return value 24 | 25 | def pop2(self) : 26 | value = 0 27 | s = self.size 28 | while (s > 0) : 29 | value = self.que1.popleft() 30 | if (s > 1) : 31 | self.que1.append(value) 32 | s -= 1 33 | self.size -= 1 34 | return value 35 | 36 | 37 | # Testing Code 38 | s = Stack() 39 | s.push(1) 40 | s.push(2) 41 | s.push(3) 42 | print("Pop :", s.pop()) 43 | print("Pop :", s.pop()) 44 | print() 45 | 46 | s1 = Stack() 47 | s1.push(1) 48 | s1.push(2) 49 | s1.push(3) 50 | print("Pop :", s1.pop2()) 51 | print("Pop :", s1.pop2()) 52 | 53 | """ 54 | Pop : 3 55 | Pop : 2 56 | """ 57 | 58 | 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Problem-Solving-in-Data-Structures-Algorithms-using-Python3 2 | 3 | This is the code repository of book **Problem Solving in Data Structures & Algorithms using Python**. 4 | 5 | ![alt text](https://m.media-amazon.com/images/P/B0BL3WN3SQ.jpg) 6 | 7 | 8 | **About The Book** 9 | - This textbook provides in depth coverage of various Data Structures and Algorithms. 10 | - Concepts are discussed in easy to understand manner. 11 | - Large number of diagrams are provided to grasp concepts easily. 12 | - Time and Space complexities of various algorithms are discussed. 13 | - Helpful for interviews preparation and competitive coding. 14 | - Large number of interview questions are solved. 15 | - Python solutions are provided with input and output. 16 | - Guide you through how to solve new problems in programming interview of various software companies. 17 | 18 | 19 | **Table of Contents** 20 | - Chapter 0: How to use this book. 21 | - Chapter 1: Algorithms Analysis 22 | - Chapter 2: Approach to solve algorithm design problems 23 | - Chapter 3: Abstract Data Type & Python Collections 24 | - Chapter 4: Searching 25 | - Chapter 5: Sorting 26 | - Chapter 6: Linked List 27 | - Chapter 7: Stack 28 | - Chapter 8: Queue 29 | - Chapter 9: Tree 30 | - Chapter 10: Priority Queue 31 | - Chapter 11: Hash-Table 32 | - Chapter 12: Graphs 33 | - Chapter 13: String Algorithms 34 | - Chapter 14: Algorithm Design Techniques 35 | - Chapter 15: Brute Force Algorithm 36 | - Chapter 16: Greedy Algorithm 37 | - Chapter 17: Divide & Conquer 38 | - Chapter 18: Dynamic Programming 39 | - Chapter 19: Backtracking 40 | - Chapter 20: Complexity Theory 41 | 42 | 43 | -------------------------------------------------------------------------------- /Searching/BitManipulation.py: -------------------------------------------------------------------------------- 1 | 2 | def andEx(a, b) : 3 | return a & b 4 | 5 | def orEx(a, b) : 6 | return a | b 7 | 8 | def xorEx(a, b) : 9 | return a ^ b 10 | 11 | def leftShiftEx(a) : # multiply by 2 12 | return a << 1 13 | 14 | def rightShiftEx(a) : # divide by 2 15 | return a >> 1 16 | 17 | def bitReversalEx(a) : 18 | return ~a 19 | 20 | def twoComplementEx(a) : 21 | return -a 22 | 23 | def kthBitCheck(a, k) : 24 | return (a & 1 << (k - 1)) > 0 25 | 26 | def kthBitSet(a, k) : 27 | return (a | 1 << (k - 1)) 28 | 29 | def kthBitReset(a, k) : 30 | return (a & ~(1 << (k - 1))) 31 | 32 | def kthBitToggle(a, k) : 33 | return (a ^ (1 << (k - 1))) 34 | 35 | def rightMostBit(a) : 36 | return a & -a 37 | 38 | def resetRightMostBit(a) : 39 | return a & (a - 1) 40 | 41 | def isPowerOf2(a) : 42 | if ((a & (a - 1)) == 0) : 43 | return True 44 | else : 45 | return False 46 | 47 | def countBits(a) : 48 | count = 0 49 | while (a > 0) : 50 | count += 1 51 | a = a & (a - 1) 52 | return count 53 | 54 | 55 | # Testing Code 56 | a = 4 57 | b = 8 58 | print(andEx(a, b)) 59 | print(orEx(a, b)) 60 | print(xorEx(a, b)) 61 | print(leftShiftEx(a)) # multiply by 2 62 | print(rightShiftEx(a)) # divide by 2 63 | print(bitReversalEx(a)) 64 | print(twoComplementEx(a)) 65 | print(kthBitCheck(a, 3)) 66 | print(kthBitSet(a, 2)) 67 | print(kthBitReset(a, 3)) 68 | print(kthBitToggle(a, 3)) 69 | print(rightMostBit(a)) 70 | print(resetRightMostBit(a)) 71 | print(isPowerOf2(a)) 72 | for i in range(10) : 73 | print(str(i) + " bit count : " + str(countBits(i))) 74 | 75 | """ 76 | 0 77 | 12 78 | 12 79 | 8 80 | 2 81 | -5 82 | -4 83 | True 84 | 6 85 | 0 86 | 0 87 | 4 88 | 0 89 | True 90 | 0 bit count : 0 91 | 1 bit count : 1 92 | 2 bit count : 1 93 | 3 bit count : 2 94 | 4 bit count : 1 95 | 5 bit count : 2 96 | 6 bit count : 2 97 | 7 bit count : 3 98 | 8 bit count : 1 99 | 9 bit count : 2 100 | """ -------------------------------------------------------------------------------- /Searching/FenwicTree.py: -------------------------------------------------------------------------------- 1 | """ 2 | Start from index+1 if you updating index in original array. Keep adding this value 3 | for next node till you reach outside range of tree 4 | """ 5 | def update_util(binary_indexed_tree, val, index): 6 | size = len(binary_indexed_tree) 7 | while index < size: 8 | binary_indexed_tree[index] += val 9 | index = get_next(index) 10 | 11 | def update(binary_indexed_tree, diff, index): 12 | update_util(binary_indexed_tree, diff, index+1) 13 | 14 | """ 15 | Start from index+1 if you want prefix sum 0 to index. Keep adding value 16 | till you reach 0 17 | """ 18 | def get_sum(binary_indexed_tree, index): 19 | index = index + 1 20 | sum = 0 21 | while index > 0 : 22 | sum += binary_indexed_tree[index] 23 | index = get_parent(index) 24 | return sum 25 | 26 | def get_range_sum(binary_indexed_tree, first, second): 27 | index = first 28 | first_sum = 0 29 | while index > 0 : 30 | first_sum += binary_indexed_tree[index] 31 | index = get_parent(index) 32 | 33 | index = second + 1 34 | second_sum = 0 35 | while index > 0 : 36 | second_sum += binary_indexed_tree[index] 37 | index = get_parent(index) 38 | return (second_sum - first_sum) 39 | 40 | """ 41 | Creating tree is like updating Fenwick tree for every value in array 42 | """ 43 | def create_tree(input): 44 | size = len(input) 45 | binary_indexed_tree = [0]*(size+1) 46 | for i in range(size) : 47 | update_util(binary_indexed_tree, input[i], i+1) 48 | return binary_indexed_tree 49 | 50 | """ 51 | To get parent 52 | 1) Boolean AND (2's complement of index) with index 53 | 2) Subtract the result from index 54 | """ 55 | def get_parent(index): 56 | return index - (index & -index) 57 | 58 | """ 59 | To get next 60 | 1) Boolean AND (2's complement of index) with index 61 | 2) Add the result to index 62 | """ 63 | def get_next(index): 64 | return index + (index & -index) 65 | 66 | # Testing Code 67 | input = [1, 2, 3, 4, 5, 6, 7, 8, 9] 68 | binary_indexed_tree = create_tree(input) 69 | for i in range(len(input)): 70 | print(get_sum(binary_indexed_tree, i)) 71 | print(get_range_sum(binary_indexed_tree, 0, i)) 72 | 73 | print(get_range_sum(binary_indexed_tree, 8, 8)) -------------------------------------------------------------------------------- /Sorting/BubbleSort.py: -------------------------------------------------------------------------------- 1 | def less(value1, value2): 2 | return value1 < value2 3 | 4 | def greater(value1, value2): 5 | return value1 > value2 6 | 7 | def bubble_sort(arr): 8 | size = len(arr) 9 | for i in range(size - 1): 10 | for j in range(size - i - 1): 11 | if greater(arr[j], arr[j + 1]): 12 | # Swapping 13 | arr[j] , arr[j + 1] = arr[j + 1], arr[j] 14 | 15 | 16 | def bubble_sort2(arr): 17 | size = len(arr) 18 | swapped = 1 19 | for i in range(size - 1): 20 | swapped = 0 21 | for j in range(size - i - 1): 22 | if greater(arr[j], arr[j + 1]): 23 | # Swapping 24 | arr[j] , arr[j + 1] = arr[j + 1], arr[j] 25 | swapped = 1 26 | if swapped == 0: 27 | break 28 | 29 | # Testing Code 30 | array = [9, 1, 8, 2, 7, 3, 6, 4, 5] 31 | bubble_sort(array) 32 | print(array) 33 | 34 | array = [9, 1, 8, 2, 7, 3, 6, 4, 5] 35 | bubble_sort2(array) 36 | print(array) 37 | 38 | """ 39 | [1, 2, 3, 4, 5, 6, 7, 8, 9] 40 | [1, 2, 3, 4, 5, 6, 7, 8, 9] 41 | """ 42 | -------------------------------------------------------------------------------- /Sorting/BucketSort.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | # Allowed values from 0 to max_value. 4 | def bucket_sort(arr, max_value) : 5 | num_bucket = 5 6 | bucket_sort_util(arr, max_value, num_bucket) 7 | 8 | def bucket_sort_util(arr, max_value, num_bucket) : 9 | length = len(arr) 10 | if (length == 0) : 11 | return 12 | 13 | bucket = [] # Create empty buckets 14 | for i in range(num_bucket) : 15 | bucket.append([]) 16 | 17 | div = math.ceil(float(max_value) / num_bucket) 18 | 19 | # Add elements into the buckets 20 | for i in range(length) : 21 | if (arr[i] < 0 or arr[i] > max_value) : 22 | print("Value out of range.") 23 | return 24 | bucket_index = arr[i] // div 25 | # Maximum value will be assigned to last bucket. 26 | if (bucket_index >= num_bucket) : 27 | bucket_index = num_bucket - 1 28 | bucket[bucket_index].append(arr[i]) 29 | 30 | # Sort the elements of each bucket. 31 | for i in range(num_bucket) : 32 | bucket[i].sort() 33 | 34 | # Populate output from the sorted sublist. 35 | index = 0 36 | for i in range(num_bucket) : 37 | temp = bucket[i] 38 | count = len(temp) 39 | for j in range(count) : 40 | arr[index] = temp[j] 41 | index += 1 42 | 43 | 44 | # Testing Code 45 | array = [1, 34, 7, 99, 5, 23, 45, 88, 77, 19, 91, 100] 46 | max_value = 100 47 | bucket_sort(array, max_value) 48 | print(array) 49 | 50 | """ 51 | [1, 5, 7, 19, 23, 34, 45, 77, 88, 91, 99, 100] 52 | """ -------------------------------------------------------------------------------- /Sorting/CountSort.py: -------------------------------------------------------------------------------- 1 | def count_sort(arr, lower_range, upper_range) : 2 | size = len(arr) 3 | rangeval = upper_range - lower_range 4 | count = [0] * rangeval 5 | for i in range(size) : 6 | count[arr[i] - lower_range] += 1 7 | 8 | j = 0 9 | for i in range(rangeval) : 10 | while (count[i] > 0) : 11 | arr[j] = i + lower_range 12 | count[i] -= 1 13 | j += 1 14 | 15 | 16 | # Testing Code 17 | array = [23, 24, 22, 21, 26, 25, 27, 28, 21, 21] 18 | count_sort(array, 20, 30) 19 | print(array) 20 | 21 | """ 22 | [21, 21, 21, 22, 23, 24, 25, 26, 27, 28] 23 | """ -------------------------------------------------------------------------------- /Sorting/InsertionSort.py: -------------------------------------------------------------------------------- 1 | def greater(value1, value2): 2 | return value1 > value2 3 | 4 | def insertion_sort(arr): 5 | size = len(arr) 6 | i = 1 7 | for i in range(1, size): 8 | temp = arr[i] 9 | j = i 10 | while j > 0 and greater(arr[j - 1], temp): 11 | arr[j] = arr[j - 1] 12 | j -= 1 13 | arr[j] = temp 14 | 15 | 16 | # Testing Code 17 | array = [9, 1, 8, 2, 7, 3, 6, 4, 5] 18 | insertion_sort(array) 19 | print(array) 20 | 21 | """ 22 | [1, 2, 3, 4, 5, 6, 7, 8, 9] 23 | """ 24 | -------------------------------------------------------------------------------- /Sorting/MergeSort.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | def merge_sort(array): 4 | arr = array 5 | size = len(arr) 6 | temp_array = [0] * size 7 | merge_sort_util(arr, temp_array, 0, size - 1) 8 | 9 | def merge_sort_util(arr, temp_array, lower, upper): 10 | if lower >= upper: 11 | return 12 | middle = (lower + upper) // 2 13 | merge_sort_util(arr, temp_array, lower, middle) 14 | merge_sort_util(arr, temp_array, middle + 1, upper) 15 | merge(arr, temp_array, lower, middle, upper) 16 | 17 | def merge(arr, temp_array, lower, middle, upper): 18 | lower_start = lower 19 | lower_stop = middle 20 | upper_start = middle + 1 21 | upper_stop = upper 22 | count = lower 23 | 24 | while lower_start <= lower_stop and upper_start <= upper_stop: 25 | if arr[lower_start] < arr[upper_start]: 26 | temp_array[count] = arr[lower_start] 27 | count += 1 28 | lower_start += 1 29 | else: 30 | temp_array[count] = arr[upper_start] 31 | count += 1 32 | upper_start += 1 33 | 34 | while lower_start <= lower_stop: 35 | temp_array[count] = arr[lower_start] 36 | count += 1 37 | lower_start += 1 38 | 39 | while upper_start <= upper_stop: 40 | temp_array[count] = arr[upper_start] 41 | count += 1 42 | upper_start += 1 43 | 44 | i = lower 45 | while i <= upper: 46 | arr[i] = temp_array[i] 47 | i += 1 48 | 49 | 50 | array = [3, 4, 2, 1, 6, 5, 7, 8, 1, 1] 51 | merge_sort(array) 52 | print(array) 53 | 54 | """ 55 | [1, 1, 1, 2, 3, 4, 5, 6, 7, 8] 56 | """ -------------------------------------------------------------------------------- /Sorting/QuickSelect.py: -------------------------------------------------------------------------------- 1 | def quick_select(array, k): 2 | arr = array 3 | size = len(arr) 4 | quick_select_util(arr, 0, size-1, k-1) 5 | return arr[k-1] 6 | 7 | def quick_select_util(arr, lower, upper, k): 8 | if upper <= lower: 9 | return 10 | pivot = arr[lower] 11 | start = lower 12 | stop = upper 13 | while lower < upper: 14 | while arr[lower] <= pivot and lower < upper: 15 | lower += 1 16 | while arr[upper] > pivot and lower <= upper: 17 | upper -= 1 18 | if lower < upper: 19 | arr[upper], arr[lower] = arr[lower], arr[upper] # swap 20 | 21 | # upper is the pivot position 22 | arr[upper], arr[start] = arr[start], arr[upper] # swap 23 | 24 | if k < upper: # pivot -1 is the upper for left sub array. 25 | quick_select_util(arr, start, upper - 1, k) 26 | 27 | if k > upper: # pivot + 1 is the lower for right sub array. 28 | quick_select_util(arr, upper + 1, stop, k) 29 | 30 | 31 | # Testing Code 32 | array = [3, 4, 2, 1, 6, 5, 7, 8, 10, 9] 33 | value = quick_select(array, 5) 34 | print("value at index 5 is: " , value) 35 | 36 | """ 37 | value at index 5 is: 5 38 | """ 39 | -------------------------------------------------------------------------------- /Sorting/QuickSort.py: -------------------------------------------------------------------------------- 1 | def quick_sort(array): 2 | arr = array 3 | size = len(arr) 4 | quick_sort_util(arr, 0, size - 1) 5 | 6 | def quick_sort_util(arr, lower, upper): 7 | if upper <= lower: 8 | return 9 | pivot = arr[lower] 10 | start = lower 11 | stop = upper 12 | while lower < upper: 13 | while arr[lower] <= pivot and lower < upper: 14 | lower += 1 15 | while arr[upper] > pivot and lower <= upper: 16 | upper -= 1 17 | if lower < upper: 18 | arr[upper], arr[lower] = arr[lower], arr[upper] # swap 19 | 20 | # upper is the pivot position 21 | arr[upper], arr[start] = arr[start], arr[upper] # swap 22 | 23 | quick_sort_util(arr, start, upper - 1) # pivot -1 is the upper for left sub array. 24 | quick_sort_util(arr, upper + 1, stop) # pivot + 1 is the lower for right sub array. 25 | 26 | 27 | # Testing Code 28 | array = [3, 4, 2, 1, 6, 5, 7, 8, 1, 1] 29 | quick_sort(array) 30 | print(array) 31 | 32 | """ 33 | [1, 1, 1, 2, 3, 4, 5, 6, 7, 8] 34 | """ 35 | 36 | -------------------------------------------------------------------------------- /Sorting/RadixSort.py: -------------------------------------------------------------------------------- 1 | def radix_sort(arr) : 2 | n = len(arr) 3 | m = get_max(arr, n) 4 | # Counting sort for every digit. 5 | # The dividend passed is used to calculate current working digit. 6 | div = 1 7 | while (m//div > 0) : 8 | count_sort(arr, n, div) 9 | div *= 10 10 | 11 | def get_max(arr, n) : 12 | mx = arr[0] 13 | for i in range(1, n) : 14 | mx = max(mx, arr[i]) 15 | return mx 16 | 17 | def count_sort(arr, n, dividend) : 18 | temp = arr.copy() 19 | count = [0] * 10 20 | 21 | # Store count of occurrences in count array. 22 | # (number / dividend) % 10 is used to find the working digit. 23 | for i in range(n) : 24 | count[(int(temp[i] / dividend)) % 10] += 1 25 | 26 | # Change count[i] so that count[i] contains 27 | # number of elements till index i in output. 28 | for i in range(1, 10) : 29 | count[i] += count[i - 1] 30 | 31 | # Copy content to input arr. 32 | for i in range(n-1, -1, -1) : 33 | arr[count[(int(temp[i] / dividend)) % 10] - 1] = temp[i] 34 | count[(int(temp[i] / dividend)) % 10] -= 1 35 | 36 | 37 | # Testing Code 38 | array = [100, 49, 65, 91, 702, 29, 4, 55] 39 | radix_sort(array) 40 | print(array) 41 | 42 | """ 43 | [4, 29, 49, 55, 65, 91, 100, 702] 44 | """ -------------------------------------------------------------------------------- /Sorting/SelectionSort.py: -------------------------------------------------------------------------------- 1 | def selection_sort(arr): 2 | # reverse array creation 3 | size = len(arr) 4 | for i in range(size - 1): 5 | max_index = 0 6 | for j in range(1, size - i): 7 | if arr[j] > arr[max_index]: 8 | max_index = j 9 | temp = arr[size - 1 - i] 10 | arr[size - 1 - i] = arr[max_index] 11 | arr[max_index] = temp 12 | 13 | def selection_sort2(arr): 14 | # forward array creation 15 | size = len(arr) 16 | for i in range(size - 1): 17 | min_index = i 18 | for j in range(i+1, size): 19 | if arr[j] < arr[min_index]: 20 | min_index = j 21 | temp = arr[i] 22 | arr[i] = arr[min_index] 23 | arr[min_index] = temp 24 | 25 | 26 | # Testing Code 27 | array = [4, 5, 3, 2, 6, 7, 1, 8, 9, 10] 28 | selection_sort(array) 29 | print(array) 30 | 31 | """ 32 | [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 33 | """ -------------------------------------------------------------------------------- /Sorting/ShellSort.py: -------------------------------------------------------------------------------- 1 | 2 | def greater(value1, value2) : 3 | return value1 > value2 4 | 5 | def shell_sort(arr) : 6 | n = len(arr) 7 | gap = n // 2 # Gap starts with n/2 and half in each iteration. 8 | while (gap > 0) : 9 | i = gap # Do a gapped insertion sort. 10 | while (i < n) : 11 | curr = arr[i] 12 | # Shift elements of already sorted list 13 | # to find right position for curr value. 14 | j = i 15 | while (j >= gap and greater(arr[j - gap], curr)) : 16 | arr[j] = arr[j - gap] 17 | j -= gap 18 | 19 | # Put current value in its correct location 20 | arr[j] = curr 21 | i += 1 22 | gap //= 2 23 | 24 | # Testing Code 25 | array = [36, 32, 11, 6, 19, 31, 17, 3] 26 | shell_sort(array) 27 | print(array) 28 | 29 | """ 30 | [3, 6, 11, 17, 19, 31, 32, 36] 31 | """ -------------------------------------------------------------------------------- /Stack/StackLinkedList.py: -------------------------------------------------------------------------------- 1 | class Stack(object): 2 | class Node(object): 3 | def __init__(self, v, n): 4 | self.value = v 5 | self.next = n 6 | 7 | def __init__(self): 8 | self.head = None 9 | self.size = 0 10 | 11 | def size(self): 12 | return self.size 13 | 14 | def is_empty(self): 15 | return self.size == 0 16 | 17 | def peek(self): 18 | if self.is_empty(): 19 | raise RuntimeError("StackEmptyException") 20 | return self.head.value 21 | 22 | def push(self, value): 23 | self.head = self.Node(value, self.head) 24 | self.size += 1 25 | 26 | def pop(self): 27 | if self.is_empty(): 28 | raise RuntimeError("StackEmptyException") 29 | value = self.head.value 30 | self.head = self.head.next 31 | self.size -= 1 32 | return value 33 | 34 | 35 | def print(self): 36 | temp = self.head 37 | while temp != None: 38 | print(temp.value, end=' ') 39 | temp = temp.next 40 | print() 41 | 42 | # Testing code 43 | s = Stack() 44 | s.push(1) 45 | s.push(2) 46 | s.push(3) 47 | s.print() 48 | print(s.pop()) 49 | s.print() 50 | 51 | """ 52 | 3 2 1 53 | 3 54 | 2 1 55 | """ 56 | -------------------------------------------------------------------------------- /Stack/StackList.py: -------------------------------------------------------------------------------- 1 | class Stack(object): 2 | def __init__(self): 3 | self.data = [] 4 | 5 | def size(self): 6 | return len(self.data) 7 | 8 | def is_empty(self): 9 | return (len(self.data) == 0) 10 | 11 | def push(self, value): 12 | self.data.append(value) 13 | 14 | def top(self): 15 | if self.is_empty(): 16 | raise RuntimeError("StackEmptyException") 17 | return self.data[len(self.data) - 1] 18 | 19 | def pop(self): 20 | if self.is_empty(): 21 | raise RuntimeError("StackEmptyException") 22 | return self.data.pop() 23 | 24 | def print(self): 25 | print(self.data) 26 | 27 | 28 | # Testing Code 29 | s = Stack() 30 | s.push(1) 31 | s.push(2) 32 | s.push(3) 33 | s.print() 34 | print(s.pop()) 35 | s.print() 36 | 37 | """ 38 | [1, 2, 3] 39 | 3 40 | [1, 2] 41 | """ -------------------------------------------------------------------------------- /Stack/TwoStack.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | 3 | class TwoStack(object): 4 | def __init__(self): 5 | self.data = deque([]) 6 | self.size1 = 0 7 | self.size2 = 0 8 | 9 | def push1(self, value): 10 | self.data.appendleft(value) 11 | self.size1 += 1 12 | 13 | def pop1(self): 14 | if self.size1 == 0: 15 | raise RuntimeError("stack empty") 16 | self.size1 -= 1 17 | return self.data.popleft() 18 | 19 | def push2(self, value): 20 | self.data.append(value) 21 | self.size2 += 1 22 | 23 | def pop2(self): 24 | if self.size2 == 0: 25 | raise RuntimeError("stack empty") 26 | self.size2 -= 1 27 | return self.data.pop() 28 | 29 | # Testing code 30 | st = TwoStack() 31 | st.push1(1) 32 | st.push1(2) 33 | st.push1(3) 34 | st.push2(4) 35 | st.push2(5) 36 | st.push2(6) 37 | 38 | print("stk1 pop", st.pop1()) 39 | print("stk1 pop", st.pop1()) 40 | print("stk2 pop", st.pop2()) 41 | print("stk2 pop", st.pop2()) 42 | 43 | """ 44 | stk1 pop 3 45 | stk1 pop 2 46 | stk2 pop 6 47 | stk2 pop 5 48 | """ -------------------------------------------------------------------------------- /String/StringClass.py: -------------------------------------------------------------------------------- 1 | str1 = "Hello" 2 | print(str1[0]) 3 | str2 = "Hello" 4 | str3 = "HELLO" 5 | print("str1 equals str2 :" , str1 == str2) 6 | print("str1 equals str3 :" , str1 == str3) 7 | print(str1[0]) 8 | first = "Hello " 9 | second = "world" 10 | third = first + second 11 | print(third) 12 | print(len(str1)) 13 | print(str1.find("ll")) 14 | print(str1.isdigit()) 15 | arr = ["1","2","3"] 16 | print("".join(arr)) 17 | print(str1.replace("ll", "LL")) 18 | print(str1.lower()) 19 | print(str1.upper()) 20 | str2 = "johny johny yes papa" 21 | print(str2.split()) 22 | 23 | -------------------------------------------------------------------------------- /String/StringCompare.py: -------------------------------------------------------------------------------- 1 | 2 | def brute_force_search(text, pattern): 3 | n = len(text) 4 | m = len(pattern) 5 | for i in range(n - m + 1) : 6 | j = 0 7 | while j < m and pattern[j] == text[i + j]: 8 | j += 1 9 | if j == m: 10 | return i 11 | return -1 12 | 13 | def robinkarp_search(text, pattern): 14 | n = len(text) 15 | m = len(pattern) 16 | prime = 101 17 | powm = 1 18 | text_hash = 0 19 | pattern_hash = 0 20 | 21 | if m == 0 or m > n: 22 | return -1 23 | 24 | for i in range(m - 1) : 25 | powm = (powm << 1) % prime 26 | 27 | for i in range(m) : 28 | pattern_hash = ((pattern_hash << 1) + ord(pattern[i])) % prime 29 | text_hash = ((text_hash << 1) + ord(text[i])) % prime 30 | 31 | for i in range(n - m + 1) : 32 | if text_hash == pattern_hash: 33 | j = 0 34 | while j < m : 35 | if text[i + j] != pattern[j]: 36 | break 37 | j += 1 38 | 39 | if j == m: 40 | return i 41 | 42 | if i < (n - m) : 43 | text_hash = (((text_hash - ord(text[i]) * powm) << 1) + ord(text[i + m])) % prime 44 | 45 | if text_hash < 0: 46 | text_hash = (text_hash + prime) 47 | return -1 48 | 49 | def kmp_preprocess(pattern, shift_arr): 50 | m = len(pattern) 51 | i = 0 52 | j = -1 53 | shift_arr[i] = -1 54 | while i < m: 55 | while j >= 0 and pattern[i] != pattern[j]: 56 | j = shift_arr[j] 57 | i += 1 58 | j += 1 59 | shift_arr[i] = j 60 | 61 | def kmp_search(text, pattern): 62 | i = 0 63 | j = 0 64 | n = len(text) 65 | m = len(pattern) 66 | shift_arr = [0] * (m + 1) 67 | kmp_preprocess(pattern, shift_arr) 68 | while i < n: 69 | while j >= 0 and text[i] != pattern[j]: 70 | j = shift_arr[j] 71 | i += 1 72 | j += 1 73 | if j == m: 74 | return (i - m) 75 | return -1 76 | 77 | def kmp_find_count(text, pattern): 78 | i = 0 79 | j = 0 80 | count = 0 81 | n = len(text) 82 | m = len(pattern) 83 | shift_arr = [0] * (m + 1) 84 | kmp_preprocess(pattern, shift_arr) 85 | while i < n: 86 | while j >= 0 and text[i] != pattern[j]: 87 | j = shift_arr[j] 88 | i += 1 89 | j += 1 90 | if j == m: 91 | count += 1 92 | j = shift_arr[j] 93 | return count 94 | 95 | # Testing code. 96 | st1 = "hello, world!" 97 | st2 = "world!" 98 | print("brute_force_search return :", brute_force_search(st1, st2)) 99 | print("robinkarp return :", robinkarp_search(st1, st2)) 100 | print("kmp return:" , kmp_search(st1, st2)) 101 | str3 = "Only time will tell if we stand the test of time" 102 | print("Frequency of 'time' is ", kmp_find_count(str3, "time")) 103 | 104 | """ 105 | brute_force_search return : 7 106 | robinkarp return : 7 107 | kmp return : 7 108 | Frequency of 'time' is 2 109 | """ -------------------------------------------------------------------------------- /String/StringEx.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | import math 3 | 4 | def match_exp_util(exp, text, i, j): 5 | if i == len(exp) and j == len(text): 6 | return True 7 | if (i == len(exp) and j != len(text)) or (i != len(exp) and j == len(text)): 8 | return False 9 | if exp[i] == '?' or exp[i] == text[j]: 10 | return match_exp_util(exp, text, i + 1, j + 1) 11 | if exp[i] == '*': 12 | return match_exp_util(exp, text, i + 1, j) or match_exp_util(exp, text, i, j + 1) or match_exp_util(exp, text, i + 1, j + 1) 13 | return False 14 | 15 | def match_exp(exp, text): 16 | return match_exp_util(exp, text, 0, 0) 17 | 18 | # Testing code. 19 | def test1(): 20 | print(match_exp("hello*", "helloworld")) 21 | print(match_exp("hello?d", "hellowd")) 22 | print(match_exp("hello*hemant", "helloworldfsdfsdfdsfhemant")) 23 | print(match_exp("*hemantj", "helloworldfsdfsdfdsfhemant")) 24 | 25 | 26 | """ 27 | True 28 | True 29 | True 30 | False 31 | """ 32 | 33 | # Match if the pattern is present in the source text. 34 | def match(source, pattern): 35 | index_source = 0 36 | index_pattern = 0 37 | sourceLen = len(source) 38 | patternLen = len(pattern) 39 | while index_source < sourceLen: 40 | if source[index_source] == pattern[index_pattern]: 41 | index_pattern += 1 42 | if index_pattern == patternLen: 43 | return True 44 | index_source += 1 45 | return False 46 | 47 | # Testing code. 48 | def test2(): 49 | print(match("hellofskdlfjsdlfjsldjflksdworld", "helloworld")) 50 | print(match("hellod", "hellowd")) 51 | print(match("hello*xxxxxxxxxxhemantxxxxxxxxxxxx", "hellnt")) 52 | print() 53 | 54 | 55 | """ 56 | True 57 | False 58 | True 59 | """ 60 | 61 | def my_strdup(src): 62 | length = len(src) 63 | dst = [None] * length 64 | index = 0 65 | for ch in src: 66 | dst[index] = ch 67 | index += 1 68 | return dst 69 | 70 | def is_prime(n): 71 | if (n > 1): 72 | answer = True 73 | else: 74 | answer = False 75 | i = 2 76 | while i * i <= n: 77 | if n % i == 0: 78 | answer = False 79 | break 80 | i += 1 81 | return answer 82 | 83 | # Testing code. 84 | def test3(): 85 | print("Prime numbers under 10 :: ", end = " ") 86 | for i in range(10): 87 | if (is_prime(i)): 88 | print(i, end = " ") 89 | print() 90 | 91 | 92 | """ 93 | Prime numbers under 10 :: 2 3 5 7 94 | """ 95 | 96 | def my_atoi(text): 97 | value = 0 98 | size = len(text) 99 | for i in range(size): 100 | value = (value << 3) + (value << 1) + (ord(text[i]) - ord('0')) 101 | return value 102 | 103 | # Testing code. 104 | print(my_atoi("100")) 105 | """ 106 | 100 107 | """ 108 | 109 | def is_unique_char(text): 110 | charset = set() 111 | for ch in text: 112 | if(ch in charset): 113 | return False 114 | charset.add(ch) 115 | return True 116 | 117 | # Testing code. 118 | def test4(): 119 | print("is_unique_char", is_unique_char("aple")) 120 | print("is_unique_char", is_unique_char("apple")) 121 | 122 | 123 | """ 124 | No duplicate detected! 125 | Duplicate detected! 126 | """ 127 | 128 | def is_permutation(s1, s2): 129 | mycounter = Counter() 130 | if len(s1) != len(s2): 131 | return False 132 | 133 | for ch in s1: 134 | mycounter[ch] += 1 135 | 136 | for ch in s2: 137 | if (ch in mycounter) == False: 138 | return False 139 | 140 | if(mycounter[ch] == 1): 141 | mycounter.pop(ch) 142 | else: 143 | mycounter[ch] -= 1 144 | return (len(mycounter) == 0) 145 | 146 | # Testing code. 147 | def test5(): 148 | print("is_permutation :", is_permutation("apple", "plepa")) 149 | print("is_permutation :", is_permutation("appleb", "plepaa")) 150 | 151 | 152 | """ 153 | is_permutation : True 154 | is_permutation : False 155 | """ 156 | 157 | def is_palindrome(text): 158 | i = 0 159 | j = len(text) - 1 160 | while i < j and text[i] == text[j]: 161 | i += 1 162 | j -= 1 163 | if i < j: 164 | print("String is not a Palindrome") 165 | return False 166 | else: 167 | print("String is a Palindrome") 168 | return True 169 | 170 | # Testing code. 171 | def test6(): 172 | is_palindrome("hello") 173 | is_palindrome("eoloe") 174 | 175 | 176 | """ 177 | String is not a Palindrome 178 | String is a Palindrome 179 | """ 180 | 181 | def pow(x, n): 182 | value = int() 183 | if n == 0: 184 | return (1) 185 | elif n % 2 == 0: 186 | value = pow(x, n // 2) 187 | return (value * value) 188 | else: 189 | value = pow(x, n // 2) 190 | return (x * value * value) 191 | 192 | # Testing code. 193 | def test7(): 194 | print(pow(5, 2)) 195 | 196 | """ 197 | 25 198 | """ 199 | 200 | def my_strcmp(a, b): 201 | len1 = len(a) 202 | len2 = len(b) 203 | minlen = min(len1, len2) 204 | 205 | index = 0 206 | while index < minlen and a[index] == b[index]: 207 | index += 1 208 | if index == len1 and index == len2: 209 | return 0 210 | elif len1 == index: 211 | return -1 212 | elif len2 == index: 213 | return 1 214 | else: 215 | return ord(a[index]) - ord(b[index]) 216 | 217 | 218 | # Testing code. 219 | def test8(): 220 | print("StrCmp returns :", my_strcmp("aba", "aas")) 221 | 222 | 223 | """ 224 | StrCmp returns : 1 225 | """ 226 | 227 | def reverse_string(a): 228 | a = list(a) 229 | lower = 0 230 | upper = len(a) - 1 231 | while lower < upper: 232 | a[lower], a[upper] = a[upper],a[lower] 233 | lower += 1 234 | upper -= 1 235 | return "".join(a) 236 | 237 | def reverse_string_util(a, lower, upper): 238 | while lower < upper: 239 | a[lower], a[upper] = a[upper],a[lower] 240 | lower += 1 241 | upper -= 1 242 | 243 | def reverse_words(a): 244 | a = list(a) 245 | length = len(a) 246 | upper = -1 247 | lower = 0 248 | for i in range(length+1): 249 | if i == length or a[i] == ' ': 250 | reverse_string_util(a, lower, upper) 251 | lower = i + 1 252 | upper = i 253 | else: 254 | upper += 1 255 | reverse_string_util(a, 0, length - 1) 256 | return "".join(a) 257 | 258 | # Testing code. 259 | def test9(): 260 | print(reverse_string("apple")) 261 | print(reverse_words("hello world")) 262 | 263 | 264 | """ 265 | elppa 266 | world hello 267 | """ 268 | 269 | 270 | def print_anagram(a): 271 | n = len(a) 272 | a = list(a) 273 | print_anagram_util(a, 0, n) 274 | 275 | 276 | def print_anagram_util(a, i, n): 277 | if i == n: 278 | print("".join(a)) 279 | return; 280 | 281 | for j in range(i, n) : 282 | a[i], a[j] = a[j], a[i] 283 | print_anagram_util(a, i+1, n) 284 | a[i], a[j] = a[j], a[i] 285 | 286 | # Testing code. 287 | def test10(): 288 | print_anagram("123") 289 | 290 | 291 | """ 292 | 123 293 | 132 294 | 213 295 | 231 296 | 321 297 | 312 298 | """ 299 | 300 | def shuffle(text): 301 | n = len(text) // 2 302 | ar = list(text) 303 | count = 0 304 | k = 1 305 | temp = '\0' 306 | i = 1 307 | while i < n: 308 | temp = ar[i] 309 | k = i 310 | while True: 311 | k = (2 * k) % (2 * n - 1) 312 | temp, ar[k] = ar[k], temp 313 | count += 1 314 | if not ((i != k)): 315 | break 316 | 317 | if count == (2 * n - 2): 318 | break 319 | i = i + 2 320 | return "".join(ar) 321 | 322 | # Testing code. 323 | def test11(): 324 | print(shuffle("ABCDE12345")) 325 | 326 | 327 | """ 328 | A1B2C3D4E5 329 | """ 330 | 331 | def add_binary(first, second): 332 | size1 = len(first) 333 | size2 = len(second) 334 | index = 0 335 | total = [] 336 | if size1 > size2: 337 | total = [0] * (size1 + 1) 338 | index = size1 339 | else: 340 | total = [0] * (size2 + 1) 341 | index = size2 342 | carry = 0 343 | size1 -= 1 344 | size2 -= 1 345 | while size1 >= 0 or size2 >= 0: 346 | firstValue = 0 347 | secondValue = 0 348 | if (size1 >= 0): 349 | firstValue = ord(first[size1]) - ord('0') 350 | if (size2 >= 0): 351 | secondValue = ord(second[size2]) - ord('0') 352 | sumvalue = firstValue + secondValue + carry 353 | carry = sumvalue >> 1 354 | sumvalue = sumvalue & 1 355 | if (sumvalue == 0): 356 | total[index] = '0' 357 | else: 358 | total[index] ='1' 359 | index -= 1 360 | size1 -= 1 361 | size2 -= 1 362 | if (carry == 0): 363 | total[index] = '0' 364 | else: 365 | total[index] = '1' 366 | return "".join(total) 367 | 368 | # Testing code. 369 | def test12(): 370 | a = "101010" 371 | b = "111111" 372 | print(add_binary(a, b)) 373 | 374 | 375 | """ 376 | 1101001 377 | """ 378 | 379 | test1() 380 | test2() 381 | test3() 382 | test4() 383 | test5() 384 | test6() 385 | test7() 386 | test8() 387 | test9() 388 | test10() 389 | test11() 390 | test12() 391 | -------------------------------------------------------------------------------- /String/StringTree.py: -------------------------------------------------------------------------------- 1 | class StringTree(object): 2 | class Node(object): 3 | def __init__(self, v, cnt=1, l=None, r=None): 4 | self.value = v 5 | self.count = cnt 6 | self.left = l 7 | self.right = r 8 | 9 | def __init__(self): 10 | self.root = None 11 | 12 | # Other Methods. 13 | def print_tree(self): 14 | self.print_tree_util(self.root) 15 | 16 | def print_tree_util(self, curr): 17 | # pre order 18 | if curr != None: 19 | print("[", curr.value, ":", curr.count, "]") 20 | self.print_tree_util(curr.left) 21 | self.print_tree_util(curr.right) 22 | 23 | def insert(self, value): 24 | self.root = self.insert_util(value, self.root) 25 | 26 | def insert_util(self, value, curr): 27 | if curr == None: 28 | curr = self.Node(value) 29 | else: 30 | compare = self.strcmp(curr.value, value) 31 | if compare == 0: 32 | curr.count += 1 33 | elif compare == 1: 34 | curr.left = self.insert_util(value, curr.left) 35 | else: 36 | curr.right = self.insert_util(value, curr.right) 37 | return curr 38 | 39 | def strcmp(self, first, second): 40 | if(first == second): 41 | return 0 42 | elif(first < second): 43 | return 1 44 | else: 45 | return -1 46 | 47 | def free(self): 48 | self.root = None 49 | 50 | def find(self, value): 51 | ret = self.find_util(self.root, value) 52 | return ret 53 | 54 | def find_util(self, curr, value): 55 | if curr == None: 56 | return False 57 | compare = self.strcmp(curr.value, value) 58 | if compare == 0: 59 | return True 60 | elif compare == 1: 61 | return self.find_util(curr.left, value) 62 | else: 63 | return self.find_util(curr.right, value) 64 | 65 | def frequency(self, value): 66 | return self.frequency_util(self.root, value) 67 | 68 | def frequency_util(self, curr, value): 69 | if curr == None: 70 | return 0 71 | compare = self.strcmp(curr.value, value) 72 | if compare == 0: 73 | return curr.count 74 | elif compare > 0: 75 | return self.frequency_util(curr.left, value) 76 | else: 77 | return self.frequency_util(curr.right, value) 78 | 79 | # Testing code. 80 | t = StringTree() 81 | t.insert("banana") 82 | t.insert("apple") 83 | t.insert("mango") 84 | print("Apple Found:", t.find("apple")) 85 | print("Grapes Found:", t.find("grapes")) 86 | print("Banana Found:", t.find("banana")) 87 | 88 | """ 89 | Apple Found: True 90 | Grapes Found: False 91 | Banana Found: True 92 | """ -------------------------------------------------------------------------------- /String/TST.py: -------------------------------------------------------------------------------- 1 | class TST(object): 2 | class Node(object): 3 | def __init__(self, d, isLast = False): 4 | self.data = d 5 | self.is_last_char = isLast 6 | self.left = self.equal = self.right = None 7 | 8 | def __init__(self): 9 | self.root = None 10 | 11 | def insert(self, word): 12 | self.root = self.insert_util(self.root, word, 0) 13 | 14 | def insert_util(self, curr, word, word_index): 15 | if curr == None: 16 | curr = self.Node(word[word_index]) 17 | if word[word_index] < curr.data: 18 | curr.left = self.insert_util(curr.left, word, word_index) 19 | elif word[word_index] > curr.data: 20 | curr.right = self.insert_util(curr.right, word, word_index) 21 | else: 22 | if word_index < len(word) - 1: 23 | curr.equal = self.insert_util(curr.equal, word, word_index + 1) 24 | else: 25 | curr.is_last_char = True 26 | return curr 27 | 28 | def find_util(self, curr, word, word_index): 29 | if curr == None: 30 | return False 31 | if word[word_index] < curr.data: 32 | return self.find_util(curr.left, word, word_index) 33 | elif word[word_index] > curr.data: 34 | return self.find_util(curr.right, word, word_index) 35 | else: 36 | if word_index == len(word) - 1: 37 | return curr.is_last_char 38 | return self.find_util(curr.equal, word, word_index + 1) 39 | 40 | def find(self, word): 41 | ret = self.find_util(self.root, word, 0) 42 | return ret 43 | 44 | # Testing code. 45 | t = TST() 46 | t.insert("banana") 47 | t.insert("apple") 48 | t.insert("mango") 49 | 50 | print("Apple Found:", t.find("apple")) 51 | print("Grapes Found:", t.find("grapes")) 52 | print("Banana Found:", t.find("banana")) 53 | 54 | """ 55 | Apple Found: True 56 | Grapes Found: False 57 | Banana Found: True 58 | """ -------------------------------------------------------------------------------- /String/Trie.py: -------------------------------------------------------------------------------- 1 | class Trie(object): 2 | class Node(object): 3 | CharCount = 26 4 | 5 | def __init__(self, c, isLast = False): 6 | self.child = [None] * (self.CharCount) 7 | self.isLastChar = isLast 8 | self.ch = c 9 | 10 | def __init__(self): 11 | self.root = self.Node(' ') 12 | # first node with dummy value. 13 | 14 | def insert(self, token): 15 | if token == None: 16 | return self.root 17 | return self.insert_util(self.root, token.lower(), 0) 18 | 19 | def insert_util(self, curr, token, index): 20 | if curr == None: 21 | curr = self.Node(token[index - 1]) 22 | if index == len(token): 23 | curr.isLastChar = True 24 | else: 25 | curr.child[ord(token[index]) - ord('a')] = self.insert_util(curr.child[ord(token[index]) - ord('a')], token, index + 1) 26 | return curr 27 | 28 | 29 | def remove(self, token): 30 | if token == None: 31 | return 32 | token = token.lower() 33 | self.remove_util(self.root, token, 0) 34 | 35 | def remove_util(self, curr, token, index): 36 | if curr == None: 37 | return 38 | if index == len(token): 39 | if curr.isLastChar: 40 | curr.isLastChar = False 41 | return 42 | self.remove_util(curr.child[ord(token[index]) - ord('a')], token, index + 1) 43 | 44 | def find(self, token): 45 | if token == None: 46 | return False 47 | token = token.lower() 48 | return self.find_util(self.root, token, 0) 49 | 50 | def find_util(self, curr, token, index): 51 | if curr == None: 52 | return False 53 | if index == len(token): 54 | return curr.isLastChar 55 | return self.find_util(curr.child[ord(token[index]) - ord('a')], token, index + 1) 56 | 57 | # Testing code. 58 | t = Trie() 59 | t.insert("banana") 60 | t.insert("apple") 61 | t.insert("mango") 62 | 63 | print("Apple Found:", t.find("apple")) 64 | print("Grapes Found:", t.find("grapes")) 65 | print("Banana Found:", t.find("banana")) 66 | """ 67 | Apple Found: True 68 | Grapes Found: False 69 | Banana Found: True 70 | """ 71 | -------------------------------------------------------------------------------- /Tree/AVLTree.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | class AVLTree : 4 | class Node : 5 | def __init__(self, d, l, r) : 6 | self.data = d 7 | self.left = l 8 | self.right = r 9 | self.height = 0 10 | 11 | def __init__(self) : 12 | self.root = None 13 | 14 | def height(self, n) : 15 | if (n == None) : 16 | return -1 17 | return n.height 18 | 19 | def get_balance(self, node) : 20 | return 0 if (node == None) else (self.height(node.left) - self.height(node.right)) 21 | 22 | def insert(self, data) : 23 | self.root = self.insert_util(self.root, data) 24 | 25 | def insert_util(self, node, data) : 26 | if (node == None) : 27 | return self.Node(data, None, None) 28 | if (node.data > data) : 29 | node.left = self.insert_util(node.left, data) 30 | elif(node.data < data) : 31 | node.right = self.insert_util(node.right, data) 32 | else : 33 | # Duplicate data not allowed 34 | return node 35 | 36 | node.height = max(self.height(node.left), self.height(node.right)) + 1 37 | 38 | balance = self.get_balance(node) 39 | if (balance > 1) : 40 | if (data < node.left.data) : # Left Left Case 41 | return self.right_rotate(node) 42 | if (data > node.left.data) : # Left Right Case 43 | return self.left_right_rotate(node) 44 | if (balance < -1) : 45 | if (data > node.right.data) : # Right Right Case 46 | return self.left_rotate(node) 47 | if (data < node.right.data) : # Right Left Case 48 | return self.right_left_rotate(node) 49 | return node 50 | 51 | # Function to right rotate subtree rooted with x 52 | def right_rotate(self, x) : 53 | y = x.left 54 | T = y.right 55 | # Rotation 56 | y.right = x 57 | x.left = T 58 | # Update heights 59 | x.height = max(self.height(x.left), self.height(x.right)) + 1 60 | y.height = max(self.height(y.left), self.height(y.right)) + 1 61 | # Return new root 62 | return y 63 | 64 | # Function to left rotate subtree rooted with x 65 | def left_rotate(self, x) : 66 | y = x.right 67 | T = y.left 68 | # Rotation 69 | y.left = x 70 | x.right = T 71 | # Update heights 72 | x.height = max(self.height(x.left), self.height(x.right)) + 1 73 | y.height = max(self.height(y.left), self.height(y.right)) + 1 74 | # Return new root 75 | return y 76 | 77 | # Function to right then left rotate subtree rooted with x 78 | def right_left_rotate(self, x) : 79 | x.right = self.right_rotate(x.right) 80 | return self.left_rotate(x) 81 | 82 | # Function to left then right rotate subtree rooted with x 83 | def left_right_rotate(self, x) : 84 | x.left = self.left_rotate(x.left) 85 | return self.right_rotate(x) 86 | 87 | def delete(self, data) : 88 | self.root = self.delete_util(self.root, data) 89 | 90 | def delete_util(self, node, data) : 91 | if (node == None) : 92 | return None 93 | if (node.data == data) : 94 | if (node.left == None and node.right == None) : 95 | return None 96 | elif (node.left == None) : 97 | return node.right 98 | elif (node.right == None) : 99 | return node.left 100 | else : 101 | min_node = self.find_min(node.right) 102 | node.data = min_node.data 103 | node.right = self.delete_util(node.right, min_node.data) 104 | else : 105 | if (node.data > data) : 106 | node.left = self.delete_util(node.left, data) 107 | else : 108 | node.right = self.delete_util(node.right, data) 109 | 110 | node.height = max(self.height(node.left), self.height(node.right)) + 1 111 | balance = self.get_balance(node) 112 | 113 | if (balance > 1) : 114 | if (data >= node.left.data) : # Left Left Case 115 | return self.right_rotate(node) 116 | if (data < node.left.data) : # Left Right Case 117 | return self.left_right_rotate(node) 118 | if (balance < -1) : 119 | if (data <= node.right.data) : # Right Right Case 120 | return self.left_rotate(node) 121 | if (data > node.right.data) : # Right Left Case 122 | return self.right_left_rotate(node) 123 | return node 124 | 125 | def find_min(self, curr) : 126 | node = curr 127 | if (node == None) : 128 | return None 129 | while (node.left != None) : 130 | node = node.left 131 | return node 132 | 133 | def print_tree(self) : 134 | self.print_tree_util(self.root, "", False) 135 | print() 136 | 137 | def print_tree_util(self, node, indent, isLeft) : 138 | if (node == None) : 139 | return 140 | if (isLeft) : 141 | print(indent + "L:", end ="") 142 | indent += "| " 143 | else : 144 | print(indent + "R:", end ="") 145 | indent += " " 146 | print(str(node.data) + "(" + str(node.height) + ")") 147 | self.print_tree_util(node.left, indent, True) 148 | self.print_tree_util(node.right, indent, False) 149 | 150 | # Testing Code 151 | t = AVLTree() 152 | t.insert(1) 153 | t.insert(2) 154 | t.insert(3) 155 | t.insert(4) 156 | t.insert(5) 157 | t.insert(6) 158 | t.insert(7) 159 | t.insert(8) 160 | t.print_tree() 161 | # R:4(3) 162 | # L:2(1) 163 | # | L:1(0) 164 | # | R:3(0) 165 | # R:6(2) 166 | # L:5(0) 167 | # R:7(1) 168 | # R:8(0) 169 | t.delete(5) 170 | t.print_tree() 171 | # R:4(2) 172 | # L:2(1) 173 | # | L:1(0) 174 | # | R:3(0) 175 | # R:7(1) 176 | # L:6(0) 177 | # R:8(0) 178 | t.delete(1) 179 | t.print_tree() 180 | # R:4(2) 181 | # L:2(1) 182 | # | R:3(0) 183 | # R:7(1) 184 | # L:6(0) 185 | # R:8(0) 186 | t.delete(2) 187 | t.print_tree() -------------------------------------------------------------------------------- /Tree/BinaryIndexTree.py: -------------------------------------------------------------------------------- 1 | 2 | class BinaryIndexTree : 3 | def __init__(self, arr) : 4 | self.size = len(arr) 5 | self.bit = [0] * (self.size + 1) # Populating bit. 6 | for i in range(self.size) : 7 | self.update(i, arr[i]) 8 | 9 | def set(self, arr, index, val) : 10 | diff = val - arr[index] 11 | arr[index] = val 12 | # Difference is propagated. 13 | self.update(index, diff) 14 | 15 | def update(self, index, val) : 16 | # Index in bit is 1 more than the input list. 17 | index = index + 1 18 | # Traverse to ancestors of nodes. 19 | while (index <= self.size) : 20 | # Add val to current node of Binary Index Tree. 21 | self.bit[index] += val 22 | # Next element which need to store val. 23 | index += index & (-index) 24 | 25 | # Range sum in the range start to end. 26 | def range_sum(self, start, end) : 27 | # Check for error conditions. 28 | if (start > end or start < 0 or end > self.size - 1) : 29 | print("Invalid Input.") 30 | return -1 31 | return self.prefix_sum(end) - self.prefix_sum(start - 1) 32 | 33 | # Prefix sum in the range 0 to index. 34 | def prefix_sum(self, index) : 35 | sum = 0 36 | index = index + 1 37 | # Traverse ancestors of Binary Index Tree nodes. 38 | while (index > 0) : 39 | # Add current element to sum. 40 | sum += self.bit[index] 41 | # Parent index calculation. 42 | index -= index & (-index) 43 | return sum 44 | 45 | # Testing Code 46 | arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] 47 | tree = BinaryIndexTree(arr) 48 | print("Sum of elements in range(0, 5): " + str(tree.prefix_sum(5))) 49 | print("Sum of elements in range(2, 5): " + str(tree.range_sum(2, 5))) 50 | tree.set(arr, 3, 10) # Set fourth element to 10. 51 | # Find sum after the value is updated 52 | print("Sum of elements in range(0, 5): " + str(tree.prefix_sum(5))) 53 | 54 | """ 55 | Sum of elements in range(0, 5): 21 56 | Sum of elements in range(2, 5): 18 57 | Sum of elements in range(0, 5): 27 58 | """ -------------------------------------------------------------------------------- /Tree/RangeMaxST.py: -------------------------------------------------------------------------------- 1 | import math 2 | import sys 3 | 4 | class RangeMaxST : 5 | def __init__(self, input) : 6 | self.n = len(input) 7 | # Height of segment tree. 8 | x = math.ceil(math.log(self.n) / math.log(2)) 9 | # Maximum size of segment tree 10 | max_size = 2 * int(math.pow(2,x)) - 1 11 | # Allocate memory for segment tree 12 | self.segarray = [0] * max_size 13 | self.construct_segtree(input, 0, self.n - 1, 0) 14 | 15 | def construct_segtree(self, input, start, end, index) : 16 | # Store it in current node of the segment tree and return 17 | if (start == end) : 18 | self.segarray[index] = input[start] 19 | return input[start] 20 | 21 | # If there are more than one elements, 22 | # then traverse left and right subtrees 23 | # and store the minimum of values in current node. 24 | mid = (start + end) // 2 25 | self.segarray[index] = max(self.construct_segtree(input, start, mid, index * 2 + 1), 26 | self.construct_segtree(input, mid + 1, end, index * 2 + 2)) 27 | return self.segarray[index] 28 | 29 | 30 | def get_max(self, start, end) : 31 | # Check for error conditions. 32 | if (start > end or start < 0 or end > self.n - 1) : 33 | print("Invalid Input.") 34 | return -sys.maxsize 35 | return self.get_max_util(0, self.n - 1, start, end, 0) 36 | 37 | def get_max_util(self, seg_start, seg_end, query_start, query_end, index) : 38 | if (query_start <= seg_start and seg_end <= query_end) : # complete overlapping case. 39 | return self.segarray[index] 40 | if (seg_end < query_start or query_end < seg_start) : # no overlapping case. 41 | return -sys.maxsize 42 | # Segment tree is partly overlaps with the query range. 43 | mid = int((seg_start + seg_end) / 2) 44 | return max(self.get_max_util(seg_start, mid, query_start, query_end, 2 * index + 1), self.get_max_util(mid + 1, seg_end, query_start, query_end, 2 * index + 2)) 45 | 46 | def update(self, ind, val) : 47 | # Check for error conditions. 48 | if (ind < 0 or ind > self.n - 1) : 49 | print("Invalid Input.") 50 | return 51 | # Update the values in segment tree 52 | self.update_util(0, self.n - 1, ind, val, 0) 53 | 54 | # Always min inside valid range will be returned. 55 | def update_util(self, seg_start, seg_end, ind, val, index) : 56 | # Update index lies outside the range of current segment. 57 | # So minimum will not change. 58 | if (ind < seg_start or ind > seg_end) : 59 | return self.segarray[index] 60 | 61 | # If the input index is in range of this node, then update the 62 | # value of the node and its children 63 | if (seg_start == seg_end) : 64 | if (seg_start == ind) : # Index value need to be updated. 65 | self.segarray[index] = val 66 | return val 67 | else : 68 | return self.segarray[index] 69 | 70 | mid = (seg_start + seg_end) // 2 71 | 72 | # Current node value is updated with min. 73 | self.segarray[index] = max(self.update_util(seg_start, mid, ind, val, 2 * index + 1), self.update_util(mid + 1, seg_end, ind, val, 2 * index + 2)) 74 | 75 | # Value of diff is propagated to the parent node. 76 | return self.segarray[index] 77 | 78 | 79 | # Testing Code 80 | arr = [1, 8, 2, 7, 3, 6, 4, 5] 81 | tree = RangeMaxST(arr) 82 | print("Max value in the range(1, 5): " + str(tree.get_max(1, 5))) 83 | print("Max value in the range(2, 7): " + str(tree.get_max(2, 7))) 84 | print("Max value of all the elements: " + str(tree.get_max(0, len(arr) - 1))) 85 | tree.update(2, 9) 86 | print("Max value in the range(1, 5): " + str(tree.get_max(1, 5))) 87 | print("Max value of all the elements: " + str(tree.get_max(0, len(arr) - 1))) 88 | 89 | """ 90 | Max value in the range(1, 5): 8 91 | Max value in the range(2, 7): 7 92 | Max value of all the elements: 8 93 | Max value in the range(1, 5): 9 94 | Max value of all the elements: 9 95 | """ -------------------------------------------------------------------------------- /Tree/RmqST.py: -------------------------------------------------------------------------------- 1 | import math 2 | import sys 3 | 4 | class RmqST : 5 | def __init__(self, input) : 6 | self.n = len(input) 7 | # Height of segment tree. 8 | x = math.ceil(math.log(self.n) / math.log(2)) 9 | # Maximum size of segment tree 10 | max_size = 2 * int(math.pow(2,x)) - 1 11 | # Allocate memory for segment tree 12 | self.segarray = [0] * (max_size) 13 | self.construct_segtree(input, 0, self.n - 1, 0) 14 | 15 | def construct_segtree(self, input, start, end, index) : 16 | # Store it in current node of the segment tree and return 17 | if (start == end) : 18 | self.segarray[index] = input[start] 19 | return input[start] 20 | # If there are more than one elements, 21 | # then traverse left and right subtrees 22 | # and store the minimum of values in current node. 23 | mid = int((start + end) / 2) 24 | self.segarray[index] = min(self.construct_segtree(input, start, mid, index * 2 + 1), self.construct_segtree(input, mid + 1, end, index * 2 + 2)) 25 | return self.segarray[index] 26 | 27 | 28 | def get_min(self, start, end) : 29 | # Check for error conditions. 30 | if (start > end or start < 0 or end > self.n - 1) : 31 | print("Invalid Input.") 32 | return sys.maxsize 33 | return self.get_min_util(0, self.n - 1, start, end, 0) 34 | 35 | def get_min_util(self, seg_start, seg_end, query_start, query_end, index) : 36 | if (query_start <= seg_start and seg_end <= query_end) : # complete overlapping case. 37 | return self.segarray[index] 38 | if (seg_end < query_start or query_end < seg_start) : # no overlapping case. 39 | return sys.maxsize 40 | # Segment tree is partly overlaps with the query range. 41 | mid = int((seg_start + seg_end) / 2) 42 | return min(self.get_min_util(seg_start, mid, query_start, query_end, 2 * index + 1), 43 | self.get_min_util(mid + 1, seg_end, query_start, query_end, 2 * index + 2)) 44 | 45 | def update(self, ind, val) : 46 | # Check for error conditions. 47 | if (ind < 0 or ind > self.n - 1) : 48 | print("Invalid Input.") 49 | return 50 | # Update the values in segment tree 51 | self.update_util(0, self.n - 1, ind, val, 0) 52 | 53 | # Always min inside valid range will be returned. 54 | def update_util(self, seg_start, seg_end, ind, val, index) : 55 | # Update index lies outside the range of current segment. 56 | # So minimum will not change. 57 | if (ind < seg_start or ind > seg_end) : 58 | return self.segarray[index] 59 | # If the input index is in range of this node, then update the 60 | # value of the node and its children 61 | if (seg_start == seg_end) : 62 | if (seg_start == ind) : 63 | # Index value need to be updated. 64 | self.segarray[index] = val 65 | return val 66 | else : 67 | return self.segarray[index] 68 | mid = int((seg_start + seg_end) / 2) 69 | # Current node value is updated with min. 70 | self.segarray[index] = min(self.update_util(seg_start, mid, ind, val, 2 * index + 1), self.update_util(mid + 1, seg_end, ind, val, 2 * index + 2)) 71 | # Value of diff is propagated to the parent node. 72 | return self.segarray[index] 73 | 74 | 75 | # Testing Code 76 | arr = [2, 3, 1, 7, 12, 5] 77 | tree = RmqST(arr) 78 | print("Min value in the range(1, 5): " + str(tree.get_min(1, 5))) 79 | print("Min value of all the elements: " + str(tree.get_min(0, len(arr) - 1))) 80 | tree.update(2, -1) 81 | print("Min value in the range(1, 5): " + str(tree.get_min(1, 5))) 82 | print("Min value of all the elements: " + str(tree.get_min(0, len(arr) - 1))) 83 | tree.update(5, -2) 84 | print("Min value in the range(0, 4): " + str(tree.get_min(0, 4))) 85 | print("Min value of all the elements: " + str(tree.get_min(0, len(arr) - 1))) 86 | 87 | """ 88 | Min value in the range(1, 5): 1 89 | Min value of all the elements: 1 90 | Min value in the range(1, 5): -1 91 | Min value of all the elements: -1 92 | Min value in the range(0, 4): -1 93 | Min value of all the elements: -2 94 | """ 95 | -------------------------------------------------------------------------------- /Tree/SPLAYTree.py: -------------------------------------------------------------------------------- 1 | 2 | class SPLAYTree : 3 | class Node : 4 | def __init__(self, d, l, r) : 5 | self.data = d 6 | self.left = l 7 | self.right = r 8 | self.parent = None 9 | 10 | def __init__(self) : 11 | self.root = None 12 | 13 | def print_tree(self) : 14 | self.print_tree_util(self.root, "", False) 15 | print() 16 | 17 | def print_tree_util(self, node, indent, isLeft) : 18 | if (node == None) : 19 | return 20 | if (isLeft) : 21 | print(indent + "L:", end ="") 22 | indent += "| " 23 | else : 24 | print(indent + "R:", end ="") 25 | indent += " " 26 | print(node.data) 27 | self.print_tree_util(node.left, indent, True) 28 | self.print_tree_util(node.right, indent, False) 29 | 30 | # Function to right rotate subtree rooted with x 31 | def right_rotate(self, x) : 32 | y = x.left 33 | T = y.right 34 | # Rotation 35 | y.parent = x.parent 36 | y.right = x 37 | x.parent = y 38 | x.left = T 39 | if (T != None) : T.parent = x 40 | if (y.parent != None and y.parent.left == x) : 41 | y.parent.left = y 42 | elif (y.parent != None and y.parent.right == x) : 43 | y.parent.right = y 44 | # Return new root 45 | return y 46 | 47 | # Function to left rotate subtree rooted with x 48 | def left_rotate(self, x) : 49 | y = x.right 50 | T = y.left 51 | # Rotation 52 | y.parent = x.parent 53 | y.left = x 54 | x.parent = y 55 | x.right = T 56 | if (T != None) : T.parent = x 57 | if (y.parent != None and y.parent.left == x) : 58 | y.parent.left = y 59 | elif (y.parent != None and y.parent.right == x) : 60 | y.parent.right = y 61 | # Return new root 62 | return y 63 | 64 | def parent(self, node) : 65 | if (node == None or node.parent == None) : 66 | return None 67 | return node.parent 68 | 69 | def splay(self, node) : 70 | while (node != self.root) : 71 | parent = self.parent(node) 72 | grand = self.parent(parent) 73 | if (parent == None) : 74 | # rotations had created new root, always last condition. 75 | self.root = node 76 | elif (grand == None) : 77 | # single rotation case. 78 | if (parent.left == node) : 79 | node = self.right_rotate(parent) 80 | else : 81 | node = self.left_rotate(parent) 82 | elif (grand.left == parent and parent.left == node) : 83 | # Zig Zig case. 84 | self.right_rotate(grand) 85 | node = self.right_rotate(parent) 86 | elif (grand.right == parent and parent.right == node) : 87 | # Zag Zag case. 88 | self.left_rotate(grand) 89 | node = self.left_rotate(parent) 90 | elif (grand.left == parent and parent.right == node) : 91 | # Zig Zag case. 92 | self.left_rotate(parent) 93 | node = self.right_rotate(grand) 94 | elif (grand.right == parent and parent.left == node) : 95 | # Zag Zig case. 96 | self.right_rotate(parent) 97 | node = self.left_rotate(grand) 98 | 99 | def find(self, data) : 100 | curr = self.root 101 | while (curr != None) : 102 | if (curr.data == data) : 103 | self.splay(curr) 104 | return True 105 | elif (curr.data > data) : 106 | curr = curr.left 107 | else : 108 | curr = curr.right 109 | return False 110 | 111 | def insert(self, data) : 112 | newnode = self.Node(data, None, None) 113 | if (self.root == None) : 114 | self.root = newnode 115 | return 116 | node = self.root 117 | parent = None 118 | while (node != None) : 119 | parent = node 120 | if (node.data > data) : 121 | node = node.left 122 | elif (node.data < data) : 123 | node = node.right 124 | else : 125 | self.splay(node) 126 | # duplicate insertion not allowed but splaying for it. 127 | return 128 | newnode.parent = parent 129 | if (parent.data > data) : 130 | parent.left = newnode 131 | else : 132 | parent.right = newnode 133 | self.splay(newnode) 134 | 135 | def find_min_node(self, curr) : 136 | node = curr 137 | if (node == None) : 138 | return None 139 | while (node.left != None) : 140 | node = node.left 141 | return node 142 | 143 | def delete(self, data) : 144 | node = self.root 145 | parent = None 146 | next = None 147 | while (node != None) : 148 | if (node.data == data) : 149 | parent = node.parent 150 | if (node.left == None and node.right == None) : 151 | next = None 152 | elif (node.left == None) : 153 | next = node.right 154 | elif (node.right == None) : 155 | next = node.left 156 | 157 | if (node.left == None or node.right == None) : 158 | if (node == self.root) : 159 | self.root = next 160 | return 161 | if (parent.left == node) : 162 | parent.left = next 163 | else : 164 | parent.right = next 165 | 166 | if (next != None) : 167 | next.parent = parent 168 | break 169 | minnode = self.find_min_node(node.right) 170 | data = minnode.data 171 | node.data = data 172 | node = node.right 173 | elif (node.data > data) : 174 | parent = node 175 | node = node.left 176 | else : 177 | parent = node 178 | node = node.right 179 | self.splay(parent) 180 | 181 | def print_in_order(self) : 182 | self.print_in_order_util(self.root) 183 | print() 184 | 185 | def print_in_order_util(self, node) : 186 | # In order 187 | if (node != None) : 188 | self.print_in_order_util(node.left) 189 | print(node.data, end =" ") 190 | self.print_in_order_util(node.right) 191 | 192 | 193 | # Testing Code 194 | tree = SPLAYTree() 195 | tree.insert(5) 196 | tree.insert(4) 197 | tree.insert(6) 198 | tree.insert(3) 199 | tree.insert(2) 200 | tree.insert(1) 201 | tree.insert(3) 202 | tree.print_tree() 203 | print("Value 2 found: " + str(tree.find(2))) 204 | tree.delete(2) 205 | tree.delete(5) 206 | tree.print_tree() 207 | 208 | """ 209 | R:3 210 | L:2 211 | | L:1 212 | R:6 213 | L:4 214 | | R:5 215 | 216 | Value 2 found: True 217 | R:4 218 | L:3 219 | | L:1 220 | R:6 221 | """ -------------------------------------------------------------------------------- /Tree/SegmentTree.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | class SegmentTree : 4 | def __init__(self, input) : 5 | self.size = len(input) 6 | # Height of segment tree. 7 | x = math.ceil(math.log(self.size) / math.log(2)) 8 | # Maximum size of segment tree 9 | max_size = 2 * int(math.pow(2,x)) - 1 10 | # Allocate memory for segment tree 11 | self.segarray = [0] * (max_size) 12 | self.construct_segtree(input, 0, self.size - 1, 0) 13 | 14 | def construct_segtree(self, input, start, end, index) : 15 | # Store it in current node of the segment tree and return 16 | if (start == end) : 17 | self.segarray[index] = input[start] 18 | return input[start] 19 | # If there are more than one elements, 20 | # then traverse left and right subtrees 21 | # and store the sum of values in current node. 22 | mid = (start + end) // 2 23 | self.segarray[index] = self.construct_segtree(input, start, mid, index * 2 + 1) + self.construct_segtree(input, mid + 1, end, index * 2 + 2) 24 | return self.segarray[index] 25 | 26 | def get_sum(self, start, end) : 27 | # Check for error conditions. 28 | if (start > end or start < 0 or end > self.size - 1) : 29 | print("Invalid Input.") 30 | return -1 31 | return self.get_sum_util(0, self.size - 1, start, end, 0) 32 | 33 | def get_sum_util(self, seg_start, seg_end, query_start, query_end, index) : 34 | if (query_start <= seg_start and seg_end <= query_end) : # complete overlapping case. 35 | return self.segarray[index] 36 | if (seg_end < query_start or query_end < seg_start) : # no overlapping case. 37 | return 0 38 | # Segment tree is partly overlaps with the query range. 39 | mid = (seg_start + seg_end) // 2 40 | return self.get_sum_util(seg_start, mid, query_start, query_end, 2 * index + 1) + \ 41 | self.get_sum_util(mid + 1, seg_end, query_start, query_end, 2 * index + 2) 42 | 43 | def set(self, arr, ind, val) : 44 | # Check for error conditions. 45 | if (ind < 0 or ind > self.size - 1) : 46 | print("Invalid Input.") 47 | return 48 | arr[ind] = val 49 | # Set new value in segment tree 50 | self.set_util(0, self.size - 1, ind, val, 0) 51 | 52 | # Always diff will be returned. 53 | def set_util(self, seg_start, seg_end, ind, val, index) : 54 | # set index lies outside the range of current segment. 55 | # So diff to its parent node will be zero. 56 | if (ind < seg_start or ind > seg_end) : 57 | return 0 58 | # If the input index is in range of this node, then set the 59 | # value of the node and its children 60 | if (seg_start == seg_end) : 61 | if (seg_start == ind) : 62 | # Index that need to be set. 63 | diff = val - self.segarray[index] 64 | self.segarray[index] = val 65 | return diff 66 | else : 67 | return 0 68 | mid = (seg_start + seg_end) // 2 69 | diff = self.set_util(seg_start, mid, ind, val, 2 * index + 1) + self.set_util(mid + 1, seg_end, ind, val, 2 * index + 2) 70 | # Current node value is set with diff. 71 | self.segarray[index] = self.segarray[index] + diff 72 | # Value of diff is propagated to the parent node. 73 | return diff 74 | 75 | 76 | # Testing Code 77 | arr = [1, 2, 4, 8, 16, 32, 64] 78 | tree = SegmentTree(arr) 79 | print("Sum of values in the range(0, 3): " + str(tree.get_sum(1, 3))) 80 | print("Sum of values of all the elements: " + str(tree.get_sum(0, len(arr) - 1))) 81 | tree.set(arr, 1, 10) 82 | print("Sum of values in the range(0, 3): " + str(tree.get_sum(1, 3))) 83 | print("Sum of values of all the elements: " + str(tree.get_sum(0, len(arr) - 1))) 84 | 85 | """ 86 | Sum of values in the range(0, 3): 14 87 | Sum of values of all the elements: 127 88 | Sum of values in the range(0, 3): 22 89 | Sum of values of all the elements: 135 90 | """ --------------------------------------------------------------------------------