【图论+利用Map检索】1615. 最大网络秩

题目描述

n 座城市和一些连接这些城市的道路 roads 共同组成一个基础设施网络。每个 roads[i] = [ai, bi] 都表示在城市 aibi 之间有一条双向道路。

两座不同城市构成的 城市对网络秩 定义为:与这两座城市 直接 相连的道路总数。如果存在一条道路直接连接这两座城市,则这条道路只计算 一次 。

整个基础设施网络的 最大网络秩 是所有不同城市对中的 最大网络秩

给你整数 n 和数组 roads,返回整个基础设施网络的 最大网络秩

示例:
示例

输入:n = 4, roads = [[0,1],[0,3],[1,2],[1,3]]
输出:4
解释:城市 01 的网络秩是 4,因为共有 4 条道路与城市 01 相连。位于 01 之间的道路只计算一次。

解题思路

最开始甚至没读懂题,简单来说,就是求图中2个结点所连接边的数目和的最大值,其中若该两节点直接相连,结果需要 -1

知道要做什么,思路是不是一下就清晰起来啦?大体思路如下:

  1. 统计各结点的度;
  2. 遍历存储结点度的数组,查询最大与次大
  3. 判断最大与次大几点是否直接相连,若相连最后结果减一。

维护结点的度可以用一维数组。至于维护结点间的连接关系,这里使用二维数组创建邻接矩阵,虽然是稀疏的,但好在查询效率高,算是拿空间换时间的无奈之举。若有更好的解决方式,欢迎评论区指正。

最后就是如何取最大与次大值。一开始的想着以时间复杂度 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 * firstfirst + second 的结果返回 2 * first - 1first + second - 1 ,鲁棒性很差。

但是我实在是不想暴力枚举,于是提出利用map存储 <度的数值,[对应度的结点所组成的数组]> 的解决方案:

  1. 维护上述的map;
  2. 利用map按照key排序的特性,一次取最大、次大的度;
  3. 若最大度值对应的数组size > 1,表示最大、次大结点都在此数组中,遍历所有可能的结点对,存在不直接连接的结点对立即返回 2 * first (相当于剪枝),若不存在,返回 2 * first - 1
  4. 若最大度值对应的数组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;
        }
        
    }
};

运行结果:
result

额。。。还不错!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值