LeetCode------冗余连接【1】】

题目链接  https://leetcode-cn.com/problems/redundant-connection/

在本问题中, 树指的是一个连通且无环的无向图。

输入一个图,该图由一个有着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

注意:

  • 输入的二维数组大小在 3 到 1000。
  • 二维数组中的整数在1到N之间,其中N是输入数组的大小。

思路:逐个去掉某一个边,测试其是否存在环

解法1,使用邻接矩阵,超内存。所以我把链接矩阵改成bool形式,连通使用1表示,否则使用0,(原来链接矩阵使用的是INT_MAX),勉强通过!

class Solution {
public:
    
    bool flag=true;bool INF=0;
    vector<int> findRedundantConnection(vector<vector<int>>& edges) {
        
        const int maxn=1000;
        
        vector<bool> temp(maxn,INF);
        vector< vector<bool> >  graph(maxn,temp);
        int mn=0;
        int n;
         
        
       for(int i=0;i<edges.size();i++)
       {
       	  for(int j=0;j<edges[i].size();j++)
       	  {  
			  mn=max(mn,edges[i][j]);
       	  }
       }
       n=mn;
   
	   for(int i=0;i<edges.size();i++)
       {
       	   int a=edges[i][0]-1;
       	   int b=edges[i][1]-1;
       	   graph[a][b]=1;
		   graph[b][a]=1;		  
       }
       
       for(int i=edges.size()-1;i>-1;i--)
       {
       	   
       	   int a=edges[i][0]-1;
       	   int b=edges[i][1]-1;
       	   graph[a][b]=INF;
		   graph[b][a]=INF;
           //print(graph,n);
		   flag=true;
		   dfs(graph);
		   if(!flag) ;//cout<<"have"<<endl;
		   else{ return edges[i];   break; } 
		   graph[a][b]=1;
		   graph[b][a]=1;		  
       }
       return {};	    
    }
    
 void  print(vector<vector<bool> >&graph,int n)
 {
       for(int i=0;i<n;i++)
       {
       	  for(int j=0;j<n;j++)
       	  {  
			  cout<<graph[i][j]<<" ";
       	  }
          cout<<endl; 
       }
 }
    
 void dfsVisit(vector<vector<bool> >&graph, int node, vector<int>&visit,
               vector<int>&father)
 {
    if(!flag) return;
	int n = graph.size();
    visit[node] = 1;
    //cout<<node<<"-\n";
    for(int i = 0; i < n; i++)
        if(i != node && graph[node][i]!= INF)
        {
            if(visit[i] == 1 && i != father[node])//ÕÒµ½Ò»¸ö»·
            {
                int tmp = node;
                //cout<<"cycle: ";
               // while(tmp != i)
                //{
                //    cout<<tmp<<"->";
                //    tmp = father[tmp];
                //}
                //cout<<tmp<<endl;
                flag=false;
            }
            else if(visit[i] == 0)
            {
                father[i] = node;
                dfsVisit(graph, i, visit, father);
            }
        }
     visit[node] = 2;
}
 
void dfs(vector<vector<bool> >&graph)
{
    int n = graph.size();
    vector<int> visit(n, 0); //visit°´ÕÕËã·¨µ¼ÂÛ22.3½Ú·ÖΪÈýÖÖ״̬
    vector<int> father(n, -1);// father[i] ¼Ç¼±éÀú¹ý³ÌÖÐiµÄ¸¸½Úµã
    for(int i = 0; i < n; i++)
        if(visit[i] == 0&&flag)
            dfsVisit(graph, i, visit, father);
}   
    
};

 

解法2:邻接表:

class Solution {
	public:

		bool flag=true;
		int INF=-1;//INT_MAX;
		vector<int> findRedundantConnection(vector<vector<int>>& edges) {
			int mn=0;
			int n;

			for(int i=0; i<edges.size(); i++) {
				for(int j=0; j<edges[i].size(); j++) {
					mn=max(mn,edges[i][j]);
				}
			}
			n=mn;
			vector< vector<int> > G(n); //临界表

			for(int i=0; i<edges.size(); i++) {
				int a=edges[i][0]-1;
				int b=edges[i][1]-1;
				G[a].push_back(b);
				G[b].push_back(a);
			}
			//print(G,n);
			for(int i=edges.size()-1; i>-1; i--) {

				int a=edges[i][0]-1;
				int b=edges[i][1]-1;
				int posa,posb;
				for(int j=0; j<G[a].size(); j++) {
					if (G[a][j]==b) {
						posa=j;
						break;
					}
				}
				G[a][posa]=INF;

				for(int j=0; j<G[b].size(); j++) {
					if (G[b][j]==a) {
						posb=j;
						break;
					}
				}
				G[b][posb]=INF;

				//print(G,n);
				flag=true;
				dfs(G);
				if(!flag) ;//cout<<"have"<<endl;
				else {
					return edges[i];
					break;
				}
				G[a][posa]=b;
				G[b][posb]=a;
			}
			return {};
		}

		void  print(vector<vector<int> >&graph,int n) {
			for(int i=0; i<graph.size(); i++) {
				for(int j=0; j<graph[i].size(); j++) {
					cout<<graph[i][j]<<" ";
				}
				cout<<endl;
			}
			cout<<"-------------"<<endl;
		}

		void dfsVisit(vector<vector<int> >&graph, int node, vector<int>&visit,
		              vector<int>&father) {
			if(!flag) return;
			int n = graph.size();
			visit[node] = 1;
			//cout<<node<<"-\n";
			for(int i = 0; i < graph[node].size(); i++)
				if(graph[node][i]!=INF) {
					int t=graph[node][i];
					if(visit[t]==1 && t!= father[node]) { //?òμ?ò????·
						int tmp = node;
						cout<<"cycle: ";
						while(tmp != t) {
							cout<<tmp<<"->";
							tmp = father[tmp];
						}
						cout<<tmp<<endl;
						flag=false;
					} else if(visit[t] == 0) {
						father[t] = node;
						dfsVisit(graph, t, visit, father);
					}
				}
			visit[node] = 2;
		}

		void dfs(vector<vector<int> >&graph) {
			int n = graph.size();
			vector<int> visit(n, 0); //visit°′????·¨μ???22.3?ú·??aèy??×′ì?
			vector<int> father(n, -1);// father[i] ????±éàú1y3ì?Diμ????úμ?
			for(int i = 0; i < n; i++)
				if(visit[i] == 0&&flag)
					dfsVisit(graph, i, visit, father);
		};

};

解法3 通过并查集

class Solution {
    public static int[] fa;
    public int find(int x){
        return fa[x]==x?x:(fa[x]=find(fa[x]));
    }
    public static int[] res;
    public void merge(int a,int b){
        int x=find(a);
        int y=find(b);
        if(x!=y){
            fa[x]=y;
        }else{
            res=new int[]{a,b};
        }
    }
    public int[] findRedundantConnection(int[][] edges) {
        if(edges==null||edges[0].length==0){
            return new int[2];
        }
        res=null;
        int n=edges.length;
        fa=new int[n+1];
        for(int i=1;i<=n;++i){
            fa[i]=i;
        }
        for(int i=0;i<n;++i){
            merge(edges[i][0],edges[i][1]);
            if(res!=null){
                return res;
            }
        }
        return new int[2];
    }
}

总结:

一、无向图回路的判断

    对于无向图,判断其是否有回路有四种方法,如下所示:

    1、利用深度优先搜索DFS,在搜索过程中判断是否会出现后向边(DFS中,连接顶点u到它的某一祖先顶点v的边),即在DFS对顶点进行着色过程中,若出现所指向的顶点为黑色,则此顶点是一个已经遍历过的顶点(祖先),出现了后向边,若完成DFS后,则图中有回路;

    2、在图的邻接表表示中,首先统计每个顶点的度,然后重复寻找一个度为1的顶点,将度为1和0的顶点从图中删除,并将与该顶点相关联的顶点的度减1,然后继续反复寻找度为1的,在寻找过程中若出现若干顶点的度都为2 sanzhangpai,则这些顶点组成了一个回路;否则,图中不存在回路。

    3、利用BFS,在遍历过程中,为每个节点标记一个深度deep,如果存在某个节点为v,除了其父节点u外,还存在与v相邻的节点w使得deep[v]<=deep[w]的,那么该图一定存在回路;
    4、用BFS或DFS遍历,最后判断对于每一个连通分量当中,如果边数m>=节点个数n,那么改图一定存在回路。因此在DFS或BFS中,我们可以统计每一个连通分量的顶点数目n和边数m,如果m>=n则return false;直到访问完所有的节点,return true。

二、有向图回路的判断

    对于有向图,判断其是否有回路的方法也有两种,如下所示:

    1、与无向图类似,若在DFS中出现后向边,即存在某一顶点被第二次访问到,则有回路出现;

    2、同样,利用拓扑排序的思想,通过这一步骤来执行拓扑排序,即重复寻找一个入度为0的顶点,将该顶点从图中删除,并将该顶点及其所有的出边从图中删除(即与该点相应的顶点的入度减1),最终若途中全为入度为1的点,则这些点至少组成一个回路。

    对于有向图,具体点就可得到如下分析:

    问题分析:如果图中存在回路,则必包含一个子图为回路。即该子图中所有顶点入度不为0且至少有边指向另外的顶点。
    算法:
    步骤1:按邻接表方式存储图。遍历与每个节点关联的边并统计每个节点的入度。需要O(n+m)次的运算。
    步骤2:删除所有入度为零的顶点及其相发出的边。并将被删除边所指向的顶点的入度减1。
    重复步骤2直到:
    (1)所有顶点被删除(则没有回路)或;
    (2)还有顶顶点但没有入度为零的顶点可删除(则存在回路)。
    算法复杂度分析:
    由于步骤二中的删除边的操作运算复杂度为O(m),删除节点的操作为O(n) 判断节点入度是否为0需要O(n+m)次运算。其中O(n)次为初始入度为零的节点,O(m)次为删除边后导致的入度为零的节点。于是整个算法复杂度为O(m+n)。


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值