mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-07 15:45:40 +08:00
0685.冗余连接II.md, 增加Java, Golang, Python的实现
This commit is contained in:
@ -39,7 +39,7 @@
|
||||
|
||||
**这说明题目中的图原本是是一棵树,只不过在不增加节点的情况下多加了一条边!**
|
||||
|
||||
还有**若有多个答案,返回最后出现在给定二维数组的答案。**这说明在两天边都可以删除的情况下,要删顺序靠后的!
|
||||
还有**若有多个答案,返回最后出现在给定二维数组的答案。**这说明在两条边都可以删除的情况下,要删顺序靠后的!
|
||||
|
||||
|
||||
那么有如下三种情况,前两种情况是出现入度为2的点,如图:
|
||||
@ -58,7 +58,7 @@
|
||||
|
||||
首先先计算节点的入度,代码如下:
|
||||
|
||||
```CPP
|
||||
```cpp
|
||||
int inDegree[N] = {0}; // 记录节点入度
|
||||
n = edges.size(); // 边的数量
|
||||
for (int i = 0; i < n; i++) {
|
||||
@ -70,7 +70,7 @@ for (int i = 0; i < n; i++) {
|
||||
|
||||
代码如下:
|
||||
|
||||
```CPP
|
||||
```cpp
|
||||
vector<int> vec; // 记录入度为2的边(如果有的话就两条边)
|
||||
// 找入度为2的节点所对应的边,注意要倒叙,因为优先返回最后出现在二维数组中的答案
|
||||
for (int i = n - 1; i >= 0; i--) {
|
||||
@ -112,7 +112,7 @@ vector<int> getRemoveEdge(const vector<vector<int>>& edges)
|
||||
本题C++代码如下:(详细注释了)
|
||||
|
||||
|
||||
```CPP
|
||||
```cpp
|
||||
class Solution {
|
||||
private:
|
||||
static const int N = 1010; // 如题:二维数组大小的在3到1000范围内
|
||||
@ -174,7 +174,7 @@ public:
|
||||
inDegree[edges[i][1]]++; // 统计入度
|
||||
}
|
||||
vector<int> vec; // 记录入度为2的边(如果有的话就两条边)
|
||||
// 找入度为2的节点所对应的边,注意要倒叙,因为优先返回最后出现在二维数组中的答案
|
||||
// 找入度为2的节点所对应的边,注意要倒序,因为优先返回最后出现在二维数组中的答案
|
||||
for (int i = n - 1; i >= 0; i--) {
|
||||
if (inDegree[edges[i][1]] == 2) {
|
||||
vec.push_back(i);
|
||||
@ -203,16 +203,313 @@ public:
|
||||
## Java
|
||||
|
||||
```java
|
||||
|
||||
class Solution {
|
||||
|
||||
private static final int N = 1010; // 如题:二维数组大小的在3到1000范围内
|
||||
private int[] father;
|
||||
public Solution() {
|
||||
father = new int[N];
|
||||
|
||||
// 并查集初始化
|
||||
for (int i = 0; i < N; ++i) {
|
||||
father[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
// 并查集里寻根的过程
|
||||
private int find(int u) {
|
||||
if(u == father[u]) {
|
||||
return u;
|
||||
}
|
||||
father[u] = find(father[u]);
|
||||
return father[u];
|
||||
}
|
||||
|
||||
// 将v->u 这条边加入并查集
|
||||
private void join(int u, int v) {
|
||||
u = find(u);
|
||||
v = find(v);
|
||||
if (u == v) return ;
|
||||
father[v] = u;
|
||||
}
|
||||
|
||||
// 判断 u 和 v是否找到同一个根,本题用不上
|
||||
private Boolean same(int u, int v) {
|
||||
u = find(u);
|
||||
v = find(v);
|
||||
return u == v;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化并查集
|
||||
*/
|
||||
private void initFather() {
|
||||
// 并查集初始化
|
||||
for (int i = 0; i < N; ++i) {
|
||||
father[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在有向图里找到删除的那条边,使其变成树
|
||||
* @param edges
|
||||
* @return 要删除的边
|
||||
*/
|
||||
private int[] getRemoveEdge(int[][] edges) {
|
||||
initFather();
|
||||
for(int i = 0; i < edges.length; i++) {
|
||||
if(same(edges[i][0], edges[i][1])) { // 构成有向环了,就是要删除的边
|
||||
return edges[i];
|
||||
}
|
||||
join(edges[i][0], edges[i][1]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删一条边之后判断是不是树
|
||||
* @param edges
|
||||
* @param deleteEdge 要删除的边
|
||||
* @return true: 是树, false: 不是树
|
||||
*/
|
||||
private Boolean isTreeAfterRemoveEdge(int[][] edges, int deleteEdge)
|
||||
{
|
||||
initFather();
|
||||
for(int i = 0; i < edges.length; i++)
|
||||
{
|
||||
if(i == deleteEdge) continue;
|
||||
if(same(edges[i][0], edges[i][1])) { // 构成有向环了,一定不是树
|
||||
return false;
|
||||
}
|
||||
join(edges[i][0], edges[i][1]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public int[] findRedundantDirectedConnection(int[][] edges) {
|
||||
int[] inDegree = new int[N];
|
||||
for(int i = 0; i < edges.length; i++)
|
||||
{
|
||||
// 入度
|
||||
inDegree[ edges[i][1] ] += 1;
|
||||
}
|
||||
|
||||
// 找入度为2的节点所对应的边,注意要倒序,因为优先返回最后出现在二维数组中的答案
|
||||
ArrayList<Integer> twoDegree = new ArrayList<Integer>();
|
||||
for(int i = edges.length - 1; i >= 0; i--)
|
||||
{
|
||||
if(inDegree[edges[i][1]] == 2) {
|
||||
twoDegree.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理图中情况1 和 情况2
|
||||
// 如果有入度为2的节点,那么一定是两条边里删一个,看删哪个可以构成树
|
||||
if(!twoDegree.isEmpty())
|
||||
{
|
||||
if(isTreeAfterRemoveEdge(edges, twoDegree.get(0))) {
|
||||
return edges[ twoDegree.get(0)];
|
||||
}
|
||||
return edges[ twoDegree.get(1)];
|
||||
}
|
||||
|
||||
// 明确没有入度为2的情况,那么一定有有向环,找到构成环的边返回就可以了
|
||||
return getRemoveEdge(edges);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Python
|
||||
|
||||
```python
|
||||
|
||||
class Solution:
|
||||
|
||||
def __init__(self):
|
||||
self.n = 1010
|
||||
self.father = [i for i in range(self.n)]
|
||||
|
||||
|
||||
def find(self, u: int):
|
||||
"""
|
||||
并查集里寻根的过程
|
||||
"""
|
||||
if u == self.father[u]:
|
||||
return u
|
||||
self.father[u] = self.find(self.father[u])
|
||||
return self.father[u]
|
||||
|
||||
def join(self, u: int, v: int):
|
||||
"""
|
||||
将v->u 这条边加入并查集
|
||||
"""
|
||||
u = self.find(u)
|
||||
v = self.find(v)
|
||||
if u == v : return
|
||||
self.father[v] = u
|
||||
pass
|
||||
|
||||
|
||||
def same(self, u: int, v: int ):
|
||||
"""
|
||||
判断 u 和 v是否找到同一个根,本题用不上
|
||||
"""
|
||||
u = self.find(u)
|
||||
v = self.find(v)
|
||||
return u == v
|
||||
|
||||
def init_father(self):
|
||||
self.father = [i for i in range(self.n)]
|
||||
pass
|
||||
|
||||
def getRemoveEdge(self, edges: List[List[int]]) -> List[int]:
|
||||
"""
|
||||
在有向图里找到删除的那条边,使其变成树
|
||||
"""
|
||||
|
||||
self.init_father()
|
||||
for i in range(len(edges)):
|
||||
if self.same(edges[i][0], edges[i][1]): # 构成有向环了,就是要删除的边
|
||||
return edges[i]
|
||||
self.join(edges[i][0], edges[i][1]);
|
||||
return []
|
||||
|
||||
def isTreeAfterRemoveEdge(self, edges: List[List[int]], deleteEdge: int) -> bool:
|
||||
"""
|
||||
删一条边之后判断是不是树
|
||||
"""
|
||||
|
||||
self.init_father()
|
||||
for i in range(len(edges)):
|
||||
if i == deleteEdge: continue
|
||||
if self.same(edges[i][0], edges[i][1]): # 构成有向环了,一定不是树
|
||||
return False
|
||||
self.join(edges[i][0], edges[i][1]);
|
||||
return True
|
||||
|
||||
def findRedundantDirectedConnection(self, edges: List[List[int]]) -> List[int]:
|
||||
inDegree = [0 for i in range(self.n)]
|
||||
|
||||
for i in range(len(edges)):
|
||||
inDegree[ edges[i][1] ] += 1
|
||||
|
||||
# 找入度为2的节点所对应的边,注意要倒序,因为优先返回最后出现在二维数组中的答案
|
||||
towDegree = []
|
||||
for i in range(len(edges))[::-1]:
|
||||
if inDegree[edges[i][1]] == 2 :
|
||||
towDegree.append(i)
|
||||
|
||||
# 处理图中情况1 和 情况2
|
||||
# 如果有入度为2的节点,那么一定是两条边里删一个,看删哪个可以构成树
|
||||
if len(towDegree) > 0:
|
||||
if(self.isTreeAfterRemoveEdge(edges, towDegree[0])) :
|
||||
return edges[towDegree[0]]
|
||||
return edges[towDegree[1]]
|
||||
|
||||
# 明确没有入度为2的情况,那么一定有有向环,找到构成环的边返回就可以了
|
||||
return self.getRemoveEdge(edges)
|
||||
```
|
||||
|
||||
## Go
|
||||
|
||||
```go
|
||||
|
||||
// 全局变量
|
||||
var (
|
||||
n = 1010// 节点数量3 到 1000
|
||||
father = make([]int, n)
|
||||
)
|
||||
|
||||
// 并查集初始化
|
||||
func initialize() {
|
||||
for i := 0; i < n; i++ {
|
||||
father[i] = i
|
||||
}
|
||||
}
|
||||
|
||||
// 并查集里寻根的过程
|
||||
func find(u int) int {
|
||||
if u == father[u] {
|
||||
return u
|
||||
}
|
||||
father[u] = find(father[u])
|
||||
return father[u]
|
||||
}
|
||||
|
||||
// 将v->u 这条边加入并查集
|
||||
func join(u, v int) {
|
||||
u = find(u)
|
||||
v = find(v)
|
||||
if u == v {
|
||||
return
|
||||
}
|
||||
father[v] = u
|
||||
}
|
||||
|
||||
// 判断 u 和 v是否找到同一个根,本题用不上
|
||||
func same(u, v int) bool {
|
||||
u = find(u)
|
||||
v = find(v)
|
||||
return u == v
|
||||
}
|
||||
|
||||
// getRemoveEdge 在有向图里找到删除的那条边,使其变成树
|
||||
func getRemoveEdge(edges [][]int) []int {
|
||||
initialize()
|
||||
for i := 0; i < len(edges); i++ { // 遍历所有的边
|
||||
if same(edges[i][0], edges[i][1]) { // 构成有向环了,就是要删除的边
|
||||
return edges[i]
|
||||
}
|
||||
join(edges[i][0], edges[i][1])
|
||||
}
|
||||
return []int{}
|
||||
}
|
||||
|
||||
// isTreeAfterRemoveEdge 删一条边之后判断是不是树
|
||||
func isTreeAfterRemoveEdge(edges [][]int, deleteEdge int) bool {
|
||||
initialize()
|
||||
for i := 0; i < len(edges); i++ {
|
||||
if i == deleteEdge {
|
||||
continue
|
||||
}
|
||||
if same(edges[i][0], edges[i][1]) { // 构成有向环了,一定不是树
|
||||
return false
|
||||
}
|
||||
join(edges[i][0], edges[i][1])
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func findRedundantDirectedConnection(edges [][]int) []int {
|
||||
inDegree := make([]int, len(father))
|
||||
for i := 0; i < len(edges); i++ {
|
||||
// 统计入度
|
||||
inDegree[edges[i][1]] += 1
|
||||
}
|
||||
// 记录入度为2的边(如果有的话就两条边)
|
||||
// 找入度为2的节点所对应的边,注意要倒序,因为优先返回最后出现在二维数组中的答案
|
||||
twoDegree := make([]int, 0)
|
||||
for i := len(edges) - 1; i >= 0; i-- {
|
||||
if inDegree[edges[i][1]] == 2 {
|
||||
twoDegree = append(twoDegree, i)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理图中情况1 和 情况2
|
||||
// 如果有入度为2的节点,那么一定是两条边里删一个,看删哪个可以构成树
|
||||
if len(twoDegree) > 0 {
|
||||
if isTreeAfterRemoveEdge(edges, twoDegree[0]) {
|
||||
return edges[twoDegree[0]]
|
||||
}
|
||||
return edges[twoDegree[1]]
|
||||
}
|
||||
|
||||
// 处理图中情况3
|
||||
// 明确没有入度为2的情况,那么一定有有向环,找到构成环的边返回就可以了
|
||||
return getRemoveEdge(edges)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## JavaScript
|
||||
|
Reference in New Issue
Block a user