From da6c1882bfca5920aa2d89b0d7a1287f1f24f12a Mon Sep 17 00:00:00 2001 From: "codeflash-ai[bot]" <148906541+codeflash-ai[bot]@users.noreply.github.com> Date: Mon, 22 Dec 2025 22:41:24 +0000 Subject: [PATCH] Optimize find_last_node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The optimized code achieves a **166x speedup** by eliminating redundant nested iterations and replacing them with efficient set-based lookups. ## Key Optimizations **1. Early Return for Empty Edges** The optimization adds a fast-path check: if there are no edges, return the first node immediately. This avoids any iteration overhead for disconnected graphs, providing 157-314% speedup on such cases. **2. Set-Based Source Lookup** The critical optimization replaces the nested `all(e["source"] != n["id"] for e in edges)` check with: - First, build a set of all source node IDs: `sources = {e["source"] for e in edges}` - Then use fast set membership: `n["id"] not in sources` This transforms the algorithm from **O(nodes × edges)** to **O(nodes + edges)** complexity. ## Why This Works In the original code, for each node, it iterates through *all* edges to check if that node is a source. With 1000 nodes and 1000 edges, this performs up to 1 million comparisons. The optimized version builds the source set once (1000 operations), then does constant-time set lookups for each node (1000 × O(1)), totaling ~2000 operations—a 500x reduction in work. ## Performance Impact by Test Type - **Empty edges cases**: 157-314% faster (early return optimization) - **Small graphs (2-10 nodes)**: 22-94% faster (overhead of set creation still worthwhile) - **Large linear chains (1000 nodes)**: **32,000%+ faster** (quadratic → linear complexity) - **Large cycle graphs**: **32,496% faster** (must check all nodes, massive iteration savings) - **Star graphs**: 87-93% faster (many edges but set lookup scales well) The optimization particularly excels when there are many nodes and edges, as it eliminates the quadratic blowup that occurs in the nested iteration pattern of the original implementation. --- src/algorithms/graph.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/algorithms/graph.py b/src/algorithms/graph.py index 777ea3b..b528754 100644 --- a/src/algorithms/graph.py +++ b/src/algorithms/graph.py @@ -47,7 +47,10 @@ def find_shortest_path(self, start: str, end: str) -> list[str]: def find_last_node(nodes, edges): """This function receives a flow and returns the last node.""" - return next((n for n in nodes if all(e["source"] != n["id"] for e in edges)), None) + if not edges: + return nodes[0] if nodes else None + sources = {e["source"] for e in edges} + return next((n for n in nodes if n["id"] not in sources), None) def find_leaf_nodes(nodes: list[dict], edges: list[dict]) -> list[dict]: