├── .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 | 
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 | """
--------------------------------------------------------------------------------