### 📌 问题描述简述
你给定一个有向图 graph[i],表示从节点 i 出发可以到达的所有节点。
目标:找出所有最终一定会走向终点的安全节点。
安全节点定义如下:
“从该节点出发的所有路径最终都会终止在没有出边的 terminal node 上,而不会形成环。”
解题思路:图的染色 + DFS 检查环
这道题的核心在于:
我们要判断每个节点是否属于环或能走进环。一旦某条路径中出现环,说明当前起点不是安全的。
我们使用状态标记法(也叫图的染色法):
UNVISITED(0):未访问VISITING(-1):当前路径正在访问中VISITED(1):已经判断为“安全节点”
public class SafeState {
private static final int VISITED = 1;
private static final int VISITING = -1;
private static final int UNVISITED = 0;
public List<Integer> safeState(int[][] graph) {
List<Integer> result = new ArrayList<>();
int[] visited = new int[graph.length];
for (int i = 0; i < graph.length; i++) {
if (dfs(i, graph, visited)) {
result.add(i);
}
}
return result;
}
private boolean dfs(int curNode, int[][] graph, int[] visited) {
if (visited[curNode] == VISITED) return true; // 已确认安全
if (visited[curNode] == VISITING) return false; // 当前路径已访问过 → 形成环
visited[curNode] = VISITING;
for (int nei : graph[curNode]) {
if (!dfs(nei, graph, visited)) {
return false;
}
}
visited[curNode] = VISITED;
return true;
}
}
示例用例执行(手动画图分析)
输入图:graph = [[1,2],[2,3],[5],[0],[5],[],[]]
可视化图如下(每个箭头为有向边):
markdown
复制编辑
0 → 1 → 2 → 5
↓
3 ←
4 → 5
6 (无出边)
执行流程:
- 节点
5和6无出边,直接是安全节点 2 → 5,安全 ✅1 → 2 → 5,安全 ✅0 → 1 → 2 → 5,安全 ✅3 → 0 → 1 → ... → 3,形成环 ❌4 → 5,安全 ✅
最终输出结果:[2, 4, 5, 6]
💡 为什么这道题在 AI 面试中的价值更高?
这不仅是图遍历问题,更涉及状态收敛、安全路径、终止性这类核心思想,而这些恰好是 AI 中常见的计算范式:
| AI 场景 | 对应题意 |
|---|---|
| 🧭 路径规划(Planning) | 找出不会进入死循环的路径起点 |
| 📊 图神经网络传播 | 识别稳定/收敛状态的节点 |
| 🔍 逻辑推理系统 | 判断哪些规则推导不会导致无限推理 |
| 🤖 强化学习策略评估 | 找出策略下最终会安全终止的状态 |
| 🧠 状态机分析 | 检查是否存在环或错误终止路径 |
在 AI 系统中,确定系统是否最终会收敛或安全终止,是最重要的稳定性问题之一。
📝 总结
核心逻辑:用 DFS 检查每个节点是否会进入环,若不会,则是“最终安全节点”。
时间复杂度:O(V + E)
适合的场景:AI 推理、路径规划、安全策略、状态图分析等。