Redundant Connection II

In this problem, a rooted tree is a directed graph such that, there is exactly one node (the root) for which all other nodes are descendants of this node, plus every node has exactly one parent, except for the root node which has no parents.

The given input is a directed graph that started as a rooted tree with N nodes (with distinct values 1, 2, ..., N), with one additional directed edge added. The added edge has two different vertices chosen from 1 to N, and was not an edge that already existed.

The resulting graph is given as a 2D-array of edges. Each element of edges is a pair [u, v] that represents a directed edge connecting nodes u and v, where u is a parent of child v.

Return an edge that can be removed so that the resulting graph is a rooted tree of N nodes. If there are multiple answers, return the answer that occurs last in the given 2D-array.

Example 1:

Input: [[1,2], [1,3], [2,3]]
Output: [2,3]
Explanation: The given directed graph will be like this:
  1
 / \
v   v
2-->3

Example 2:

Input: [[1,2], [2,3], [3,4], [4,1], [1,5]]
Output: [4,1]
Explanation: The given directed graph will be like this:
5 <- 1 -> 2
     ^    |
     |    v
     4 <- 3

Note:

The size of the input 2D-array will be between 3 and 1000.Every integer represented in the 2D-array will be between 1 and N, where N is the size of the input array.

题目理解:用节点对“(父亲节点,孩子节点)”的方式给出一个有向图,这个有向图在删除一个节点对之后才能构成一棵二叉树,问应当删除哪一个节点对,当有多个答案的时候,返回最后出现的那个节点对

解题思路:设共有n个节点对,那么首先用一个n行2列的数组存储每一个节点的父亲节点;稍微分析一下我们可以知道,不能构成二叉树的有向图只有两种情况,一种是一个节点有多个父亲节点,即2->1<-3(2和3都是1的父亲节点),另一个是有环,即1->2->3->4->1;考虑第一种情况,删除的一定是(2,1)节点对或者(3,1)节点对,但是不知道要删除哪一个,这里我们可以做一个尝试,首先删除(2,1)节点对,然后判断剩下的有向图能不能构成二叉树,如果可以,就返回(2,1),否则返回(3,1);然后考虑后一种情况,这种情况更复杂,因为删除环上的任何一个节点对都有可能,因此我们需要尝试环上的所有节点对,找到下标最大的符合要求的节点对返回即可。

本题思路其实很简单,但是实现起来有点复杂,AC代码如下

class Solution {
	public int[] findRedundantDirectedConnection(int[][] edges){
		return helper(edges, new int[edges.length + 1]);
	}
    public int[] helper(int[][] edges, int[] ancestor) {
    	int len = edges.length;
        for(int i = 0; i < len + 1; i++)
        	ancestor[i] = i;
        for(int[] it : edges){
        	if(find(it[1], ancestor) != it[1]){
        		int m = it[0];
        		int n = it[1];
        		it[0] = 0;
        		it[1] = 0;
        		//show(edges);
        		if(helper(edges, new int[len + 1]) == null){
        			it[0] = m;
        			it[1] = n;
        			return new int[]{m, n};
        		}
        		else{
        			it[0] = m;
        			it[1] = n;
        			return new int[]{ancestor[n], n};
        		}
        	}
        	//剩下的问题在这里,如果出现了环,不知道应该解哪一个链
        	if(it[0] != 0 && find(it[0], ancestor) == it[1]){
        		//System.out.println(it[0] + " " + it[1]);
        		ancestor[it[1]] = it[0];
        		int child = it[0];
        		int pare = ancestor[child];
        		int maxPos = 0;
        		while(true){
        			int pos = findPos(new int[]{pare, child}, edges);
        			edges[pos][0] = 0;
        			edges[pos][1] = 0;
        			if(helper(edges, new int[len + 1]) == null){
        				maxPos = Math.max(maxPos, pos);
        			}
        			edges[pos][0] = pare;
        			edges[pos][1] = child;
        			child = pare;
        			pare = ancestor[child];
        			if(child == it[0])
        				break;
        		}
        		ancestor[it[1]] = it[1];
        		return edges[maxPos];
        	}
        	ancestor[it[1]] = it[0];
        }
        return null;
    }
    
    public int findPos(int[] it, int[][] edges){
    	for(int i = 0; i < edges.length; i++)
    		if(it[0] == edges[i][0] && it[1] == edges[i][1])
    			return i;
    	return 0;
    }
    
    public int find(int n, int[] ancestor){
    	while(ancestor[n] != n)
    		n = ancestor[n];
    	return n;
    }
}

猜你喜欢

转载自blog.csdn.net/m0_37889928/article/details/80329612