LeetCode-684/685 冗余连接

LeetCode-684:https://leetcode-cn.com/problems/redundant-connection/description/
题目描述:

在本问题中, 树指的是一个连通且无环的无向图。
输入一个图,该图由一个有着N个节点 (节点值不重复1, 2, …, N) 的树及一条附加的边构成。附加的边的两个顶点包含在1到N中间,这条附加的边不属于树中已存在的边。
结果图是一个以边组成的二维数组。每一个边的元素是一对[u, v] ,满足 u < v,表示连接顶点u 和v的无向图的边。
返回一条可以删去的边,使得结果图是一个有着N个节点的树。如果有多个答案,则返回二维数组中最后出现的边。答案边 [u, v] 应满足相同的格式 u < v。

示例 1:

输入: [[1,2], [1,3], [2,3]]
输出: [2,3]
解释: 给定的无向图为:

  1
 / \
2 - 3

示例 2:

输入: [[1,2], [2,3], [3,4], [1,4], [1,5]]
输出: [1,4]
解释: 给定的无向图为:

5 - 1 - 2
    |   |
    4 - 3

思路分析:

其实这道题的题意并不难,如题目所说去掉“冗余连接”,使之仍然连通。给定的图其实就是一个树上加了一条边,我们要做的就是找到数组中最后一个不影响图的连通性的边,那么我们从最后一条边开始向前枚举,找到一个符合条件的边之后程序就结束。具体做法如下,我们以找到的这条边作为参数进行 dfs,从任一点开始搜索,搜索到某点 s 则将其记录下来,然后遍历所有的边,对于每个边,判断是否是我们上面选定的“准备被去掉的边”,如果不是,我们进行下一步判断,看这个边中是否含有我们刚刚搜索过的点,有的话我们可以沿着这条边继续进行搜索,这里要注意,给定的 edges 数组并非邻接表,因此这次搜索有一点点不同,就是因为是无向图, s 可能是 e = (u,v) 中的 u 或者 v,要分情况讨论,而且还要判断另一个点是否被访问过,如果没访问过那么就可以递归的进行搜索。最终,如果所有点都被访问过了,那么返回这个边就行,否则进行下一次循环。

代码如下:

class Solution {
public:
    unordered_set <int> visited;
    vector<int> findRedundantConnection(vector<vector<int>>& edges) {
        for (int i = edges.size() - 1;i >= 0;i --){
            int u = edges[i][0],v = edges[i][1];
            visited.clear();
            dfs(edges,u,v,v);
            cout << visited.size() << endl;
            if(visited.size() == edges.size()){
                return edges[i];
            }
        }
    }
    void dfs(vector<vector<int>>& edges,int u,int v,int s){
        visited.insert(s);
        for(auto e : edges){
            if(!(e[0] == u && e[1] == v)){
                if(e[0] == s && visited.count(e[1]) == 0){
                    dfs(edges,u,v,e[1]);
                }
                else if(e[1] == s && visited.count(e[0]) == 0){
                    dfs(edges,u,v,e[0]);
                }
            }
        }
    }
};

LeetCode-685:https://leetcode-cn.com/problems/redundant-connection-ii/description/
思路分析:

这道题与 684 相比就是把无向图变成了有向图,总体思路变化不大。只不过搜索的起点要有所选择,在 684 题中从无向图的任何一点开始搜索都是 ok 的,但是这道题是有向图,那么就需要找到入度为 0 的点作为搜索的起点,特别的如果入度为 0 的点的个数大于 2 ,那么肯定不行。

代码如下:

class Solution {
public:
    unordered_set <int> visited;
    vector<int> findRedundantDirectedConnection(vector<vector<int>>& edges) {
        int n = 0,s,cnt;
        for(auto e : edges){
                n = max(max(e[0],e[1]),n);
        }
        auto start = vector <bool>(n + 1,0);
        for (int i = edges.size() - 1;i >= 0;i --){
            int u = edges[i][0],v = edges[i][1];
            visited.clear();
            for(int k = 1;k <= n;k ++){
                start[k] = 0;
            }
            cnt = 0;
            for(auto e : edges){
                if(e[0] == u && e[1] == v)
                    continue;
                start[e[1]] = true;
            }
            for(int j = 1;j <= n;j ++){
                if(start[j] == false){
                    cnt ++;
                    s = j;
                }
            }
            if(cnt != 1){
                continue;
            }
            dfs(edges,u,v,s);
            if(visited.size() == edges.size()){
                return edges[i];
            }
        }
    }
    void dfs(vector<vector<int>>& edges,int u,int v,int s){
        visited.insert(s);
        for(auto e : edges){
            if(!(e[0] == u && e[1] == v)){
                if(e[0] == s && visited.count(e[1]) == 0){
                    dfs(edges,u,v,e[1]);
                }
                // else if(e[1] == s && visited.count(e[0]) == 0){
                //     dfs(edges,u,v,e[0]);
                // }
            }
        }
    }
};

拓展:

事实上,对于 684 题来说,我们可以用并查集来做,即判断新来的边 e = (u,v) 的两个顶点 u v 是否已经连通,如果此两点已经连通,那么新来的边 e 就必为冗余边,也就是正确答案。

代码如下

class Solution {
public:
    vector<int> findRedundantConnection(vector<vector<int>>& edges) {
        int n = edges.size();
        auto p = vector <int> (n + 1);
        for(int i = 0;i <= n;i ++){
            p[i] = i;
        }
        for(auto e : edges){
            if(find(e[0],p) != find(e[1],p)){
                p[p[e[1]]] = p[e[0]];
            }
            else{
                return e;
            }
        }        
        return {};
    }
    int find(int x,vector <int>& p){
        return x == p[x] ? x : p[x] = find(p[x],p);
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值