携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情
题目描述
给定一个数组edges表示有向图边的情况,edges[i]=j 所表示的含义为i->j之间有一条有向边,edges[i]=-1 表示节点i没有出边。给出两个节点node1、node2,返回从节点node1、node2都能到达的节点的距离较大值最小化的节点编号。
例1:输入:"[2,-1,1,4,2] 2 3 " 输出:"2"
解释:该图的结构如下图所示
所要找出的是节点2和3都能到达且节点距离较大值最小化的节点编号。可以看出节点2能到达的点为2、1,3能到达的点为4、2、1。可见二者都能到达1、2,但到达节点 1 的距离为3(节点 3 到达节点 1 的距离 ),到达节点 2 的距离为2(节点 3 到达节点 2 的距离 ),因为要选择距离最小化,所以答案应为节点2。
本题值得注意的地方
- 所给的两个节点可能为同一节点
- 每个节点最多有一条出边
- 图中没有自环
- 图中有可能存在环
原题地址:6134. 找到离给定两个节点最近的节点
解题思路
因为每个节点最多只有一条出边,所以可以分别对给出的两个节点分别进行查找其能够到达的节点,在查找时,同时也要记录其到该节点的距离。在找出两个节点所能到达的节点后,还要对这些节点进行比较,挑选出到达这两个节点最大距离最小的节点。
为了方便起见,我们可以使用两个map来存储两个节点所能到达的节点及其距离。其key为节点编号,其value为距离。最后遍历每个节点,如果两个map中都有某节点的key,则该节点可由node1、node2到达,比较所有符合的节点在map1、map2中的最大值,取最大值最小的节点返回。
当然,为了防止图中的环所引起死循环,可以对访问过的节点进行标记。
实现代码
class Solution {
public:
int closestMeetingNode(vector<int>& edges, int node1, int node2) {
int len = 0,nd1 = node1,nd2 = node2,ans = -1;
// 分别用来存储node1、node2所能到达的节点及距离
unordered_map<int,int> ndmp1,ndmp2;
// 标记节点的访问情况
bool st[edges.size()+1];
// 初始化为false
memset(st,0,sizeof st);
// 寻找node1所能到达的节点
while( nd2 != -1 &&!st[nd2] ){
st[nd2] = true;
ndmp2[nd2] = len++;
nd2 = edges[nd2];
}
// 重置st、len,寻找node2所能达到的节点
memset(st,0,sizeof st);
len = 0;
while(nd1 != -1&& !st[nd1] ){
st[nd1] = true;
ndmp1[nd1] = len++;
nd1 = edges[nd1];
}
// 寻找node1、node2所能达到的公共节点
for(int i = 0;i < edges.size();i++){
// 找到到达公共节点最大距离最小的节点
if(ndmp1.count(i)>0 && ndmp2.count(i)>0){
if(ans != -1 && max(ndmp1[ans],ndmp2[ans]) > max(ndmp1[i],ndmp2[i])) ans = i;
else if(ans == -1) ans = i;
}
}
return ans;
}
};