1761. 一个图中连通三元组的最小度数

文章目录

Tag

【暴力枚举】【度数】【有向图】【无向图】


题目来源

1761. 一个图中连通三元组的最小度数

题目解读

现在有一个无向图,找出连通三元组中度数的最小值,如果没有三元组,则返回 -1。连通三元组指的是三个节点组成的集合并且两两之间有边。连通三元组的度数指的是排除指向三元组其他顶点的度数。


解题思路

方法一:无向图暴力枚举

看看数据 O ( n 3 ) O(n^3) O(n3) 的时间复杂度不会超时。于是直接枚举所有的三元组,找出最小的度数即可。

具体实现中,需要建立起顶点之间的邻接表 grids,两个顶点之间相连用 girds[i][j] = 1 表示。需要统计每个节点的度 degree[i]

枚举所有顶点时,如果 grids[i][j] = 1grids[j][k] = 1grids[k][i] = 1 时,我们则认为顶点 ijk 构成连通三元组。该连通三元组的度数为 degree[i] + degree[j] + degree[k] - 6

代码

cpp 复制代码
class Solution {
public:
    int minTrioDegree(int n, vector<vector<int>>& edges) {
        vector<vector<int>> grids(n, vector<int>(n));
        vector<int> degree(n);

        for (auto& edge : edges) {
            int x = edge[0] - 1, y = edge[1] - 1;
            grids[x][y] = grids[y][x] = 1;
            ++degree[x];
            ++degree[y];
        }

        int res = INT_MAX;
        for (int i = 0; i < n; ++i) {
            for (int j = i+1; j < n; ++j) {
                if (grids[i][j] == 1) {
                    for (int k = j+1; k < n; ++k) {
                        if (grids[j][k] == 1 && grids[k][i] == 1) {
                            res = min(res, degree[i] + degree[j] + degree[k] - 6);
                        }
                    }
                }
            }
        }
        return res == INT_MAX ? -1 : res;
    }
};

复杂度分析

时间复杂度: O ( n 3 ) O(n^3) O(n3), n n n 为顶点个数。

空间复杂度: O ( n 2 ) O(n^2) O(n2),因为需要存储顶点之间的关系即邻接矩阵的大小。

方法二:给无向图定向

因为本题的数据规模在 1 0 2 10^2 102 左右,暴力枚举的时间复杂度也在 1 0 7 10^7 107 左右,所以可以过。但是如果数据规模再大一些,比如 1 0 5 10^5 105,那么无向图的暴力枚举一定过不了。对这样规模的数据,如何解决呢?

我们考虑给无向图定向,具体地,如果图中的两个顶点 ij,它们之间有一条无向边:

  • 如果 degree[i] < degree[j],那么边的方向由 i 指向 j
  • 如果 degree[i] > degree[j],那么边的方向由 j 指向 i
  • 如果 degree[i] = degree[j],那么边的方向由编号较小的顶点指向编号较大的顶点;

我们给无向图进行以上规则的定向之后,任意一个节点的出度都不会超过 2 m \sqrt{2m} 2m , m m m 为图的边数,现在利用反证法进行证明。

假设节点 i 的出度大于 2 m \sqrt{2m} 2m ,那么节点 i 在原始无向图中的度数(出度+入度)大于 2 m \sqrt{2m} 2m ,那么顶点 i 指向的顶点在无向图中的入度大于 2 m \sqrt{2m} 2m ,其出度自然也大于 2 m \sqrt{2m} 2m 。因此总数大于 2 m ∗ 2 m = 2 m \sqrt{2m} * \sqrt{2m} = 2m 2m ∗2m =2m(第一个 2 m \sqrt{2m} 2m 表示从顶点 i 出去的边的数量),这与边数为 m m m 的图总度数为 2 m 2m 2m 矛盾。于是任意一个节点的出度都不会超过 2 m \sqrt{2m} 2m 。

接下来进行有向图上的连通三元组枚举计算就可以了。

实现中除了要使用一个数组 degree 记录各个顶点的度数之外,还会使用到哈希集合 grids 来记录原无向图中与各个顶点连接的所有顶点,使用二维数组 h 记录有向图。

代码

cpp 复制代码
class Solution {
public:
    int minTrioDegree(int n, vector<vector<int>>& edges) {

        vector<unordered_set<int>> grids(n);    // 原无向图
        vector<vector<int>> h(n);               // 有向图
        vector<int> degree(n);                  // 统计节点度数

        for (auto& edge : edges) {
            int x = edge[0] - 1, y = edge[1] - 1;
            grids[x].insert(y);
            grids[y].insert(x);
            ++degree[x];
            ++degree[y];
        }

        for (auto& edge : edges) {
            int x = edge[0] - 1, y = edge[1] - 1;
            if (degree[x] < degree[y] || (degree[x] == degree[y] && x < y)) {
                h[x].push_back(y);
            }
            else {
                h[y].push_back(x);
            }
        }

        int res = INT_MAX;
        for (int i = 0; i < n; ++i) {
            for (int j : h[i]) {
                for (int k : h[j]) {
                    if (grids[i].count(k)) {
                        res = min(res, degree[i] + degree[j] + degree[k] - 6);
                    }
                }
            }
        }
        return res == INT_MAX ? -1 : res;
    }
};

复杂度分析

时间复杂度: O ( n + m m ) O(n+m\sqrt{m}) O(n+mm ),因为枚举连通三元组第一层是枚举的是 顶点 i 指向顶点 j 构成的边,这一步部分时间复杂度为 O ( m ) O(m) O(m);第二层枚举 j 指向节点 k,由于 j 的出度不超过 2 m \sqrt{2m} 2m ,这一部分时间复杂度为 O ( m ) O(\sqrt{m}) O(m );第三层判断 k 是否与 i 构成无向边,使用哈希表,时间复杂度为 O ( 1 ) O(1) O(1)。其中, n n n 为顶点的数量, m m m 为图中的边数。

空间复杂度: O ( m ) O(m) O(m),邻接表使用的空间。


写在最后

以上就是本篇文章的内容了,感谢您的阅读。🍗🍗🍗

如果感到有所收获的话可以给博主点一个 👍 哦。

如果文章内容有任何错误或者您对文章有任何疑问,欢迎私信博主或者在评论区指出。💬💬💬

相关推荐
一直学习永不止步12 分钟前
LeetCode题练习与总结:最长回文串--409
java·数据结构·算法·leetcode·字符串·贪心·哈希表
Rstln1 小时前
【DP】个人练习-Leetcode-2019. The Score of Students Solving Math Expression
算法·leetcode·职场和发展
芜湖_1 小时前
【山大909算法题】2014-T1
算法·c·单链表
珹洺1 小时前
C语言数据结构——详细讲解 双链表
c语言·开发语言·网络·数据结构·c++·算法·leetcode
孙同学要努力1 小时前
C++知识整理day1——前置基础知识整理(命名空间、输入输出、函数重载、引用)
开发语言·c++
沐泽Mu1 小时前
嵌入式学习-C嘎嘎-Day05
开发语言·c++·学习
几窗花鸢1 小时前
力扣面试经典 150(下)
数据结构·c++·算法·leetcode
.Cnn2 小时前
用邻接矩阵实现图的深度优先遍历
c语言·数据结构·算法·深度优先·图论
2401_858286112 小时前
101.【C语言】数据结构之二叉树的堆实现(顺序结构) 下
c语言·开发语言·数据结构·算法·
Beau_Will2 小时前
数据结构-树状数组专题(1)
数据结构·c++·算法