diff --git a/problems/0684.冗余连接.md b/problems/0684.冗余连接.md index c9eb33c4..bfbdeba9 100644 --- a/problems/0684.冗余连接.md +++ b/problems/0684.冗余连接.md @@ -10,6 +10,9 @@ # 684.冗余连接 + +[力扣题目链接](https://leetcode-cn.com/problems/redundant-connection/) + 树可以看成是一个连通且 无环 的 无向 图。 给定往一棵 n 个节点 (节点值 1~n) 的树中添加一条边后的图。添加的边的两个顶点包含在 1 到 n 中间,且这条附加的边不属于树中已存在的边。图的信息记录于长度为 n 的二维数组 edges ,edges[i] = [ai, bi] 表示图中在 ai 和 bi 之间存在一条边。 @@ -140,16 +143,161 @@ public: ## Java ```java +class Solution { + private int n; // 节点数量3 到 1000 + private int[] father; + public Solution() { + n = 1005; + 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; + } + + public int[] findRedundantConnection(int[][] edges) { + for (int i = 0; i < edges.length; i++) { + if (same(edges[i][0], edges[i][1])) { + return edges[i]; + } else { + join(edges[i][0], edges[i][1]); + } + } + return null; + } +} ``` ## Python ```python + +class Solution: + + def __init__(self): + """ + 初始化 + """ + self.n = 1005 + self.father = [i for i in range(self.n)] + + + def find(self, u): + """ + 并查集里寻根的过程 + """ + if u == self.father[u]: + return u + self.father[u] = self.find(self.father[u]) + return self.father[u] + + def join(self, u, v): + """ + 将v->u 这条边加入并查集 + """ + u = self.find(u) + v = self.find(v) + if u == v : return + self.father[v] = u + pass + + + def same(self, u, v ): + """ + 判断 u 和 v是否找到同一个根,本题用不上 + """ + u = self.find(u) + v = self.find(v) + return u == v + + def findRedundantConnection(self, edges: List[List[int]]) -> List[int]: + for i in range(len(edges)): + if self.same(edges[i][0], edges[i][1]) : + return edges[i] + else : + self.join(edges[i][0], edges[i][1]) + return [] ``` ## Go ```go + +// 全局变量 +var ( + n = 1005 // 节点数量3 到 1000 + father = make([]int, 1005) +) + +// 并查集初始化 +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 +} + +func findRedundantConnection(edges [][]int) []int { + initialize() + for i := 0; i < len(edges); i++ { + if same(edges[i][0], edges[i][1]) { + return edges[i] + } else { + join(edges[i][0], edges[i][1]) + } + } + return []int{} +} ``` ## JavaScript diff --git a/problems/0685.冗余连接II.md b/problems/0685.冗余连接II.md index 68d0376e..404813f3 100644 --- a/problems/0685.冗余连接II.md +++ b/problems/0685.冗余连接II.md @@ -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 vec; // 记录入度为2的边(如果有的话就两条边) // 找入度为2的节点所对应的边,注意要倒叙,因为优先返回最后出现在二维数组中的答案 for (int i = n - 1; i >= 0; i--) { @@ -112,7 +112,7 @@ vector getRemoveEdge(const vector>& edges) 本题C++代码如下:(详细注释了) -```CPP +```cpp class Solution { private: static const int N = 1010; // 如题:二维数组大小的在3到1000范围内 @@ -174,7 +174,7 @@ public: inDegree[edges[i][1]]++; // 统计入度 } vector 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 twoDegree = new ArrayList(); + 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 diff --git a/problems/0724.寻找数组的中心索引.md b/problems/0724.寻找数组的中心索引.md index b4115893..991ce647 100644 --- a/problems/0724.寻找数组的中心索引.md +++ b/problems/0724.寻找数组的中心索引.md @@ -9,6 +9,8 @@ # 724.寻找数组的中心下标 +[力扣题目链接](https://leetcode-cn.com/problems/find-pivot-index/) + 给你一个整数数组 nums ,请计算数组的 中心下标 。 数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。 @@ -87,15 +89,15 @@ class Solution { } ``` -## Python +## Python3 -```python3 +```python class Solution: def pivotIndex(self, nums: List[int]) -> int: numSum = sum(nums) #数组总和 leftSum = 0 for i in range(len(nums)): - if numSum - leftSum -nums[i] == leftSum: #左右和相等 + if numSum - leftSum -nums[i] == leftSum: #左右和相等 return i leftSum += nums[i] return -1 @@ -104,6 +106,24 @@ class Solution: ## Go ```go +func pivotIndex(nums []int) int { + sum := 0 + for _, v := range nums { + sum += v; + } + + leftSum := 0 // 中心索引左半和 + rightSum := 0 // 中心索引右半和 + for i := 0; i < len(nums); i++ { + leftSum += nums[i] + rightSum = sum - leftSum + nums[i] + if leftSum == rightSum{ + return i + } + } + return -1 +} + ``` ## JavaScript