leetcode1615

题目描述

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

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

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

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

解题思路

设first 表示所有节点中度数的最大值,second\textit{second}second 表示所有节点中度数的次大值,实际我们只需要考虑度数为最大值与次大值的城市即可,其余即可城市可以无须考虑,原因如下:

已知最大值 first 与次大值 second,则此时可以知道当前最差的情况下,假设这两城市存在连接,则最大的网络秩为 first+second−1;
假设存在度数比 second小的城市 x,则此时 degree[x]<second,此时含有 xxx 构成的城市对的最大网络秩不超过 degree[x]+first,此时一定满足degree[x]+first ≤ second+first;

综上可以得出结论选择最大或者次大度数的城市一定是最优的。我们可以求出度数为 first,first 的城市集合 firstArr,同时求出度数为 second,second 的城市集合 secondArr。设城市的总数量为 nnn,道路的总数量为 m,集合 firstArr的数量为 x,则此时该集合可以构造的城市对数量为 x(x−1)/2 ,分以下几种情况来讨论:

如果 x=1,此时我们必须选择 firstArr中唯一的城市,另一个城市只能在 secondArr中选择,枚举 secondArr中的每个城市,找到最大的网络秩即可,此时需要的时间复杂度为 O(n);
如果 x>1时,分类讨论如下:

如果满足 x(x−1)/2>m(从x个城市中选2个城市组成的道路总和大于m) 时,此时集合 firstArr 一定存在一对城市,他们之间没有道路连接,此时最大的网络秩即为 2×first;

如果满足 x(x−1)/2≤m 时,此时枚举集合 firstArr中所有不同的城市对即可,此时不需要再考虑次大的城市集合 secondArr,因为此时一定满足 2×first−1≥first+second>2×second ,此时时间复杂度不超过 O(m);
因此通过以上分析,上述解法的时间复杂度为 O(n+m)

代码实现

class Solution {
    public int maximalNetworkRank(int n, int[][] roads) {
        int[] degree = new int[n];
        boolean[][] connected = new boolean[n][n];
        for (int i = 0; i < roads.length; i++) {
            int[] edge = roads[i];
            connected[edge[0]][edge[1]] = true;
            connected[edge[1]][edge[0]] = true;
            degree[edge[0]]++;
            degree[edge[1]]++;
        }
        List<Integer> firstA = new ArrayList<>(); // 最大度数集合
        List<Integer> secondA = new ArrayList<>();  // 次大度数集合
        int first = -1, second = -1;
        for (int i = 0; i < n; i++) {
            if (degree[i] > first) {
                second = first;
                secondA = new ArrayList<>(firstA);
                first = degree[i];
                firstA.clear();
                firstA.add(i);
            } else if (degree[i] == first) {
                firstA.add(i);
            } else if (degree[i] > second) {
                secondA.clear();
                second = degree[i];
                secondA.add(i);
            } else if (degree[i] == second) {
                secondA.add(i);
            }
        }

        if (firstA.size() == 1) {
            int f = firstA.get(0);
            for (int t :
                    secondA) {
                if (!connected[f][t]) {
                    return first + second;
                }
            }
            return first + second - 1;
        } else {
            int m = roads.length;
            if (firstA.size() * (firstA.size() - 1) / 2 > m) {
                return first * 2;
            }
            for (int u : firstA) {
                for (int v : firstA) {
                    if (u != v && !connected[u][v]) {
                        return first * 2;
                    }
                }
            }
            return first * 2 -1;

        }

    }
}

思路参考

思路

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值