diff --git a/Graph Algorithms/Bellman Ford algorithm.py b/Graph Algorithms/Bellman Ford algorithm.py new file mode 100644 index 0000000..63edac9 --- /dev/null +++ b/Graph Algorithms/Bellman Ford algorithm.py @@ -0,0 +1,107 @@ +import sys + + +class Node(object): + def __init__(self, name): + self.name = name + self.visited = False + self.adjacencyList = [] + self.predecessor = None + self.minDistance = sys.maxsize + + +class Edge(object): + def __init__(self, weight, startVertex, targetVertex): + self.weight = weight + self.startVertex = startVertex + self.targetVertex = targetVertex + + +class Bellman_Ford(object): + HAS_CYCLE = False + + def calculate_shortest_path(self, edgeList, vertexList, startVertex): + startVertex.minDistance = 0 + + for i in range(0, len(vertexList)-1): + for edge in edgeList: + u = edge.startVertex + v = edge.targetVertex + tempDist = u.minDistance + edge.weight + + if tempDist < v.minDistance: + v.minDistance = tempDist + v.predecessor = u + for edge in edgeList: + if self.hasCycle(edge): + print("Negative cycle detected......") + Bellman_Ford.HAS_CYCLE = True + return + + def hasCycle(self, edge): + if (edge.startVertex.minDistance + edge.weight) < edge.targetVertex.minDistance: + return True + else: + return False + + def get_shortest_path(self, targetVertex): + if Bellman_Ford.HAS_CYCLE is not None: + print("The path to the vertex {} is {}".format(targetVertex.name, targetVertex.minDistance)) + node = targetVertex + while node is not None: + print(node.name) + node = node.predecessor + else: + print("The graph has a negative cycle") + + +node1 = Node("A") +node2 = Node("B") +node3 = Node("C") +node4 = Node("D") +node5 = Node("E") +node6 = Node("F") +node7 = Node("G") +node8 = Node("H") + +edge1 = Edge(5, node1, node2) +edge2 = Edge(8, node1, node8) +edge3 = Edge(9, node1, node5) +edge4 = Edge(15, node2, node4) +edge5 = Edge(12, node2, node3) +edge6 = Edge(4, node2, node8) +edge7 = Edge(7, node8, node3) +edge8 = Edge(6, node8, node6) +edge9 = Edge(5, node5, node8) +edge10 = Edge(4, node5, node6) +edge11 = Edge(20, node5, node7) +edge12 = Edge(1, node6, node3) +edge13 = Edge(13, node6, node7) +edge14 = Edge(3, node3, node4) +edge15 = Edge(11, node3, node7) +edge16 = Edge(9, node4, node7) + +node1.adjacencyList.append(edge1) +node1.adjacencyList.append(edge2) +node1.adjacencyList.append(edge3) +node2.adjacencyList.append(edge4) +node2.adjacencyList.append(edge5) +node2.adjacencyList.append(edge6) +node8.adjacencyList.append(edge7) +node8.adjacencyList.append(edge8) +node5.adjacencyList.append(edge9) +node5.adjacencyList.append(edge10) +node5.adjacencyList.append(edge11) +node6.adjacencyList.append(edge12) +node6.adjacencyList.append(edge13) +node3.adjacencyList.append(edge14) +node3.adjacencyList.append(edge15) +node4.adjacencyList.append(edge16) + + +vertexList = (node1, node2, node3, node4, node5, node6, node7, node8) +edgeList = (edge1, edge2, edge3, edge4, edge5, edge6, edge7, edge8, edge9, edge10, edge11, edge12, edge13, edge14, edge15, edge16) + +algorithm = Bellman_Ford() +algorithm.calculate_shortest_path(edgeList, vertexList, node1) +algorithm.get_shortest_path(node7) \ No newline at end of file diff --git a/Graph Algorithms/Breadth First Search.py b/Graph Algorithms/Breadth First Search.py new file mode 100644 index 0000000..82a25a3 --- /dev/null +++ b/Graph Algorithms/Breadth First Search.py @@ -0,0 +1,50 @@ +class Node(object): + def __init__(self, name): + # This will store the data of the node + self.name = name + # This is the neighbours of the node + self.adjacencyList = [] + # We create a boolean to check the node is visited or not + self.visited = False + # Should ask + self.predecessor = None + + +class BreadthFirstSearch(object): + def bfs(self, start_node): + # We create a queue with the starting node + queue = [start_node] + # We set that the given node is visited + start_node.visited = True + # We iterate through the queue until it's not empty + while queue: + # We get the first item in the queue -> FIFO structure + actual_node = queue.pop(0) + # We print it out + print(actual_node.name) + # We iterate through the neighbours and visit them also adding them to the queue + for node in actual_node.adjacencyList: + if not node.visited: + node.visited = True + queue.append(node) + + +n1 = Node("A") +n2 = Node("B") +n3 = Node("C") +n4 = Node("D") +n5 = Node("E") +n6 = Node("F") +n7 = Node("G") +n8 = Node("H") + +n1.adjacencyList.append(n2) +n1.adjacencyList.append(n3) +n2.adjacencyList.append(n4) +n2.adjacencyList.append(n5) +n1.adjacencyList.append(n6) +n3.adjacencyList.append(n7) +n4.adjacencyList.append(n8) + +bfs = BreadthFirstSearch() +bfs.bfs(n1) diff --git a/Graph Algorithms/CycleDetection.cpp b/Graph Algorithms/CycleDetection.cpp new file mode 100644 index 0000000..43def40 --- /dev/null +++ b/Graph Algorithms/CycleDetection.cpp @@ -0,0 +1,81 @@ +#include + +using namespace std; + +// 0-> unvisited +// 1-> processing +// 2-> exited +vector visited; +bool found = false; +vector ans; +vector curStack; + +void DFS(vector graph[], int node){ + if (visited[node] != 0) return; + + visited[node] = 1; + curStack.push_back(node); + + for (int neighbour: graph[node]){ + if (visited[neighbour] == 1){ + // Found a cycle + found = true; + ans.push_back(neighbour); + while (curStack.back() != neighbour){ + ans.push_back(curStack.back()); + curStack.pop_back(); + } + ans.push_back(neighbour); + reverse(ans.begin(), ans.end()); + return; + } + + else if (visited[neighbour] == 0){ + DFS(graph, neighbour); + } + if (found) return; + } + + curStack.pop_back(); + visited[node] = 2; // Done processing +} + +void solve(vector graph[], int n){ + for (int i=0; i> n >> m; + + vector graph[n]; + visited.resize(n+1); + fill(visited.begin(), visited.end(), false); + + while (m--){ + int u, v; + cin >> u >> v; + u--; v--; + graph[u].push_back(v); + } + solve(graph, n); + + + return 0; +} \ No newline at end of file diff --git a/Graph Algorithms/Depth First Search.py b/Graph Algorithms/Depth First Search.py new file mode 100644 index 0000000..ed0faa0 --- /dev/null +++ b/Graph Algorithms/Depth First Search.py @@ -0,0 +1,42 @@ +class Node(object): + def __init__(self, name): + self.name = name + self.adjacencyList = [] + self.visited = False + self.predecessor = None + + +class DepthFirstSearch(object): + # This is the recursive solution + def dfs(self, node): + # We set the node to be visited + node.visited = True + # We print it + print(node.name) + # Then we iterate through the neighbour list + for n in node.adjacencyList: + # If it is not visited we call the function recursively + if not n.visited: + # We don't return so it will iterate fully + self.dfs(n) + + +n1 = Node("A") +n2 = Node("B") +n3 = Node("C") +n4 = Node("D") +n5 = Node("E") +n6 = Node("F") +n7 = Node("G") +n8 = Node("H") + +n1.adjacencyList.append(n2) +n1.adjacencyList.append(n3) +n2.adjacencyList.append(n4) +n2.adjacencyList.append(n5) +n1.adjacencyList.append(n6) +n3.adjacencyList.append(n7) +n4.adjacencyList.append(n8) + +dfs = DepthFirstSearch() +dfs.dfs(n1) diff --git a/Graph Algorithms/Dijkstra's Shortest Path algorithm.py b/Graph Algorithms/Dijkstra's Shortest Path algorithm.py new file mode 100644 index 0000000..0a33fbe --- /dev/null +++ b/Graph Algorithms/Dijkstra's Shortest Path algorithm.py @@ -0,0 +1,133 @@ +import sys +import heapq + + +class Edge(object): + # This is the class for every edge in the tree + def __init__(self, weight, startVertex, targetVertex): + # Each edge has a weight + self.weight = weight + # There is starting vertex + self.startVertex = startVertex + # There is also an ending vertex + self.targetVertex = targetVertex + + +class Node(object): + # We define our node class + def __init__(self, name): + self.name = name + self.visited = False + # This is the neighbours list + self.adjacencyList = [] + # This is the predecessor of the node So that we can back track and find the shortest path + self.predecessor = None + # We define the minimum distance to be infinity + # The sys.maxsize gives the infinity value + # We set this up to all other nodes + self.minDistance = sys.maxsize + + # This is the comparator of the node function + def __cmp__(self, otherVertex): + # We are pushing the the nodes into the heap + # So we have to set it in what basis we are going to push them + # We push them with the minimum distance as the priority value + return self.cmp(self.minDistance, otherVertex.minDistance) + + # This is the less than function + def __lt__(self, other): + # We have to define in what basis we are going to order the nodes + # We define them with the min Distance + self_priority = self.minDistance + other_priority = other.minDistance + # We will return a boolean + return self_priority < other_priority + + +class Algorithm(object): + # This algorithm sets the shortest path for the given graph + def shortest_path(self, vertexList, startVertex): + # We create priority queue as an one dimensional array + q = [] + # We set the starting node's distance to 0 + startVertex.minDistance = 0 + # We will push the starting vertex to the queue + heapq.heappush(q, startVertex) + # We will iterate throughout the queue while it's empty + while len(q) > 0: + # We take out the minimum distance node + actual_vertex = heapq.heappop(q) + # We iterate throughout the neighbours of the list + for edge in actual_vertex.adjacencyList: + u = edge.startVertex + v = edge.targetVertex + # We calculate the distance by adding the node's distance with the edge's weight + temp_distance = u.minDistance + edge.weight + # We check if the calculated distance is less than the node's distance + if temp_distance < v.minDistance: + # We set the predecessor and the minDistance + v.predecessor = u + v.minDistance = temp_distance + # Finally we push it to the heap + heapq.heappush(q, v) + + def get_shortest_path(self, targetVertex): + # We print out the vertex we are looking for + print("Shortest path to vertex {} is {}".format(targetVertex.name, targetVertex.minDistance)) + # We set the node to be the target and we backtrack + node = targetVertex + while node is not None: + print(node.name) + # We increment it by setting it to its predecessor + node = node.predecessor + + +node1 = Node("A") +node2 = Node("B") +node3 = Node("C") +node4 = Node("D") +node5 = Node("E") +node6 = Node("F") +node7 = Node("G") +node8 = Node("H") + +edge1 = Edge(5, node1, node2) +edge2 = Edge(8, node1, node8) +edge3 = Edge(9, node1, node5) +edge4 = Edge(15, node2, node4) +edge5 = Edge(12, node2, node3) +edge6 = Edge(4, node2, node8) +edge7 = Edge(7, node8, node3) +edge8 = Edge(6, node8, node6) +edge9 = Edge(5, node5, node8) +edge10 = Edge(4, node5, node6) +edge11 = Edge(20, node5, node7) +edge12 = Edge(1, node6, node3) +edge13 = Edge(13, node6, node7) +edge14 = Edge(3, node3, node4) +edge15 = Edge(11, node3, node7) +edge16 = Edge(9, node4, node7) + +node1.adjacencyList.append(edge1) +node1.adjacencyList.append(edge2) +node1.adjacencyList.append(edge3) +node2.adjacencyList.append(edge4) +node2.adjacencyList.append(edge5) +node2.adjacencyList.append(edge6) +node8.adjacencyList.append(edge7) +node8.adjacencyList.append(edge8) +node5.adjacencyList.append(edge9) +node5.adjacencyList.append(edge10) +node5.adjacencyList.append(edge11) +node6.adjacencyList.append(edge12) +node6.adjacencyList.append(edge13) +node3.adjacencyList.append(edge14) +node3.adjacencyList.append(edge15) +node4.adjacencyList.append(edge16) + + +vertexList = (node1, node2, node3, node4, node5, node6, node7, node8) + +algorithm = Algorithm() +algorithm.shortest_path(vertexList, node1) +algorithm.get_shortest_path(node4) diff --git a/Graph Algorithms/Krusakal's MST Algorithm.py b/Graph Algorithms/Krusakal's MST Algorithm.py new file mode 100644 index 0000000..4feaeca --- /dev/null +++ b/Graph Algorithms/Krusakal's MST Algorithm.py @@ -0,0 +1,160 @@ +class Vertex(object): + # This is the vertex class + def __init__(self, name): + # We define the name and the node which the vertex is in + self.name = name + self.node = None + + +class Node(object): + # We have the nodeId(representative value), height, parent node to backtrack + def __init__(self, height, nodeId, parentNode): + self.height = height + self.nodeId = nodeId + self.parentNode = parentNode + + +class Edge(object): + # Every edge will have weight, starting vertex and a target vertex + def __init__(self, weight, startingVertex, targetVertex): + self.weight = weight + self.startVertex = startingVertex + self.targetVertex = targetVertex + + # We use the comparator function to compare the edges with their weights + def __cmp__(self, other): + return self.cmp(self.weight, other.weight) + + # This less than method is defined to compare the edges and returns a boolean + # if self weight is less than the other weight + def __lt__(self, other): + selfPriority = self.weight + otherPriority = other.weight + return selfPriority < otherPriority + + +class DisjointSets(object): + # We define the parameters + def __init__(self, vertexList): + self.vertexList = vertexList + self.rootNodes = [] + self.setCount = 0 + self.nodeCount = 0 + self.makeSets(vertexList) + + def find(self, node): + # We get the node to the current node + currentNode = node + # We loop through the tree until we find the root node + while currentNode.parentNode is not None: + currentNode = currentNode.parentNode + # we set the root and the current node to the node we are looking for + root = currentNode + currentNode = node + # We make the current node to be the child of the root node + # We swap the values + while currentNode is not root: + temp = currentNode.parentNode + currentNode.parentNode = root + currentNode = temp + # Finally we return the node Id of the root node + return root.nodeId + + def merge(self, node1, node2): + index1 = self.find(node1) + index2 = self.find(node2) + # if both the indices are equal we know that they are in the same subset + if index1 == index2: + return + + root1 = self.rootNodes[index1] + root2 = self.rootNodes[index2] + # Case 1: the rank of the root 1 is less than the root 2 + # So the parent will be root2 + if root1.height < root2.height: + root1.parentNode = root2 + # Case 2: the rank of the root 1 greater than the root 1 + # So the parent of the root 2 is root 1 + elif root1.height > root2.height: + root2.parentNode = root1 + # We know the heights are the same + # So we can assign the root to be either root1 or root2 + else: + root2.parentNode = root1 + # We increment the height of the current root node + root1.height += 1 + + def makeSets(self, vertexList): + # We iterate through the vertex list and call the function makeSet + for v in vertexList: + self.makeSet(v) + + def makeSet(self, vertex): + # We create a node + node = Node(0, len(self.rootNodes), None) + # We assign the vertex node to be node + vertex.node = node + # We get the disjoint nodes in the root nodes + self.rootNodes.append(node) + # We increment the node and the set counts + self.nodeCount += 1 + self.setCount += 1 + + +class kruskalAlgorithm(object): + def spanning_tree(self, vertexList, edgeList): + # First we define the disjoint set by passing the vertex list + # By the above function each vertices are going to be a disjoint set + disjointset = DisjointSets(vertexList) + # We have the spanning tree array + # We will append the edges to this tree + spanningTree = [] + # We can call the sort method here because we have already defined the comparator and less than method + # To consider its weight + edgeList.sort() + # We shall iterate through the list + for edge in edgeList: + # We assign the starting vertex and the target vertex to these parameters + u = edge.startVertex + v = edge.targetVertex + # Here we check whether those two nodes are in the same set or not + # This will return the nodeId which is the representative of the set + if disjointset.find(u.node) is not disjointset.find(v.node): + # if the following condition satisfies we append them to our spanning tree + spanningTree.append(edge) + # Also we will merge them together + disjointset.merge(u.node, v.node) + print("Minimum Spanning Tree order") + weight = 0 + for edge in spanningTree: + print("{} - {}, weight = {}".format(edge.startVertex.name, edge.targetVertex.name, edge.weight)) + weight += edge.weight + print("The weight of the MST is ", weight) + + +vertex1 = Vertex("a") +vertex2 = Vertex("b") +vertex3 = Vertex("c") +vertex4 = Vertex("d") +vertex5 = Vertex("e") +vertex6 = Vertex("f") +vertex7 = Vertex("g") + +edge1 = Edge(2, vertex1, vertex2) +edge2 = Edge(6, vertex1, vertex3) +edge3 = Edge(5, vertex1, vertex5) +edge4 = Edge(10, vertex1, vertex6) +edge5 = Edge(3, vertex2, vertex4) +edge6 = Edge(3, vertex2, vertex5) +edge7 = Edge(1, vertex3, vertex4) +edge8 = Edge(2, vertex3, vertex6) +edge9 = Edge(4, vertex4, vertex5) +edge10 = Edge(5, vertex4, vertex7) +edge11 = Edge(5, vertex6, vertex7) + +vertexList = [vertex1, vertex2, vertex3, vertex4, vertex5, vertex6, vertex7] + +edgeList = [edge1, edge2, edge3, edge4, edge5, edge6, edge7, edge8, edge9, edge10, edge11] + +algorithm = kruskalAlgorithm() +algorithm.spanning_tree(vertexList, edgeList) \ No newline at end of file diff --git a/Graph Algorithms/Prims-Jarnik Algorithm MST.py b/Graph Algorithms/Prims-Jarnik Algorithm MST.py new file mode 100644 index 0000000..2d9106c --- /dev/null +++ b/Graph Algorithms/Prims-Jarnik Algorithm MST.py @@ -0,0 +1,131 @@ +import heapq + + +class Vertex(object): + def __init__(self, name): + self.name = name + self.adjacencyList = [] + self.visited = False + + # We define this method to return the name of the vertex whenever we call them + def __str__(self): + return self.name + + +class Edge(object): + def __init__(self, weight, startVertex, targetVertex): + self.weight = weight + self.targetVertex = targetVertex + self.startVertex = startVertex + + # This is the method helps python to understand how do we compare each edge + def __lt__(self, other): + selfPriority = self.weight + otherPriority = other.weight + return selfPriority < otherPriority + +class PrimsJarnik(object): + def __init__(self, unvisitedList): + # We will have an unvisited list so that we can check nodes + # This contains all the nodes + self.unvisitedList = unvisitedList + # We define the spanning tree + self.spanningTree = [] + # The weight of the MST + self.fullCost = 0 + # This is the heap for edge + self.edgeHeap = [] + + def CaculateSpanningTree(self, vertex): + # First we remove the vertex from the unvisited list + self.unvisitedList.remove(vertex) + # We visit all the other nodes while the list is not empty + while self.unvisitedList: + # We iterate all through the neighbours of the vertex + for edge in vertex.adjacencyList: + # We check if the edge is unvisited + if edge.targetVertex in self.unvisitedList: + # We push it to the heap + heapq.heappush(self.edgeHeap, edge) + # We get the minimum edge in the minEdge + minEdge = heapq.heappop(self.edgeHeap) + # if the target of the min edge is in the unvisited list + if minEdge.targetVertex in self.unvisitedList: + # We append the edge to the MST + self.spanningTree.append(minEdge) + # We print it out just for our verification of what are the added edges + print("Edge added to the spanning tree {} - {}".format(minEdge.startVertex, minEdge.targetVertex)) + # We increment the weight + self.fullCost += minEdge.weight + # We set the vertex to be the min edge's target vertex + # We will visit that vertex and append the rest of the edges to the heap + vertex = minEdge.targetVertex + # Finally we remove the visited vertex from the unvisited list + self.unvisitedList.remove(vertex) + + def getSpanningTree(self): + return self.spanningTree + + def getCost(self): + return self.fullCost + + +vertexA = Vertex("A") +vertexB = Vertex("B") +vertexC = Vertex("C") +vertexD = Vertex("D") +vertexE = Vertex("E") +vertexF = Vertex("F") +vertexG = Vertex("G") + +edgeAB = Edge(2, vertexA, vertexB) +edgeBA = Edge(2, vertexB, vertexA) +edgeAE = Edge(5, vertexA, vertexE) +edgeEA = Edge(5, vertexE, vertexA) +edgeAC = Edge(6, vertexA, vertexC) +edgeCA = Edge(6, vertexC, vertexA) +edgeAF = Edge(10, vertexA, vertexF) +edgeFA = Edge(10, vertexF, vertexA) +edgeBE = Edge(3, vertexB, vertexE) +edgeEB = Edge(3, vertexE, vertexB) +edgeBD = Edge(3, vertexB, vertexD) +edgeDB = Edge(3, vertexD, vertexB) +edgeCD = Edge(1, vertexC, vertexD) +edgeDC = Edge(1, vertexD, vertexC) +edgeCF = Edge(2, vertexC, vertexF) +edgeFC = Edge(2, vertexF, vertexC) +edgeDE = Edge(4, vertexD, vertexE) +edgeED = Edge(4, vertexE, vertexD) +edgeDG = Edge(5, vertexD, vertexG) +edgeGD = Edge(5, vertexG, vertexD) +edgeFG = Edge(3, vertexF, vertexG) +edgeGF = Edge(3, vertexG, vertexF) + +unvisitedList = [vertexA, vertexB, vertexC, vertexD, vertexE, vertexF, vertexG] + +vertexA.adjacencyList.append(edgeAB) +vertexA.adjacencyList.append(edgeAC) +vertexA.adjacencyList.append(edgeAE) +vertexA.adjacencyList.append(edgeAF) +vertexB.adjacencyList.append(edgeBA) +vertexB.adjacencyList.append(edgeBD) +vertexB.adjacencyList.append(edgeBE) +vertexC.adjacencyList.append(edgeCA) +vertexC.adjacencyList.append(edgeCD) +vertexC.adjacencyList.append(edgeCF) +vertexD.adjacencyList.append(edgeDB) +vertexD.adjacencyList.append(edgeDC) +vertexD.adjacencyList.append(edgeDE) +vertexD.adjacencyList.append(edgeDG) +vertexE.adjacencyList.append(edgeEA) +vertexE.adjacencyList.append(edgeEB) +vertexE.adjacencyList.append(edgeED) +vertexF.adjacencyList.append(edgeFA) +vertexF.adjacencyList.append(edgeFC) +vertexF.adjacencyList.append(edgeFG) +vertexG.adjacencyList.append(edgeGD) +vertexG.adjacencyList.append(edgeGF) + +algorithm = PrimsJarnik(unvisitedList) +algorithm.CaculateSpanningTree(vertexD) +print(algorithm.getCost()) diff --git a/Graph Algorithms/TopologicalOrder.cpp b/Graph Algorithms/TopologicalOrder.cpp new file mode 100644 index 0000000..728da8f --- /dev/null +++ b/Graph Algorithms/TopologicalOrder.cpp @@ -0,0 +1,59 @@ +/* +Topological ordering => + an ordering of each nodes in a directed graph where for each directed edge + from node A to node B, node A appears before the node B in the ordering + +Topological Sort => + Algorithm to find a topological ordering in O(V + E) time. + Topological ordering is not unique + +ONLY DIRECTED ACYCLIC GRAPHS ONLY HAVE A VALID TOPOLOGICAL ORDERING +*/ + +#include + +using namespace std; + +stack topoOrder; +vector visited; + +void topologicalSort(vector graph[], int src){ + + visited[src] = true; + for (int neighbour: graph[src]){ + if (!visited[neighbour]) + topologicalSort(graph, neighbour); + } + + topoOrder.push(src); +} + +int main(){ + int n, m; + cin >> n >> m; + + vector graph[n]; + visited.resize(n, 0); + + while (m--){ + int u, v; + cin >> u >> v; + u--; + v--; + graph[u].push_back(v); + } + + for (int node=0; node + +using namespace std; + +const int size = 4; +int board[size][size] = {0}; + +void printBoard(){ + // Output the state of the board + for (int i=0; i=0 && j=0; i++, j--){ + if (board[i][j] == 1) { + cout << "4" << endl; + return false; + } + } + + // Check if there is a qeen in the upper left diagonal + for (int i=row, j=col; i>=0 && j>=0; i--, j--){ + if (board[i][j] == 1) { + cout << "5" << endl; + return false; + } + } + + // Check if there is a qeen in the lower left diagonal + for (int i=row, j=col; i +#include +#include +#include +#include + +using namespace std; + +int factorial(int n){ + if (n < 0) return -1; + if (n==1 or n==0) return 1; + return n * factorial(n-1); +} + +int factorialIter(int n){ + if (n < 0) return -1; + int ans = 1; + while (n > 1){ + ans *= n; + n--; + } + return ans; +} + +int fibonacci(int a, int b, int n){ + if (n == 0) return a; + if (n == 1) return b; + return fibonacci(b, a+b, n-1); +} + +void fibonacciIter(int n){ + int fib[n]; + fib[0] = 0; + fib[1] = 0; + for (int i=2; i right) return -1; + int mid = (left + right)/2; + + if (arr[mid] == val) return mid; + else if (arr[mid] < val){ + return binarySearch(mid+1, right, arr, val); + } + else{ + return binarySearch(left, mid-1, arr, val); + } +} + +int binarySearchIter(int arr[], int val, int n){ + int left = 0, right = n-1; + while (left <= right){ + int mid = (left+right)/2; + if (arr[mid] == val){ + return mid; + } + else if (arr[mid] < val){ + left = mid + 1; + } + else{ + right = mid - 1; + } + } + return -1; +} + +int fastExp(int a, int b){ + if (b == 0) return 1; + + int p = fastExp(a, b/2); + if (b & 1) return p*p*a; + return p*p; +} + +int exponentiation(int a, int b){ + if (b == 0) return 1; + return a * exponentiation(a, b-1); +} + +int numberOfZeros(int number){ + if (number == 0) return 1; + if (number < 10 && number > -10) return 0; + + // number/10 -> The recursive case for the rest of the digits + // number%10 -> The recursive case for the current digit + return numberOfZeros(number/10) + numberOfZeros(number%10); +} + +// bool isPalindrome(const char* const s){ +// if (strlen(s) <= 1) return true; + +// else if (s[0] == s[strlen(s)-1]){ +// return isPalindrome(substring(s, 1, strlen(s)-2)); +// } +// return false; +// } + +bool isPalindrome(string s){ + if (s.length() <= 1) return true; + + int l = s.length(); + + if (s[0] == s[l-1]){ + return isPalindrome(s.substr(1, l-2)); + } + + return false; +} + + +int main(){ + // for (int i=0; i<10; i++){ + // int ans = fibonacci(0, 1, i); + // cout << ans << " "; + // } + // cout << endl; + + // int arr[5] = {1, 3, 5, 8, 9}; + // int ans = binarySearchIter(arr, 8, 5); + // cout << ans << endl; + + // cout << numberOfZeros(10002300) << endl; + + cout << isPalindrome("apple") << endl; + return 0; +} \ No newline at end of file diff --git a/Recursion Problems/TowersOfHanoi.cpp b/Recursion Problems/TowersOfHanoi.cpp new file mode 100644 index 0000000..bd74eb9 --- /dev/null +++ b/Recursion Problems/TowersOfHanoi.cpp @@ -0,0 +1,23 @@ +#include + +using namespace std; + +void TowersOfHanoi(int Stand_from, int Stand_mid, int Stand_to, int diskNum){ + // Base case: Only one disk + if (diskNum == 1){ + cout << "Move disk " << diskNum << " from stand " << Stand_from << " to stand " << Stand_to << endl; + return; + } + // Move the current disk to the spare stand + TowersOfHanoi(Stand_from, Stand_to, Stand_mid, diskNum-1); + + cout << "Move disk " << diskNum << " from stand " << Stand_from << " to stand " << Stand_to << endl; + // Move the disk from the spare stand to the required stand + TowersOfHanoi(Stand_mid, Stand_from, Stand_to, diskNum-1); +} + + +int main(){ + TowersOfHanoi(1, 2, 3, 3); + return 0; +} \ No newline at end of file