You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

有向图深度优先搜索(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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 19:06:02