In a directed graph, we start at some node and every turn, walk along a directed edge of the graph. If we reach a node that is terminal (that is, it has no outgoing directed edges), we stop.
Now, say our starting node is eventually safe if and only if we must eventually walk to a terminal node. More specifically, there exists a natural number K so that for any choice of where to walk, we must have stopped at a terminal node in less than K steps.
Which nodes are eventually safe? Return them as an array in sorted order.
The directed graph has N nodes with labels 0, 1, ..., N-1, where N is the length of graph. The graph is given in the following form: graph[i] is a list of labels j such that (i, j) is a directed edge of the graph.
Example:
Input: graph = [[1,2],[2,3],[5],[0],[5],[],[]]
Output: [2,4,5,6]
Here is a diagram of the above graph.
1.思考
- 首先想到方法就是DPS,然后对每个节点深度优先搜索直到找到回路,找到就返回true,否则返回false;
- 一开始是使用vector<int> cyc,然后通过push_back和find来工作的,但是这个方法时间复杂度太高;后来进行优化才想到直接用vector<int> cyc(len, 0),找到回路赋值为1,没找到赋值为0,所以这个方法时间复杂度更低;
- 在调试过程中,提交之后一直都是Time Exceeded。其实刚开始的思路就是正确的,但是没有很优化,所以才导致的超时。后来考虑到其实不能每个节点都访问才知道它是否有回路,在dps每一个节点的时候,中间节点的回路信息都是可以知道的(在有回路的情况下是知道的,没有回路的情况还要到时候轮到该节点时进行遍历);
- 本来设置了visit用来记录是否访问,之后发现初始化cyc为1,就可以减少一个变量的使用,还更加简洁明了。
2.实现
- RunTime: 172ms (56.97%)
- Memory: 32.2MB (91.80%)
class Solution {
public:
vector<int> eventualSafeNodes(vector<vector<int>>& graph) {
int len = graph.size();
vector<int> res, cyc(len, 0);
for(int i=0; i<len; i++){
if(dfs(i, graph, cyc))
cyc[i] = 1;
else
res.push_back(i);
}
return res;
}
bool dfs(int src, vector<vector<int>>& graph, vector<int>& cyc){
if(cyc[src]==1)//src is in a cycle
return true;
else if(cyc[src]==-1)//src isn't in a cycle
return false;
cyc[src] = 1;//Default which means this node has been visited
for(auto dst:graph[src]){
if(dfs(dst, graph, cyc)){//dst is in a cycle
cyc[dst] = 1;
return true;
}
}
cyc[src] = -1;//dst isn't in a cycle
return false;
}
};