题目
给你一个 n 个节点的 有向图 ,节点编号为 0 到 n - 1 ,每个节点 至多 有一条出边。
有向图用大小为 n 下标从 0 开始的数组 edges 表示,表示节点 i 有一条有向边指向 edges[i] 。如果节点 i 没有出边,那么 edges[i] == -1 。
同时给你两个节点 node1 和 node2 。
请你返回一个从 node1 和 node2 都能到达节点的编号,使节点 node1 和节点 node2 到这个节点的距离 较大值最小化。如果有多个答案,请返回 最小 的节点编号。如果答案不存在,返回 -1 。
注意 edges 可能包含环。
示例 1:
输入:edges = [2,2,3,-1], node1 = 0, node2 = 1 输出:2 解释:从节点 0 到节点 2 的距离为 1 ,从节点 1 到节点 2 的距离为 1 。 两个距离的较大值为 1 。我们无法得到一个比 1 更小的较大值,所以我们返回节点 2 。
示例 2:
输入:edges = [1,2,-1], node1 = 0, node2 = 2 输出:2 解释:节点 0 到节点 2 的距离为 2 ,节点 2 到它自己的距离为 0 。 两个距离的较大值为 2 。我们无法得到一个比 2 更小的较大值,所以我们返回节点 2 。
解题
方法一:哈希
创建1个哈希集合,记录从node1开始经过的节点,那么从node2开始遍历,第一次经过set中已经有的节点,那么就是交点。
但是此时不能保证就是最小距离,因此还要类似相同重复一遍,从node2开始的节点记录到set,然后从node1开始第一次遇到set中已有的节点。
取两个路径结果中的最小值,就是最终的节点。
创建2个数组,visit数组记录节点是否访问过,len数组记录当前节点到起始节点的距离
从node1开始,遍历到结束(-1的点或者已经访问过的点),同时更新visit和len数组
class Solution { public: int closestMeetingNode(vector<int>& edges, int node1, int node2) { pair<int,int> p1=fun(edges,node1,node2); pair<int,int> p2=fun(edges,node2,node1); if(p1.first==p2.first) return p1.first;//如果是同一个节点,那么直接返回节点 else{ if(p1.second==p2.second) return min(p1.first,p2.first);//如果节点不同,但是距离相同,选编号小的节点 else if(p1.second<p2.second) return p1.first;//如果节点不同,且距离不同,那么选距离小的节点 else return p2.first; } } pair<int,int> fun(vector<int>& edges, int node1, int node2){//返回值:(节点,路径) unordered_set<int> set;//记录node1开始,经过的节点 vector<bool> visit(edges.size(),false);//visit数组记录节点是否访问过(作用:防止出现环,死循环) int i=node1; vector<int> len(edges.size(),-1);//len数组记录经过的节点的距离node1的距离 int curLen=0; while(true){ if(i==-1||visit[i]==true) break;//如果节点没有出边 或者 节点访问过,那么直接break visit[i]=true; len[i]=curLen++; set.insert(i); i=edges[i];//访问下一个节点 } visit=vector<bool>(edges.size(),false); i=node2; curLen=0; while(true){ if(i==-1||visit[i]==true) return {-1,-1}; visit[i]=true; if(set.count(i)){//如果该节点从node1开始访问过,说明这是一个交点 int resLen=max(len[i],curLen);//取最大的路径 return {i,resLen}; } curLen++; i=edges[i]; } return {-1,-1}; } };