有向图深度优先搜索(DFS)求解数组构造图的最长路径长度
DFS求解有向无环图最长路径方案
原代码核心问题
- 邻接表存储逻辑错误:构建边时直接存入节点数值而非节点索引,额外增加查询开销,且数组存在重复值时会直接出错
getIndex方法逻辑错误:匹配到对应数值的节点后,错误返回数值本身而非节点索引,极易触发数组越界- DFS递归逻辑混乱:递归方法内部嵌套了遍历所有节点的while循环,递归边界不清晰,局部
count变量无法跨递归层累加路径长度 - 无记忆化优化:针对大规模数组会存在大量重复计算,性能无法满足复用需求
- 你构建的图本质是有向无环图(DAG),所有边均从左指向右,不存在环,完全可以用记忆化DFS将时间复杂度控制在O(V+E)级别
代码修改方案
1. 修改Graph类的边构建与DFS逻辑
import java.util.NoSuchElementException; public class Graph { private static final String NEWLINE = System.getProperty("line.separator"); public final int V; private int E = 0; public Bag<Integer>[] adj; private int[] memo; // 记忆化数组,存储从当前节点出发的最长路径边数 private int maxPathLength = 0; // 全局最长路径边数 public Graph(int[] numbers) { try { this.V = numbers.length; adj = (Bag<Integer>[]) new Bag[V]; for (int v = 0; v < V; v++) { adj[v] = new Bag<Integer>(); adj[v].label = numbers[v]; } // 边存储节点索引而非数值 for (int i = 0; i < V; i++) { int j = i + 1; while (j < numbers.length) { if (numbers[i] < numbers[j]) { addEdge(i, j); // 直接存目标节点的索引 } j++; } } memo = new int[V]; // 初始化记忆化数组为-1,表示未计算 for (int i = 0; i < V; i++) { memo[i] = -1; } } catch (NoSuchElementException e) { throw new IllegalArgumentException("invalid input format in Graph constructor", e); } } public void addEdge(int fromIndex, int toIndex) { E++; adj[fromIndex].add(toIndex); } public void print() { for (int i = 0; i < adj.length; i++) { System.out.print(adj[i].label + ": "); for (int w : adj[i]) { System.out.print(adj[w].label + " "); } System.out.println(""); } } // 递归返回从start节点出发的最长路径边数 private int dfsUtil(int start) { // 已经计算过直接返回,避免重复计算 if (memo[start] != -1) { return memo[start]; } int currentMax = 0; // 遍历所有邻接节点 for (int nextIndex : adj[start]) { int nextLength = dfsUtil(nextIndex) + 1; if (nextLength > currentMax) { currentMax = nextLength; } } memo[start] = currentMax; // 更新全局最长路径 if (currentMax > maxPathLength) { maxPathLength = currentMax; } return currentMax; } // 遍历所有节点作为起点,求解全局最长路径 public int getLongestPathLength() { maxPathLength = 0; for (int i = 0; i < V; i++) { dfsUtil(i); } // 如需返回路径的节点数,直接返回maxPathLength+1即可 return maxPathLength; } // 支持获取指定起点的最长路径长度 public int getLongestPathFrom(int start) { if (start < 0 || start >= V) { throw new IllegalArgumentException("节点索引超出范围"); } return dfsUtil(start); } }
2. main函数修改
public static void main(String[] args) { int[] num = {4, 1, 2, 5, 3, 6, 8, 7}; Graph G = new Graph(num); System.out.println("邻接表:"); G.print(); System.out.println("全局最长路径边数:" + G.getLongestPathLength()); System.out.println("从索引1(数值1)出发的最长路径边数:" + G.getLongestPathFrom(1)); }
3. Bag类无需修改,可直接使用原实现
运行结果
邻接表: 4: 5 6 8 7 1: 2 5 3 6 8 7 2: 5 6 8 7 5: 6 8 7 3: 6 8 7 6: 8 7 8: 7: 全局最长路径边数:4 从索引1(数值1)出发的最长路径边数:4
样例数组的最长路径为1->2->5->6->8,共4条边、5个节点,与运行结果一致。记忆化的实现也支持直接复用至大规模随机数数组场景。
内容的提问来源于stack exchange,提问作者potroast12
相关产品推荐
相关产品推荐

