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的点,如图:
|
那么有如下三种情况,前两种情况是出现入度为2的点,如图:
|
||||||
@ -58,7 +58,7 @@
|
|||||||
|
|
||||||
首先先计算节点的入度,代码如下:
|
首先先计算节点的入度,代码如下:
|
||||||
|
|
||||||
```CPP
|
```cpp
|
||||||
int inDegree[N] = {0}; // 记录节点入度
|
int inDegree[N] = {0}; // 记录节点入度
|
||||||
n = edges.size(); // 边的数量
|
n = edges.size(); // 边的数量
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
@ -70,7 +70,7 @@ for (int i = 0; i < n; i++) {
|
|||||||
|
|
||||||
代码如下:
|
代码如下:
|
||||||
|
|
||||||
```CPP
|
```cpp
|
||||||
vector<int> vec; // 记录入度为2的边(如果有的话就两条边)
|
vector<int> vec; // 记录入度为2的边(如果有的话就两条边)
|
||||||
// 找入度为2的节点所对应的边,注意要倒叙,因为优先返回最后出现在二维数组中的答案
|
// 找入度为2的节点所对应的边,注意要倒叙,因为优先返回最后出现在二维数组中的答案
|
||||||
for (int i = n - 1; i >= 0; i--) {
|
for (int i = n - 1; i >= 0; i--) {
|
||||||
@ -112,7 +112,7 @@ vector<int> getRemoveEdge(const vector<vector<int>>& edges)
|
|||||||
本题C++代码如下:(详细注释了)
|
本题C++代码如下:(详细注释了)
|
||||||
|
|
||||||
|
|
||||||
```CPP
|
```cpp
|
||||||
class Solution {
|
class Solution {
|
||||||
private:
|
private:
|
||||||
static const int N = 1010; // 如题:二维数组大小的在3到1000范围内
|
static const int N = 1010; // 如题:二维数组大小的在3到1000范围内
|
||||||
@ -174,7 +174,7 @@ public:
|
|||||||
inDegree[edges[i][1]]++; // 统计入度
|
inDegree[edges[i][1]]++; // 统计入度
|
||||||
}
|
}
|
||||||
vector<int> vec; // 记录入度为2的边(如果有的话就两条边)
|
vector<int> vec; // 记录入度为2的边(如果有的话就两条边)
|
||||||
// 找入度为2的节点所对应的边,注意要倒叙,因为优先返回最后出现在二维数组中的答案
|
// 找入度为2的节点所对应的边,注意要倒序,因为优先返回最后出现在二维数组中的答案
|
||||||
for (int i = n - 1; i >= 0; i--) {
|
for (int i = n - 1; i >= 0; i--) {
|
||||||
if (inDegree[edges[i][1]] == 2) {
|
if (inDegree[edges[i][1]] == 2) {
|
||||||
vec.push_back(i);
|
vec.push_back(i);
|
||||||
@ -203,16 +203,313 @@ public:
|
|||||||
## Java
|
## Java
|
||||||
|
|
||||||
```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
|
||||||
|
|
||||||
```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
|
||||||
|
|
||||||
```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
|
## JavaScript
|
||||||
|
Reference in New Issue
Block a user