From c94c4c82c430ce8838b7358b6db3e296025b1720 Mon Sep 17 00:00:00 2001 From: "codeflash-ai[bot]" <148906541+codeflash-ai[bot]@users.noreply.github.com> Date: Tue, 17 Mar 2026 07:44:18 +0000 Subject: [PATCH] Optimize find_leaf_nodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The optimized function cuts runtime from 59.4 ms to 0.157 ms (~378× faster) by building a set of edge["source"] values and using a single list comprehension to filter nodes instead of the original nested node×edge loop. The key insight is that membership checks against a precomputed set are O(1), turning the algorithm from O(n·m) into O(n+m); the line profiler shows the inner edge loop accounted for ~99% of the original time, so eliminating it yields the large win. It also short-circuits the no-edges case by returning a shallow copy for minimal overhead and wraps set construction in a try/except to fall back to the original nested loop if sources are unhashable or the 'source' key is missing, preserving the original exception behavior. Trade-offs: set construction adds a small upfront cost and a couple of microbenchmarks (empty-nodes and the missing-key fallback) show marginal regressions, but these are rare compared with the huge speedup on typical graphs. --- src/algorithms/graph.py | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/algorithms/graph.py b/src/algorithms/graph.py index 777ea3b..9bef300 100644 --- a/src/algorithms/graph.py +++ b/src/algorithms/graph.py @@ -52,15 +52,29 @@ def find_last_node(nodes, edges): def find_leaf_nodes(nodes: list[dict], edges: list[dict]) -> list[dict]: """Find all leaf nodes (nodes with no outgoing edges).""" - leaf_nodes = [] - for node in nodes: - is_leaf = True - for edge in edges: - if edge["source"] == node["id"]: - is_leaf = False - break - if is_leaf: - leaf_nodes.append(node) + # If there are no edges, every node is a leaf; avoid accessing node["id"] + if not edges: + return nodes[:] + + # Attempt to build a set of sources for O(1) membership checks. + # If building the set fails (e.g., unhashable source, missing "source" key), + # fall back to the original nested-loop logic to preserve behavior and exceptions. + try: + sources = {edge["source"] for edge in edges} + except Exception: + leaf_nodes = [] + for node in nodes: + is_leaf = True + for edge in edges: + if edge["source"] == node["id"]: + is_leaf = False + break + if is_leaf: + leaf_nodes.append(node) + return leaf_nodes + + # Fast path using the precomputed set of sources. + leaf_nodes = [node for node in nodes if node["id"] not in sources] return leaf_nodes