题目描述
n
座城市和一些连接这些城市的道路 roads
共同组成一个基础设施网络。每个 roads[i] = [ai, bi]
都表示在城市 ai
和 bi
之间有一条双向道路。
两座不同城市构成的 城市对 的 网络秩 定义为:与这两座城市 直接 相连的道路总数。如果存在一条道路直接连接这两座城市,则这条道路只计算 一次 。
整个基础设施网络的 最大网络秩 是所有不同城市对中的 最大网络秩 。
给你整数 n
和数组 roads
,返回整个基础设施网络的 最大网络秩 。
示例:
输入:n = 4, roads = [[0,1],[0,3],[1,2],[1,3]]
输出:4
解释:城市 0 和 1 的网络秩是 4,因为共有 4 条道路与城市 0 或 1 相连。位于 0 和 1 之间的道路只计算一次。
解题思路
最开始甚至没读懂题,简单来说,就是求图中2个结点所连接边的数目和的最大值,其中若该两节点直接相连,结果需要 -1。
知道要做什么,思路是不是一下就清晰起来啦?大体思路如下:
- 统计各结点的度;
- 遍历存储结点度的数组,查询最大与次大度;
- 判断最大与次大几点是否直接相连,若相连最后结果减一。
维护结点的度可以用一维数组。至于维护结点间的连接关系,这里使用二维数组创建邻接矩阵,虽然是稀疏的,但好在查询效率高,算是拿空间换时间的无奈之举。若有更好的解决方式,欢迎评论区指正。
最后就是如何取最大与次大值。一开始的想着以时间复杂度 O(n)
的代价遍历数组求得:
int first = 0, second = 0;
int id1 = 0, id2 = 0;
for(int i = 0; i < n; i++){
if(first <= edges[i]){
second = first;
first = edges[i];
id2 = id1;
id1 = i;
}
}
但是,存在一个很严重的问题!对应first
的结点可能存在多个或first
的结点唯一而second
对应结点复数个!而复数个结点间,存在连接和不连接的情况,这就导致本来应为 2 * first
或 first + second
的结果返回 2 * first - 1
或 first + second - 1
,鲁棒性很差。
但是我实在是不想暴力枚举,于是提出利用map存储 <度的数值,[对应度的结点所组成的数组]>
的解决方案:
- 维护上述的map;
- 利用map按照key排序的特性,一次取最大、次大的度;
- 若最大度值对应的数组size > 1,表示最大、次大结点都在此数组中,遍历所有可能的结点对,存在不直接连接的结点对立即返回
2 * first
(相当于剪枝),若不存在,返回2 * first - 1
; - 若最大度值对应的数组size = 1,遍历次大度所对应的数组。存在非直接连接的结点对返回
first + second
,否则返回first + second - 1
。
代码实现
class Solution {
public:
int maximalNetworkRank(int n, vector<vector<int>>& roads) {
//维护结点度的数组
vector<int> edges(n);
//邻接矩阵维护连接关系
vector<vector<bool>> connect(n, vector<bool>(n));
for(auto& vec : roads){
edges[vec[0]]++;
edges[vec[1]]++;
connect[vec[0]][vec[1]] = true;
connect[vec[1]][vec[0]] = true;
}
//创建 <度的数值,[对应度的结点所组成的数组]> 的map
map<int, vector<int>> myMap;
for(int i = 0; i < n; i++){
myMap[edges[i]].push_back(i);
}
//利用map解决关键问题
auto it = myMap.end();
//迭代器指向最大度
it--;
//最大度结点有复数个
if(it->second.size() > 1){
for(int i = 0; i < it->second.size(); i++){
for(int j = i + 1; j < it->second.size(); j++){
if(!connect[it->second[i]][it->second[j]]) return 2 * it->first;
}
}
return 2 * it->first - 1;
}else{
//最大度结点唯一
//对应结点编号
int maxId = it->second[0];
//最大度值
int maxDeg = it->first;
//指向次大度
it--;
for(int i = 0; i < it->second.size(); i++){
if(!connect[maxId][it->second[i]]) return maxDeg + it->first;
}
return maxDeg + it->first - 1;
}
}
};
运行结果:
额。。。还不错!