{"id":6144,"date":"2025-01-05T20:16:59","date_gmt":"2025-01-05T20:16:59","guid":{"rendered":"https:\/\/algocademy.com\/blog\/mastering-graph-cycle-problems-essential-techniques-for-coding-interviews\/"},"modified":"2025-01-05T20:16:59","modified_gmt":"2025-01-05T20:16:59","slug":"mastering-graph-cycle-problems-essential-techniques-for-coding-interviews","status":"publish","type":"post","link":"https:\/\/algocademy.com\/blog\/mastering-graph-cycle-problems-essential-techniques-for-coding-interviews\/","title":{"rendered":"Mastering Graph Cycle Problems: Essential Techniques for Coding Interviews"},"content":{"rendered":"<p><!DOCTYPE html PUBLIC \"-\/\/W3C\/\/DTD HTML 4.0 Transitional\/\/EN\" \"http:\/\/www.w3.org\/TR\/REC-html40\/loose.dtd\"><br \/>\n<html><body><\/p>\n<article>\n<p>Welcome to another in-depth tutorial from AlgoCademy! Today, we&#8217;re diving into an essential topic for coding interviews and algorithmic problem-solving: techniques for solving graph cycle problems. Whether you&#8217;re preparing for a technical interview at a FAANG company or simply looking to enhance your programming skills, understanding how to detect and manipulate cycles in graphs is crucial.<\/p>\n<p>Graphs are versatile data structures that can represent a wide variety of real-world scenarios, from social networks to computer networks, from road systems to dependency relationships in software. Cycles in graphs often represent important patterns or issues that need to be identified and addressed. In this comprehensive guide, we&#8217;ll explore various techniques to tackle graph cycle problems, providing you with the tools you need to excel in your coding interviews and beyond.<\/p>\n<h2>Table of Contents<\/h2>\n<ol>\n<li><a href=\"#introduction\">Introduction to Graph Cycles<\/a><\/li>\n<li><a href=\"#dfs\">Depth-First Search (DFS) for Cycle Detection<\/a><\/li>\n<li><a href=\"#bfs\">Breadth-First Search (BFS) for Cycle Detection<\/a><\/li>\n<li><a href=\"#union-find\">Union-Find (Disjoint Set) Method<\/a><\/li>\n<li><a href=\"#topological-sort\">Topological Sort for Cycle Detection in Directed Graphs<\/a><\/li>\n<li><a href=\"#floyd\">Floyd&#8217;s Cycle-Finding Algorithm<\/a><\/li>\n<li><a href=\"#coloring\">Graph Coloring Method<\/a><\/li>\n<li><a href=\"#advanced\">Advanced Techniques and Optimizations<\/a><\/li>\n<li><a href=\"#practice\">Practice Problems and Solutions<\/a><\/li>\n<li><a href=\"#conclusion\">Conclusion and Next Steps<\/a><\/li>\n<\/ol>\n<h2 id=\"introduction\">1. Introduction to Graph Cycles<\/h2>\n<p>Before we dive into the techniques, let&#8217;s establish a solid understanding of what graph cycles are and why they&#8217;re important.<\/p>\n<h3>What is a Graph Cycle?<\/h3>\n<p>A cycle in a graph is a path that starts and ends at the same vertex, without repeating any edges. In other words, it&#8217;s a closed loop in the graph structure. Cycles can occur in both directed and undirected graphs, though their properties and detection methods may differ.<\/p>\n<h3>Why are Graph Cycles Important?<\/h3>\n<p>Detecting and analyzing cycles in graphs is crucial for various reasons:<\/p>\n<ul>\n<li>In dependency graphs, cycles can indicate circular dependencies, which are often problematic in software design.<\/li>\n<li>In network topologies, cycles provide alternative routes, which can be important for reliability and load balancing.<\/li>\n<li>In scheduling problems, cycles may represent deadlock situations or impossible schedules.<\/li>\n<li>In social network analysis, cycles can reveal interesting relationship patterns.<\/li>\n<\/ul>\n<p>Now that we understand the importance of graph cycles, let&#8217;s explore the various techniques to detect and work with them.<\/p>\n<h2 id=\"dfs\">2. Depth-First Search (DFS) for Cycle Detection<\/h2>\n<p>Depth-First Search is one of the most fundamental and versatile algorithms for graph traversal and cycle detection. It&#8217;s particularly effective for detecting cycles in both directed and undirected graphs.<\/p>\n<h3>How DFS Works for Cycle Detection<\/h3>\n<p>The basic idea behind using DFS for cycle detection is to keep track of vertices currently in the recursion stack. If we encounter a vertex that is already in the recursion stack, we have found a cycle.<\/p>\n<h3>Implementation for Undirected Graphs<\/h3>\n<p>Here&#8217;s a Python implementation for detecting cycles in an undirected graph using DFS:<\/p>\n<pre><code>def has_cycle(graph):\n    visited = set()\n    \n    def dfs(vertex, parent):\n        visited.add(vertex)\n        for neighbor in graph[vertex]:\n            if neighbor not in visited:\n                if dfs(neighbor, vertex):\n                    return True\n            elif neighbor != parent:\n                return True\n        return False\n    \n    for vertex in graph:\n        if vertex not in visited:\n            if dfs(vertex, None):\n                return True\n    return False\n\n# Example usage\ngraph = {\n    0: [1, 2],\n    1: [0, 2],\n    2: [0, 1, 3],\n    3: [2]\n}\n\nprint(has_cycle(graph))  # Output: True<\/code><\/pre>\n<h3>Implementation for Directed Graphs<\/h3>\n<p>For directed graphs, we need to modify our approach slightly. Instead of just keeping track of visited nodes, we also need to track nodes in the current recursion stack:<\/p>\n<pre><code>def has_cycle_directed(graph):\n    visited = set()\n    rec_stack = set()\n    \n    def dfs(vertex):\n        visited.add(vertex)\n        rec_stack.add(vertex)\n        \n        for neighbor in graph[vertex]:\n            if neighbor not in visited:\n                if dfs(neighbor):\n                    return True\n            elif neighbor in rec_stack:\n                return True\n        \n        rec_stack.remove(vertex)\n        return False\n    \n    for vertex in graph:\n        if vertex not in visited:\n            if dfs(vertex):\n                return True\n    return False\n\n# Example usage\ndirected_graph = {\n    0: [1, 2],\n    1: [2],\n    2: [3],\n    3: [1]\n}\n\nprint(has_cycle_directed(directed_graph))  # Output: True<\/code><\/pre>\n<h3>Time and Space Complexity<\/h3>\n<p>The time complexity of DFS-based cycle detection is O(V + E), where V is the number of vertices and E is the number of edges in the graph. This is because we visit each vertex and edge once. The space complexity is O(V) to store the visited set and the recursion stack.<\/p>\n<h2 id=\"bfs\">3. Breadth-First Search (BFS) for Cycle Detection<\/h2>\n<p>While Depth-First Search is often the go-to method for cycle detection, Breadth-First Search can also be used, particularly in scenarios where you want to find the shortest cycle or when working with very large graphs where the recursion depth of DFS might be a concern.<\/p>\n<h3>BFS Approach for Cycle Detection<\/h3>\n<p>The BFS approach for cycle detection involves keeping track of the parent of each node as we traverse the graph. If we encounter a node that has already been visited and it&#8217;s not the parent of the current node, we&#8217;ve found a cycle.<\/p>\n<h3>Implementation for Undirected Graphs<\/h3>\n<p>Here&#8217;s a Python implementation using BFS to detect cycles in an undirected graph:<\/p>\n<pre><code>from collections import deque\n\ndef has_cycle_bfs(graph):\n    visited = set()\n    \n    for start_vertex in graph:\n        if start_vertex not in visited:\n            queue = deque([(start_vertex, None)])\n            \n            while queue:\n                vertex, parent = queue.popleft()\n                visited.add(vertex)\n                \n                for neighbor in graph[vertex]:\n                    if neighbor not in visited:\n                        queue.append((neighbor, vertex))\n                    elif neighbor != parent:\n                        return True\n    \n    return False\n\n# Example usage\ngraph = {\n    0: [1, 2],\n    1: [0, 2],\n    2: [0, 1, 3],\n    3: [2]\n}\n\nprint(has_cycle_bfs(graph))  # Output: True<\/code><\/pre>\n<h3>Advantages and Disadvantages of BFS<\/h3>\n<p>Advantages of using BFS for cycle detection:<\/p>\n<ul>\n<li>It can find the shortest cycle in an unweighted graph.<\/li>\n<li>It&#8217;s useful for graphs where DFS might exceed the maximum recursion depth.<\/li>\n<li>It can be more intuitive for some problems, especially those involving shortest paths.<\/li>\n<\/ul>\n<p>Disadvantages:<\/p>\n<ul>\n<li>It typically uses more memory than DFS due to the queue.<\/li>\n<li>It may be less efficient for sparse graphs.<\/li>\n<\/ul>\n<h3>Time and Space Complexity<\/h3>\n<p>The time complexity of BFS-based cycle detection is O(V + E), the same as DFS. The space complexity is O(V) to store the visited set and the queue.<\/p>\n<h2 id=\"union-find\">4. Union-Find (Disjoint Set) Method<\/h2>\n<p>The Union-Find data structure, also known as a disjoint set data structure, is particularly useful for detecting cycles in undirected graphs. This method is especially efficient when you&#8217;re adding edges to the graph one by one and want to check if each new edge creates a cycle.<\/p>\n<h3>How Union-Find Works for Cycle Detection<\/h3>\n<p>The basic idea is to maintain disjoint sets of vertices. When we add an edge, we check if the vertices it connects are already in the same set. If they are, adding this edge would create a cycle. If not, we union the sets containing these vertices.<\/p>\n<h3>Implementation<\/h3>\n<p>Here&#8217;s a Python implementation of cycle detection using Union-Find:<\/p>\n<pre><code>class UnionFind:\n    def __init__(self, n):\n        self.parent = list(range(n))\n        self.rank = [0] * n\n    \n    def find(self, item):\n        if self.parent[item] != item:\n            self.parent[item] = self.find(self.parent[item])\n        return self.parent[item]\n    \n    def union(self, x, y):\n        xroot = self.find(x)\n        yroot = self.find(y)\n        \n        if self.rank[xroot] &lt; self.rank[yroot]:\n            self.parent[xroot] = yroot\n        elif self.rank[xroot] &gt; self.rank[yroot]:\n            self.parent[yroot] = xroot\n        else:\n            self.parent[yroot] = xroot\n            self.rank[xroot] += 1\n\ndef has_cycle_union_find(n, edges):\n    uf = UnionFind(n)\n    \n    for x, y in edges:\n        if uf.find(x) == uf.find(y):\n            return True\n        uf.union(x, y)\n    \n    return False\n\n# Example usage\nn = 4\nedges = [(0, 1), (1, 2), (2, 3), (3, 1)]\nprint(has_cycle_union_find(n, edges))  # Output: True<\/code><\/pre>\n<h3>Advantages of Union-Find<\/h3>\n<ul>\n<li>Very efficient for graphs that are being built incrementally.<\/li>\n<li>Can handle dynamic graphs where edges are being added or removed.<\/li>\n<li>With path compression and union by rank, operations are nearly constant time.<\/li>\n<\/ul>\n<h3>Time and Space Complexity<\/h3>\n<p>With path compression and union by rank optimizations, the amortized time complexity for each operation (find and union) is nearly O(1). For a graph with V vertices and E edges, the overall time complexity is O(E &Icirc;&plusmn;(V)), where &Icirc;&plusmn;(V) is the inverse Ackermann function, which grows very slowly and is effectively constant for all practical values of V. The space complexity is O(V) to store the parent and rank arrays.<\/p>\n<h2 id=\"topological-sort\">5. Topological Sort for Cycle Detection in Directed Graphs<\/h2>\n<p>Topological sorting is an algorithm for ordering the vertices of a directed acyclic graph (DAG) such that for every directed edge (u, v), vertex u comes before v in the ordering. This property makes topological sort particularly useful for detecting cycles in directed graphs.<\/p>\n<h3>How Topological Sort Detects Cycles<\/h3>\n<p>The key insight is that a directed graph has a valid topological ordering if and only if it is acyclic. Therefore, if we attempt to perform a topological sort and find that it&#8217;s not possible to complete it, we know the graph contains a cycle.<\/p>\n<h3>Implementation Using Kahn&#8217;s Algorithm<\/h3>\n<p>Here&#8217;s an implementation of cycle detection using Kahn&#8217;s algorithm for topological sorting:<\/p>\n<pre><code>from collections import deque\n\ndef has_cycle_topological_sort(graph):\n    in_degree = {node: 0 for node in graph}\n    for node in graph:\n        for neighbor in graph[node]:\n            in_degree[neighbor] += 1\n    \n    queue = deque([node for node in graph if in_degree[node] == 0])\n    visited_count = 0\n    \n    while queue:\n        node = queue.popleft()\n        visited_count += 1\n        \n        for neighbor in graph[node]:\n            in_degree[neighbor] -= 1\n            if in_degree[neighbor] == 0:\n                queue.append(neighbor)\n    \n    return visited_count != len(graph)\n\n# Example usage\ngraph = {\n    0: [1, 2],\n    1: [2],\n    2: [3],\n    3: [1]\n}\n\nprint(has_cycle_topological_sort(graph))  # Output: True<\/code><\/pre>\n<h3>Advantages of Topological Sort<\/h3>\n<ul>\n<li>It can detect cycles in directed graphs efficiently.<\/li>\n<li>If there&#8217;s no cycle, it provides a valid topological ordering of the graph, which can be useful for dependency resolution and scheduling problems.<\/li>\n<li>It&#8217;s particularly useful when you need to know not just if there&#8217;s a cycle, but also a valid ordering if there isn&#8217;t one.<\/li>\n<\/ul>\n<h3>Time and Space Complexity<\/h3>\n<p>The time complexity of Kahn&#8217;s algorithm is O(V + E), where V is the number of vertices and E is the number of edges. We process each vertex and edge once. The space complexity is O(V) to store the in-degree map and the queue.<\/p>\n<h2 id=\"floyd\">6. Floyd&#8217;s Cycle-Finding Algorithm<\/h2>\n<p>Floyd&#8217;s Cycle-Finding Algorithm, also known as the &#8220;tortoise and hare&#8221; algorithm, is a pointer algorithm that uses only two pointers, moving through the sequence at different speeds. While it&#8217;s most commonly used for detecting cycles in linked lists, it can also be applied to certain types of graphs, particularly those that can be represented as a sequence.<\/p>\n<h3>How Floyd&#8217;s Algorithm Works<\/h3>\n<p>The algorithm uses two pointers, often called the &#8220;tortoise&#8221; and the &#8220;hare&#8221;. The tortoise moves one step at a time, while the hare moves two steps. If there&#8217;s a cycle, the hare will eventually catch up to the tortoise inside the cycle.<\/p>\n<h3>Implementation for a Graph Represented as a Sequence<\/h3>\n<p>Here&#8217;s an implementation of Floyd&#8217;s algorithm for a graph represented as a sequence where each index points to the next node:<\/p>\n<pre><code>def has_cycle_floyd(graph):\n    tortoise = hare = 0\n    \n    while True:\n        tortoise = graph[tortoise]\n        hare = graph[graph[hare]]\n        \n        if tortoise == hare:\n            return True\n        \n        if hare == len(graph) - 1:\n            return False\n\n# Example usage\ngraph = [1, 2, 3, 4, 2]  # Node 4 points back to node 2, creating a cycle\nprint(has_cycle_floyd(graph))  # Output: True<\/code><\/pre>\n<h3>Advantages of Floyd&#8217;s Algorithm<\/h3>\n<ul>\n<li>It uses constant extra space, making it very memory-efficient.<\/li>\n<li>It&#8217;s simple to implement and understand.<\/li>\n<li>It can detect cycles in infinite sequences without getting stuck.<\/li>\n<\/ul>\n<h3>Limitations<\/h3>\n<p>Floyd&#8217;s algorithm is primarily useful for graphs that can be represented as a sequence where each node has a single &#8220;next&#8221; node. It&#8217;s not directly applicable to general graphs with multiple edges per node.<\/p>\n<h3>Time and Space Complexity<\/h3>\n<p>The time complexity is O(n), where n is the number of nodes in the graph. In the worst case, the hare will go around the cycle twice before meeting the tortoise. The space complexity is O(1) as it only uses two pointers regardless of the input size.<\/p>\n<h2 id=\"coloring\">7. Graph Coloring Method<\/h2>\n<p>The graph coloring method is another approach to detect cycles in both directed and undirected graphs. This method assigns colors to vertices to keep track of their state during traversal.<\/p>\n<h3>How Graph Coloring Works for Cycle Detection<\/h3>\n<p>We use three colors:<\/p>\n<ul>\n<li>White: Unvisited vertices<\/li>\n<li>Gray: Vertices being visited (in the current DFS path)<\/li>\n<li>Black: Completely visited vertices<\/li>\n<\/ul>\n<p>If we encounter a gray vertex during traversal, we&#8217;ve found a cycle.<\/p>\n<h3>Implementation for Directed Graphs<\/h3>\n<pre><code>from enum import Enum\n\nclass Color(Enum):\n    WHITE = 0\n    GRAY = 1\n    BLACK = 2\n\ndef has_cycle_coloring(graph):\n    colors = {node: Color.WHITE for node in graph}\n    \n    def dfs(node):\n        colors[node] = Color.GRAY\n        \n        for neighbor in graph[node]:\n            if colors[neighbor] == Color.GRAY:\n                return True\n            if colors[neighbor] == Color.WHITE and dfs(neighbor):\n                return True\n        \n        colors[node] = Color.BLACK\n        return False\n    \n    for node in graph:\n        if colors[node] == Color.WHITE:\n            if dfs(node):\n                return True\n    \n    return False\n\n# Example usage\ngraph = {\n    0: [1, 2],\n    1: [2],\n    2: [3],\n    3: [1]\n}\n\nprint(has_cycle_coloring(graph))  # Output: True<\/code><\/pre>\n<h3>Advantages of Graph Coloring<\/h3>\n<ul>\n<li>It provides a clear visual understanding of the graph traversal process.<\/li>\n<li>It can be easily extended to solve more complex graph problems.<\/li>\n<li>It works well for both directed and undirected graphs with minimal modifications.<\/li>\n<\/ul>\n<h3>Time and Space Complexity<\/h3>\n<p>The time complexity is O(V + E), where V is the number of vertices and E is the number of edges, as we visit each vertex and edge once. The space complexity is O(V) to store the color of each vertex.<\/p>\n<h2 id=\"advanced\">8. Advanced Techniques and Optimizations<\/h2>\n<p>As you become more proficient with graph cycle problems, you&#8217;ll encounter scenarios that require more advanced techniques or optimizations. Here are a few to consider:<\/p>\n<h3>Tarjan&#8217;s Strongly Connected Components Algorithm<\/h3>\n<p>Tarjan&#8217;s algorithm can be used to find all strongly connected components in a directed graph. A directed graph with no strongly connected components of size greater than one is acyclic. This algorithm can be particularly useful when you need to identify all cycles in a directed graph.<\/p>\n<h3>Parallel and Distributed Algorithms<\/h3>\n<p>For very large graphs, parallel or distributed algorithms for cycle detection can be employed. These algorithms distribute the work across multiple processors or machines, allowing for faster processing of massive graphs.<\/p>\n<h3>Incremental Cycle Detection<\/h3>\n<p>In scenarios where the graph is dynamically changing (edges being added or removed), incremental algorithms can be more efficient than recomputing from scratch each time.<\/p>\n<h3>Memory-Efficient Techniques<\/h3>\n<p>For graphs that are too large to fit entirely in memory, external memory algorithms or streaming algorithms can be used to detect cycles while minimizing memory usage.<\/p>\n<h2 id=\"practice\">9. Practice Problems and Solutions<\/h2>\n<p>To reinforce your understanding of graph cycle detection techniques, here are some practice problems along with their solutions:<\/p>\n<h3>Problem 1: Detect Cycle in a Directed Graph<\/h3>\n<p>Given a directed graph, determine if it contains a cycle.<\/p>\n<p>Solution:<\/p>\n<pre><code>def has_cycle_directed(graph):\n    visited = set()\n    rec_stack = set()\n    \n    def dfs(node):\n        visited.add(node)\n        rec_stack.add(node)\n        \n        for neighbor in graph[node]:\n            if neighbor not in visited:\n                if dfs(neighbor):\n                    return True\n            elif neighbor in rec_stack:\n                return True\n        \n        rec_stack.remove(node)\n        return False\n    \n    for node in graph:\n        if node not in visited:\n            if dfs(node):\n                return True\n    \n    return False\n\n# Test the function\ngraph = {\n    0: [1, 2],\n    1: [2],\n    2: [3],\n    3: [1]\n}\nprint(has_cycle_directed(graph))  # Output: True<\/code><\/pre>\n<h3>Problem 2: Course Schedule<\/h3>\n<p>There are a total of n courses you have to take, labeled from 0 to n-1. Some courses may have prerequisites. For example, to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]. Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?<\/p>\n<p>Solution:<\/p>\n<pre><code>from collections import defaultdict\n\ndef can_finish(num_courses, prerequisites):\n    graph = defaultdict(list)\n    for course, prereq in prerequisites:\n        graph[course].append(prereq)\n    \n    visited = set()\n    rec_stack = set()\n    \n    def has_cycle(course):\n        visited.add(course)\n        rec_stack.add(course)\n        \n        for prereq in graph[course]:\n            if prereq not in visited:\n                if has_cycle(prereq):\n                    return True\n            elif prereq in rec_stack:\n                return True\n        \n        rec_stack.remove(course)\n        return False\n    \n    for course in range(num_courses):\n        if course not in visited:\n            if has_cycle(course):\n                return False\n    \n    return True\n\n# Test the function\nnum_courses = 4\nprerequisites = [[1,0],[2,1],[3,2],[1,3]]\nprint(can_finish(num_courses, prerequisites))  # Output: False<\/code><\/pre>\n<h2 id=\"conclusion\">10. Conclusion and Next Steps<\/h2>\n<p>Congratulations! You&#8217;ve now explored a variety of techniques for solving graph cycle problems. From basic DFS and BFS approaches to more advanced methods like Union-Find and Topological Sort, you have a robust toolkit for tackling cycle-related challenges in your coding interviews and real-world applications.<\/p>\n<p>Remember, the key to mastering these techniques is practice. Here are some next steps to further enhance your skills:<\/p>\n<ul>\n<li>Implement each of these algorithms from scratch without referring to the examples.<\/li>\n<li>Solve more complex graph problems on coding platforms like LeetCode, HackerRank, or CodeForces.<\/li>\n<li>Study the time and space complexity trade-offs of different approaches and practice optimizing your solutions.<\/li>\n<li>Explore how these cycle detection techniques can be applied to real-world problems in areas like network analysis, dependency management, or scheduling systems.<\/li>\n<li>Dive deeper into advanced graph algorithms and their applications.<\/li>\n<\/ul>\n<p>Keep coding, keep learning, and remember that every challenging problem you solve brings you one step closer to your goals in software development and algorithmic mastery. Happy coding!<\/p>\n<\/article>\n<p><\/body><\/html><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Welcome to another in-depth tutorial from AlgoCademy! Today, we&#8217;re diving into an essential topic for coding interviews and algorithmic problem-solving:&#8230;<\/p>\n","protected":false},"author":1,"featured_media":6143,"comment_status":"","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[23],"tags":[],"class_list":["post-6144","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-problem-solving"],"_links":{"self":[{"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/posts\/6144"}],"collection":[{"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/comments?post=6144"}],"version-history":[{"count":0,"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/posts\/6144\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/media\/6143"}],"wp:attachment":[{"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/media?parent=6144"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/categories?post=6144"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/tags?post=6144"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}