{"id":285,"date":"2025-06-12T14:25:35","date_gmt":"2025-06-12T08:55:35","guid":{"rendered":"https:\/\/codeanddebug.in\/blog\/?p=285"},"modified":"2025-06-12T14:25:37","modified_gmt":"2025-06-12T08:55:37","slug":"find-eventual-safe-states-bfs","status":"publish","type":"post","link":"https:\/\/codeanddebug.in\/blog\/find-eventual-safe-states-bfs\/","title":{"rendered":"Find Eventual Safe States | Leetcode 802 | Kahn\u2019s Algorithm (BFS) Solution"},"content":{"rendered":"\n<p>We flip the graph, run Kahn\u2019s topological BFS, and list every node guaranteed to avoid cycles. Includes clear intuition, step-by-step code walk-through, dry run, and full Python code with comments.<\/p>\n\n\n\n<p>Here&#8217;s the [<strong><a href=\"https:\/\/leetcode.com\/problems\/find-eventual-safe-states\/description\/\" target=\"_blank\" rel=\"noreferrer noopener\"><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-purple-color\"><span style=\"text-decoration: underline;\">Problem Link<\/span><\/mark><\/a><\/strong>] to begin with.<\/p>\n\n\n<div style=\"max-width: -moz-fit-content; \" class=\"wp-block-ub-table-of-contents-block ub_table-of-contents ub_table-of-contents-collapsed\" id=\"ub_table-of-contents-0e12c1ff-ee8a-4982-9a33-c28996ec1d22\" data-linktodivider=\"false\" data-showtext=\"show\" data-hidetext=\"hide\" data-scrolltype=\"auto\" data-enablesmoothscroll=\"true\" data-initiallyhideonmobile=\"false\" data-initiallyshow=\"false\"><div class=\"ub_table-of-contents-header-container\" style=\"\">\n\t\t\t<div class=\"ub_table-of-contents-header\" style=\"text-align: left; \">\n\t\t\t\t<div class=\"ub_table-of-contents-title\">Contents:<\/div>\n\t\t\t\t<div class=\"ub_table-of-contents-header-toggle\">\n\t\t\t<div class=\"ub_table-of-contents-toggle\" style=\"\">\n\t\t\t\u00a0[<a class=\"ub_table-of-contents-toggle-link\" href=\"#\" style=\"\">show<\/a>]\n\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t<\/div>\n\t\t<\/div><div class=\"ub_table-of-contents-extra-container\" style=\"\">\n\t\t\t<div class=\"ub_table-of-contents-container ub_table-of-contents-1-column ub-hide\">\n\t\t\t\t<ul style=\"\"><li style=\"\"><a href=\"https:\/\/codeanddebug.in\/blog\/find-eventual-safe-states-bfs\/#0-1-what-does-the-problem-ask\" style=\"\">1. What does the problem ask?<\/a><\/li><li style=\"\"><a href=\"https:\/\/codeanddebug.in\/blog\/find-eventual-safe-states-bfs\/#1-2-what-we-need-to-do\" style=\"\">2. What we need to do?<\/a><\/li><li style=\"\"><a href=\"https:\/\/codeanddebug.in\/blog\/find-eventual-safe-states-bfs\/#2-intuition-amp-approach-%E2%80%93-bfs-kahn%E2%80%99s-way\" style=\"\">Intuition &amp; Approach \u2013 BFS \/ Kahn\u2019s way<\/a><ul><li style=\"\"><a href=\"https:\/\/codeanddebug.in\/blog\/find-eventual-safe-states-bfs\/#3-31-why-reverse-the-graph\" style=\"\">3.1 Why reverse the graph?<\/a><\/li><li style=\"\"><a href=\"https:\/\/codeanddebug.in\/blog\/find-eventual-safe-states-bfs\/#4-32-build-the-reversed-graph\" style=\"\">3.2 Build the reversed graph<\/a><\/li><li style=\"\"><a href=\"https:\/\/codeanddebug.in\/blog\/find-eventual-safe-states-bfs\/#5-33-kahn%E2%80%99s-topological-idea-in-this-setting\" style=\"\">3.3 Kahn\u2019s topological idea in this setting<\/a><\/li><li style=\"\"><a href=\"https:\/\/codeanddebug.in\/blog\/find-eventual-safe-states-bfs\/#6-34-why-it-guarantees-correctness\" style=\"\">3.4 Why it guarantees correctness<\/a><\/li><\/ul><\/li><li style=\"\"><a href=\"https:\/\/codeanddebug.in\/blog\/find-eventual-safe-states-bfs\/#7-4-code\" style=\"\">4. Code<\/a><\/li><li style=\"\"><a href=\"https:\/\/codeanddebug.in\/blog\/find-eventual-safe-states-bfs\/#8-5-step-by-step-code-explanation\" style=\"\">5. Step-by-step code explanation<\/a><\/li><li style=\"\"><a href=\"https:\/\/codeanddebug.in\/blog\/find-eventual-safe-states-bfs\/#9-6-dry-run-on-leetcode%E2%80%99s-sample\" style=\"\">6. Dry run on LeetCode\u2019s sample<\/a><\/li><li style=\"\"><a href=\"https:\/\/codeanddebug.in\/blog\/find-eventual-safe-states-bfs\/#10-7-complexity-analysis\" style=\"\">7. Complexity analysis<\/a><\/li><li style=\"\"><a href=\"https:\/\/codeanddebug.in\/blog\/find-eventual-safe-states-bfs\/#11-8-conclusion\" style=\"\">8. Conclusion<\/a><\/li><\/ul>\n\t\t\t<\/div>\n\t\t<\/div><\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"0-1-what-does-the-problem-ask\">1. What does the problem ask?<\/h2>\n\n\n\n<p>You get a directed graph as an adjacency list <code>graph<\/code>, where <code>graph[i]<\/code> contains every node you can reach <strong>directly<\/strong> from node <code>i<\/code>.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A node is <strong>eventual safe<\/strong> if <strong>every<\/strong> path that starts there eventually ends at a terminal node (a node with <strong>no<\/strong> outgoing edges).<\/li>\n\n\n\n<li>If even one path can spin forever inside a cycle, the start node is <strong>not<\/strong> safe.<\/li>\n<\/ul>\n\n\n\n<p>Return all safe nodes in <strong>ascending order<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"1-2-what-we-need-to-do\">2. What we need to do?<\/h2>\n\n\n\n<p>Imagine marbles rolling along the arrows.<br><em>If a marble starting at node <code>x<\/code> might whirl around a loop forever, <code>x<\/code> is unsafe.<br>If every marble that ever starts at <code>x<\/code> always falls off the board at a dead-end, <code>x<\/code> is safe.<\/em><\/p>\n\n\n\n<p>So: <strong>\u201cSafe\u201d = cannot reach a directed cycle.<\/strong><\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>Also check <a href=\"https:\/\/codeanddebug.in\/blog\/topo-sort-kahns-algorithm\/\" data-type=\"post\" data-id=\"259\"><strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-purple-color\">Topological Sort (Kahn\u2019s Algorithm)<\/mark><\/strong><\/a><\/p>\n<\/blockquote>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"2-intuition-amp-approach-%E2%80%93-bfs-kahn%E2%80%99s-way\">3. Intuition &amp; Approach \u2013 BFS \/ Kahn\u2019s way<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"3-31-why-reverse-the-graph\">3.1 Why reverse the graph?<\/h3>\n\n\n\n<p>The dangerous objects are <strong>cycles<\/strong>.<br>Terminal nodes (out-degree 0) are certainly safe, because a marble there is already at rest.<br>If you can only reach <strong>terminal or already-safe<\/strong> nodes, you are safe too.<\/p>\n\n\n\n<p>That logic points <em>backwards<\/em>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>From a safe node, every predecessor that points <strong>into<\/strong> it might also be safe.<\/li>\n<\/ul>\n\n\n\n<p>Reversing all arrows turns \u201cpredecessor\u201d into \u201csuccessor\u201d, which is perfect for <strong>BFS<\/strong>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"4-32-build-the-reversed-graph\">3.2 Build the reversed graph<\/h3>\n\n\n\n<p>For every original edge <code>u \u2192 v<\/code> we insert <code>v \u2190 u<\/code>.<br>Now an arrow means \u201c<em>this node depends on that neighbour still being proven safe<\/em>\u201d.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"5-33-kahn%E2%80%99s-topological-idea-in-this-setting\">3.3 Kahn\u2019s topological idea in this setting<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Indegree<\/strong> = how many outgoing edges the node had in the <strong>original<\/strong> graph.<br><em>In the reversed graph it tells us how many neighbours are <strong>blocking<\/strong> the node from being called safe.<\/em><\/li>\n\n\n\n<li><strong>Queue start:<\/strong> every terminal node (indegree 0) is already safe.<\/li>\n\n\n\n<li><strong>BFS loop:<\/strong>\n<ul class=\"wp-block-list\">\n<li>Pop a safe node.<\/li>\n\n\n\n<li>For each predecessor in the reversed graph, lower its indegree.<\/li>\n\n\n\n<li>When a predecessor\u2019s indegree hits 0, <strong>all<\/strong> its original edges now lead to known-safe nodes, so the predecessor itself becomes safe; push it into the queue.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Finish:<\/strong> every node we popped is safe. Sort the list and return it.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"6-34-why-it-guarantees-correctness\">3.4 Why it guarantees correctness<\/h3>\n\n\n\n<p>Kahn\u2019s algorithm deletes edges layer by layer.<br><em>If a node ever reaches indegree 0, none of its original edges point to a cycle any more.<\/em><br>Nodes trapped in or feeding into a cycle will always keep at least one edge pointing inside that loop, so their indegree never reaches 0, and they never enter the queue.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"7-4-code\">4. Code<\/h2>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"from collections import deque\nfrom typing import List     # for type hinting only\n\nclass Solution:\n    def eventualSafeNodes(self, graph: List[List[int]]) -&gt; List[int]:\n        V = len(graph)\n\n        # -------- 1. Build reversed adjacency list --------\n        adj_list = [[] for _ in range(V)]          # reversed graph\n        for node in range(V):\n            for adjNode in graph[node]:            # original edge node -&gt; adjNode\n                adj_list[adjNode].append(node)     # reversed edge adjNode -&gt; node\n\n        # -------- 2. Compute indegree array (original out-degrees) --------\n        indegrees = [0] * V\n        for node in range(V):\n            for adjNode in adj_list[node]:\n                indegrees[adjNode] += 1            # edge points *into* adjNode\n\n        # -------- 3. Queue initial safe nodes (terminal nodes) --------\n        queue = deque()\n        for node in range(V):\n            if indegrees[node] == 0:               # no outgoing edges originally\n                queue.append(node)\n\n        # -------- 4. BFS to peel off safe layers --------\n        result = []\n        while queue:\n            node = queue.popleft()\n            result.append(node)                    # node confirmed safe\n            for adjNode in adj_list[node]:         # visit predecessors\n                indegrees[adjNode] -= 1            # remove supporting edge\n                if indegrees[adjNode] == 0:        # all outgoing paths now safe\n                    queue.append(adjNode)\n\n        # -------- 5. Return sorted list of safe nodes --------\n        result.sort()\n        return result\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C586C0\">from<\/span><span style=\"color: #D4D4D4\"> collections <\/span><span style=\"color: #C586C0\">import<\/span><span style=\"color: #D4D4D4\"> deque<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">from<\/span><span style=\"color: #D4D4D4\"> typing <\/span><span style=\"color: #C586C0\">import<\/span><span style=\"color: #D4D4D4\"> List     <\/span><span style=\"color: #6A9955\"># for type hinting only<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">class<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Solution<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">def<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">eventualSafeNodes<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">self<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">graph<\/span><span style=\"color: #D4D4D4\">: List[List[<\/span><span style=\"color: #4EC9B0\">int<\/span><span style=\"color: #D4D4D4\">]]) -&gt; List[<\/span><span style=\"color: #4EC9B0\">int<\/span><span style=\"color: #D4D4D4\">]:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        V = <\/span><span style=\"color: #DCDCAA\">len<\/span><span style=\"color: #D4D4D4\">(graph)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #6A9955\"># -------- 1. Build reversed adjacency list --------<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        adj_list = [[] <\/span><span style=\"color: #C586C0\">for<\/span><span style=\"color: #D4D4D4\"> _ <\/span><span style=\"color: #C586C0\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">range<\/span><span style=\"color: #D4D4D4\">(V)]          <\/span><span style=\"color: #6A9955\"># reversed graph<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">for<\/span><span style=\"color: #D4D4D4\"> node <\/span><span style=\"color: #C586C0\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">range<\/span><span style=\"color: #D4D4D4\">(V):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #C586C0\">for<\/span><span style=\"color: #D4D4D4\"> adjNode <\/span><span style=\"color: #C586C0\">in<\/span><span style=\"color: #D4D4D4\"> graph[node]:            <\/span><span style=\"color: #6A9955\"># original edge node -&gt; adjNode<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                adj_list[adjNode].append(node)     <\/span><span style=\"color: #6A9955\"># reversed edge adjNode -&gt; node<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #6A9955\"># -------- 2. Compute indegree array (original out-degrees) --------<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        indegrees = [<\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">] * V<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">for<\/span><span style=\"color: #D4D4D4\"> node <\/span><span style=\"color: #C586C0\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">range<\/span><span style=\"color: #D4D4D4\">(V):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #C586C0\">for<\/span><span style=\"color: #D4D4D4\"> adjNode <\/span><span style=\"color: #C586C0\">in<\/span><span style=\"color: #D4D4D4\"> adj_list[node]:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                indegrees[adjNode] += <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #6A9955\"># edge points *into* adjNode<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #6A9955\"># -------- 3. Queue initial safe nodes (terminal nodes) --------<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        queue = deque()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">for<\/span><span style=\"color: #D4D4D4\"> node <\/span><span style=\"color: #C586C0\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">range<\/span><span style=\"color: #D4D4D4\">(V):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> indegrees[node] == <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">:               <\/span><span style=\"color: #6A9955\"># no outgoing edges originally<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                queue.append(node)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #6A9955\"># -------- 4. BFS to peel off safe layers --------<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        result = []<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">while<\/span><span style=\"color: #D4D4D4\"> queue:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            node = queue.popleft()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            result.append(node)                    <\/span><span style=\"color: #6A9955\"># node confirmed safe<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #C586C0\">for<\/span><span style=\"color: #D4D4D4\"> adjNode <\/span><span style=\"color: #C586C0\">in<\/span><span style=\"color: #D4D4D4\"> adj_list[node]:         <\/span><span style=\"color: #6A9955\"># visit predecessors<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                indegrees[adjNode] -= <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #6A9955\"># remove supporting edge<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> indegrees[adjNode] == <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">:        <\/span><span style=\"color: #6A9955\"># all outgoing paths now safe<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                    queue.append(adjNode)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #6A9955\"># -------- 5. Return sorted list of safe nodes --------<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        result.sort()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">return<\/span><span style=\"color: #D4D4D4\"> result<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"8-5-step-by-step-code-explanation\">5. Step-by-step code explanation<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Reverse the arrows<\/strong> so we can move <em>backwards<\/em> from terminals.<\/li>\n\n\n\n<li><strong><code>indegrees<\/code><\/strong> now counts <em>how many original outgoing edges<\/em> each node still has that are <strong>not yet proven safe<\/strong>.<\/li>\n\n\n\n<li><strong>Initial queue<\/strong> collects every terminal node (indegree 0). They are safe by definition.<\/li>\n\n\n\n<li><strong>BFS loop<\/strong>\n<ul class=\"wp-block-list\">\n<li>Pop the next safe node.<\/li>\n\n\n\n<li>\u201cDelete\u201d its contribution to each predecessor by subtracting from indegree.<\/li>\n\n\n\n<li>If a predecessor\u2019s indegree drops to zero, absolutely <strong>all<\/strong> its original edges now lead to safe nodes, so we mark it safe too.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Sorting<\/strong> \u2013 BFS pops nodes in topological order of the reversed graph, which is not necessarily ascending numeric order, so we sort before returning.<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"9-6-dry-run-on-leetcode%E2%80%99s-sample\">6. Dry run on LeetCode\u2019s sample<\/h2>\n\n\n\n<p><code>graph = [[1,2],[2,3],[5],[0],[5],[],[]]<\/code><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Stage<\/th><th>Queue<\/th><th>Safe list<\/th><th>Indegree snapshot (keep 0\u2019s)<\/th><\/tr><\/thead><tbody><tr><td>Build reversed graph &amp; indegrees<\/td><td><code>[4,5,6]<\/code><\/td><td><code>[]<\/code><\/td><td>indeg 0 for 4,5,6<\/td><\/tr><tr><td>Pop 5 (terminal)<\/td><td><code>[4,6]<\/code><\/td><td><code>[5]<\/code><\/td><td>indeg[2]\u21920 \u2192 enqueue 2<\/td><\/tr><tr><td>Pop 4<\/td><td><code>[6,2]<\/code><\/td><td><code>[5,4]<\/code><\/td><td>indeg stays same<\/td><\/tr><tr><td>Pop 6<\/td><td><code>[2]<\/code><\/td><td><code>[5,4,6]<\/code><\/td><td>(6 has no predecessors)<\/td><\/tr><tr><td>Pop 2<\/td><td><code>[]<\/code><\/td><td><code>[5,4,6,2]<\/code><\/td><td>indeg[1]\u21920, indeg[0]\u21921 (<em>not zero yet<\/em>) \u2192 enqueue 1<\/td><\/tr><tr><td>Pop 1<\/td><td><code>[]<\/code><\/td><td><code>[5,4,6,2,1]<\/code><\/td><td>indeg[0]\u21920 \u2192 enqueue 0<\/td><\/tr><tr><td>Pop 0<\/td><td><code>[]<\/code><\/td><td><code>[5,4,6,2,1,0]<\/code><\/td><td>done<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Sort \u2192 <strong><code>[0,1,2,4,5,6]<\/code><\/strong> (matches the official answer).<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"10-7-complexity-analysis\">7. Complexity analysis<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Metric<\/th><th>Cost<\/th><th>Explanation<\/th><\/tr><\/thead><tbody><tr><td><strong>Time<\/strong><\/td><td><strong>O(V + 2E)<\/strong><\/td><td>We build one reversed edge per original edge and examine each edge once in BFS.<\/td><\/tr><tr><td><strong>Space<\/strong><\/td><td><strong>O(V + E)<\/strong><\/td><td>Reversed adjacency list plus arrays <code>indegrees<\/code>, <code>queue<\/code>, <code>result<\/code>.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><code>V = number of nodes<\/code>, <code>E = number of edges<\/code>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"11-8-conclusion\">8. Conclusion<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Reversing the graph and running <strong>Kahn\u2019s topological BFS<\/strong> peels off \u201csafe layers\u201d from the terminal nodes outward.<\/li>\n\n\n\n<li>Every node that eventually reaches indegree 0 is <strong>guaranteed<\/strong> not to touch a cycle.<\/li>\n\n\n\n<li>The method is linear, easy to code, and a great alternative to the DFS back-edge technique when you prefer an iterative approach.<\/li>\n<\/ul>\n\n\n\n<div class=\"wp-block-buttons is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-16018d1d wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/www.codeanddebug.in\/course\/zero-to-hero-python-dsa\">Join our Advance DSA COURSE<\/a><\/div>\n<\/div>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><em>For any changes to the article, kindly email at <a href=\"mailto:code@codeanddebug.in\">code@codeanddebug.in<\/a> or contact us at <a href=\"tel:+91-9712928220\">+91-9712928220<\/a>.<\/em><\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>We flip the graph, run Kahn\u2019s topological BFS, and list every node guaranteed to avoid cycles. Includes clear intuition, step-by-step code walk-through, dry run, and full Python code with comments. Here&#8217;s the [Problem Link] to begin with. 1. What does the problem ask? You get a directed graph as an adjacency list graph, where graph[i]<\/p>\n","protected":false},"author":1,"featured_media":287,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ub_ctt_via":"","footnotes":""},"categories":[3,5],"tags":[21,17,18],"class_list":{"0":"post-285","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","7":"category-data-structures-and-algorithm","8":"category-expert","9":"tag-bfs","10":"tag-graph","11":"tag-hard"},"featured_image_src":"https:\/\/codeanddebug.in\/blog\/wp-content\/uploads\/2025\/06\/find-eventual-safe-states-featured-image.png","author_info":{"display_name":"codeanddebug","author_link":"https:\/\/codeanddebug.in\/blog\/author\/codeanddebug\/"},"_links":{"self":[{"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/posts\/285","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/comments?post=285"}],"version-history":[{"count":2,"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/posts\/285\/revisions"}],"predecessor-version":[{"id":290,"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/posts\/285\/revisions\/290"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/media\/287"}],"wp:attachment":[{"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/media?parent=285"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/categories?post=285"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/tags?post=285"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}