6134. 找到离给定两个节点最近的节点
给你一个 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 。
提示:
n == edges.length
2 <= n <= 105
-1 <= edges[i] < n
edges[i] != i
0 <= node1, node2 < n
我的想法
每个节点 至多 有一条出边→路径唯一有点链表的感觉
能不能按照交叉链表那样做
因为存在环,搞了半天也没整出来
图算法这块还是不行,菜就多练!
正确思路
可以想到求出 node1
和 node2
到其它所有点的最短距离,然后遍历可选择的「中间点」。所以现在的问题就是如何求出其它点到起点的最短路径
为什么想不到遍历!!!
class Solution {
public:
int closestMeetingNode(vector<int>& edges, int node1, int node2) {
int n=edges.size();
auto cal_dis=[&](int s)->vector<int>
{
vector<int> dis(n,-1);
int count=0;
for(int i=0;i<n;i++)
{
if(s==-1)
break;
if(dis[s]!=-1)
break;
dis[s]=count++;
s=edges[s];
}
return dis;
};
vector<int> dis1=cal_dis(node1),dis2=cal_dis(node2);
int ans=-1,min=2147483647;
for(int i=0;i<n;i++)
{
if(dis1[i]==-1||dis2[i]==-1)
continue;
if(max(dis1[i],dis2[i])<min)
{
ans=i;
min=max(dis1[i],dis2[i]);
}
}
return ans;
}
};
6135. 图中的最长环
给你一个 n
个节点的 有向图 ,节点编号为 0
到 n - 1
,其中每个节点 至多 有一条出边。
图用一个大小为 n
下标从 0 开始的数组 edges
表示,节点 i
到节点 edges[i]
之间有一条有向边。如果节点 i
没有出边,那么 edges[i] == -1
。
请你返回图中的 最长 环,如果没有任何环,请返回 -1
。
一个环指的是起点和终点是 同一个 节点的路径。
示例 1:
输入:edges = [3,3,4,2,3]
输出去:3
解释:图中的最长环是:2 -> 4 -> 3 -> 2 。
这个环的长度为 3 ,所以返回 3 。
示例 2:
输入:edges = [2,-1,3,1]
输出:-1
解释:图中没有任何环。
提示:
n == edges.length
2 <= n <= 105
-1 <= edges[i] < n
edges[i] != i
我的想法
内向基环树找环 + 利用时间戳简单实现
出度至多为1保证连通片只有两种形式
遍历起点在这两种形式里一共有三种情况
class Solution {
public:
int longestCycle(vector<int>& edges) {
int n=edges.size();
int ans=-1;
vector<int> visit(n,0);//时间戳数组
int count=0;
for(int i=0;i<n;i++)
{
if(visit[i])
continue;
int s=i;
int init_count=count;
do
{
visit[s]=count;
s=edges[s];
count++;
}while(s!=-1&&!visit[s]);
if(s==-1)//情况1
continue;
if(visit[s]<init_count)//当碰到之前已经遍历过的点,不需要重复遍历,直接跳过
continue;
if(visit[s])
ans=max(count-visit[s],ans);
}
return ans;
}
};
官解
拓扑排序,分离出环
class Solution {
public:
int longestCycle(vector<int>& edges) {
int n=edges.size();
vector<int> indeg(n,0);
vector<bool> visit(n,false);
//计算入度
for(int i=0;i<n;i++)
{
if(edges[i]!=-1) indeg[edges[i]]++;
}
//拓扑排序
queue<int> q;
for(int i=0;i<n;i++)
{
if(!indeg[i])
{
q.push(i);
visit[i]=true;
}
}
while(!q.empty())
{
int v=q.front();
q.pop();
int w=edges[v];
if(w!=-1&&--indeg[w]==0)
{
visit[w]=true;
q.push(w);
}
}
//没有visit到的是环
int ans=-1;
for(int i=0;i<n;i++)
{
if(!visit[i])
{
int count=0;
int s=i;
do
{
visit[s]=true;
count++;
s=edges[s];
}while(s!=i);
if(count>ans)
ans=count;
}
}
return ans;
}
};
类似:2127. 参加会议的最多员工数
难度困难59
一个公司准备组织一场会议,邀请名单上有 n
位员工。公司准备了一张 圆形 的桌子,可以坐下 任意数目 的员工。
员工编号为 0
到 n - 1
。每位员工都有一位 喜欢 的员工,每位员工 当且仅当 他被安排在喜欢员工的旁边,他才会参加会议。每位员工喜欢的员工 不会 是他自己。
给你一个下标从 0 开始的整数数组 favorite
,其中 favorite[i]
表示第 i
位员工喜欢的员工。请你返回参加会议的 最多员工数目 。
示例 1:
输入:favorite = [2,2,1,2]
输出:3
解释:
上图展示了公司邀请员工 0,1 和 2 参加会议以及他们在圆桌上的座位。
没办法邀请所有员工参与会议,因为员工 2 没办法同时坐在 0,1 和 3 员工的旁边。
注意,公司也可以邀请员工 1,2 和 3 参加会议。
所以最多参加会议的员工数目为 3 。
示例 2:
输入:favorite = [1,2,0]
输出:3
解释:
每个员工都至少是另一个员工喜欢的员工。所以公司邀请他们所有人参加会议的前提是所有人都参加了会议。
座位安排同图 1 所示:
- 员工 0 坐在员工 2 和 1 之间。
- 员工 1 坐在员工 0 和 2 之间。
- 员工 2 坐在员工 1 和 0 之间。
参与会议的最多员工数目为 3 。
示例 3:
输入:favorite = [3,0,1,4,1]
输出:4
解释:
上图展示了公司可以邀请员工 0,1,3 和 4 参加会议以及他们在圆桌上的座位。
员工 2 无法参加,因为他喜欢的员工 0 旁边的座位已经被占领了。
所以公司只能不邀请员工 2 。
参加会议的最多员工数目为 4 。
提示:
n == favorite.length
2 <= n <= 105
0 <= favorite[i] <= n - 1
favorite[i] != i
题解
class Solution {
public:
int maximumInvitations(vector<int>& favorite) {
int n=favorite.size();
vector<int> indeg(n,0);
vector<bool> visit(n,false);
vector<int> depth(n,1);
//计算入度
for(int i=0;i<n;i++)
{
indeg[favorite[i]]++;
}
//拓扑排序
queue<int> q;
for(int i=0;i<n;i++)
{
if(!indeg[i])
{
q.push(i);
visit[i]=true;
depth[i]=1;//
}
}
while(!q.empty())
{
int v=q.front();
q.pop();
int w=favorite[v];
depth[w]=max(depth[w],depth[v]+1);//
if(--indeg[w]==0)
{
visit[w]=true;
q.push(w);
}
}
int ans=1,total=0;
for(int i=0;i<n;i++)
{
if(!visit[i])
{
visit[i]=true;
int j=favorite[i];
if(favorite[j]==i)
{
visit[j]=true;
total+=depth[i]+depth[j];
}
else
{
int count=1;
while(j!=i)
{
visit[j]=true;
count++;
j=favorite[j];
}
ans=max(ans,count);
}
}
}
return max(ans,total);
}
};