diff --git a/src/main/java/graph/CloneGraph.java b/src/main/java/graph/CloneGraph.java new file mode 100644 index 0000000..1359476 --- /dev/null +++ b/src/main/java/graph/CloneGraph.java @@ -0,0 +1,57 @@ +package graph; +/** + * 题目: 133. 克隆图 (cloneGraph) + * 描述:给你无向 连通 图中一个节点的引用,请你返回该图的 深拷贝(克隆)。 + * + * 图中的每个节点都包含它的值 val(int) 和其邻居的列表(list[Node])。 + * + * class Node { + * public int val; + * public List neighbors; + * } + * + * 差值是一个正数,其数值等于两值之差的绝对值。 + * + 示例 1: + 输入:adjList = [[2,4],[1,3],[2,4],[1,3]] + 输出:[[2,4],[1,3],[2,4],[1,3]] + 解释: + 图中有 4 个节点。 + 节点 1 的值是 1,它有两个邻居:节点 2 和 4 。 + 节点 2 的值是 2,它有两个邻居:节点 1 和 3 。 + 节点 3 的值是 3,它有两个邻居:节点 2 和 4 。 + 节点 4 的值是 4,它有两个邻居:节点 1 和 3 。 + + * 链接:https://leetcode.cn/problems/clone-graph/ + */ +//不会做 +import graph.Node; + +import java.util.ArrayList; +import java.util.HashMap; + +public class CloneGraph { + private HashMap visited = new HashMap <> (); + public Node cloneGraph(Node node) { + if (node == null) { + return node; + } + + // 如果该节点已经被访问过了,则直接从哈希表中取出对应的克隆节点返回 + if (visited.containsKey(node)) { + return visited.get(node); + } + + // 克隆节点,注意到为了深拷贝我们不会克隆它的邻居的列表 + Node cloneNode = new Node(node.val, new ArrayList()); + // 哈希表存储 + visited.put(node, cloneNode); + + // 第一次 遇到某个邻居时,递归会深入——先把它自身拷贝出来(并加入 visited),再去拷贝它的邻居们…… + //如果再次遇到 同一个原节点(例如有环或多条路径到同一节点),就会走到第 2 步直接从 visited 里拿到已有的克隆节点,避免重复和死循环。 + for (Node neighbor: node.neighbors) { + cloneNode.neighbors.add(cloneGraph(neighbor)); + } + return cloneNode; + } +} diff --git a/src/main/java/graph/Node.java b/src/main/java/graph/Node.java new file mode 100644 index 0000000..59df4e5 --- /dev/null +++ b/src/main/java/graph/Node.java @@ -0,0 +1,21 @@ +package graph; + +import java.util.ArrayList; +import java.util.List; + +class Node { + public int val; + public List neighbors; + public Node() { + val = 0; + neighbors = new ArrayList(); + } + public Node(int _val) { + val = _val; + neighbors = new ArrayList(); + } + public Node(int _val, ArrayList _neighbors) { + val = _val; + neighbors = _neighbors; + } +} \ No newline at end of file diff --git a/src/main/java/union_find/CalcEquation.java b/src/main/java/union_find/CalcEquation.java new file mode 100644 index 0000000..1ad19b6 --- /dev/null +++ b/src/main/java/union_find/CalcEquation.java @@ -0,0 +1,32 @@ +package union_find; + +import java.util.List; + +/** + * 题目: 399. 除法求值 (calcEquation) + * 描述:给你一个变量对数组 equations 和一个实数值数组 values 作为已知条件,其中 equations[i] = [Ai, Bi] 和 values[i] 共同表示等式 Ai / Bi = values[i] 。每个 Ai 或 Bi 是一个表示单个变量的字符串。 + * + * 另有一些以数组 queries 表示的问题,其中 queries[j] = [Cj, Dj] 表示第 j 个问题,请你根据已知条件找出 Cj / Dj = ? 的结果作为答案。 + * + * 返回 所有问题的答案 。如果存在某个无法确定的答案,则用 -1.0 替代这个答案。如果问题中出现了给定的已知条件中没有出现的字符串,也需要用 -1.0 替代这个答案。 + * + * 注意:输入总是有效的。你可以假设除法运算中不会出现除数为 0 的情况,且不存在任何矛盾的结果。 + * + * 注意:未在等式列表中出现的变量是未定义的,因此无法确定它们的答案。 + * + 示例 1: + 输入:equations = [["a","b"],["b","c"]], values = [2.0,3.0], queries = [["a","c"],["b","a"],["a","e"],["a","a"],["x","x"]] + 输出:[6.00000,0.50000,-1.00000,1.00000,-1.00000] + 解释: + 条件:a / b = 2.0, b / c = 3.0 + 问题:a / c = ?, b / a = ?, a / e = ?, a / a = ?, x / x = ? + 结果:[6.0, 0.5, -1.0, 1.0, -1.0 ] + 注意:x 是未定义的 => -1.0 + + * 链接:https://leetcode.cn/problems/evaluate-division/ + */ +public class CalcEquation { + public double[] calcEquation(List> equations, double[] values, List> queries) { + return new double[1]; + } +} diff --git a/src/main/java/union_find/EquationsPossible.java b/src/main/java/union_find/EquationsPossible.java new file mode 100644 index 0000000..6df8c51 --- /dev/null +++ b/src/main/java/union_find/EquationsPossible.java @@ -0,0 +1,58 @@ +package union_find; +/** + * 题目: 990. 等式方程的可满足性 (equationsPossible) + * 描述:给定一个由表示变量之间关系的字符串方程组成的数组,每个字符串方程 equations[i] 的长度为 4,并采用两种不同的形式之一:"a==b" 或 "a!=b"。在这里,a 和 b 是小写字母(不一定不同),表示单字母变量名。 + * 只有当可以将整数分配给变量名,以便满足所有给定的方程时才返回 true,否则返回 false。 + * + 示例 1: + 输入:["a==b","b!=a"] + 输出:false + 解释:如果我们指定,a = 1 且 b = 1,那么可以满足第一个方程,但无法满足第二个方程。没有办法分配变量同时满足这两个方程。 + + * 链接:https://leetcode.cn/problems/satisfiability-of-equality-equations/ + */ +//并查集,第一次不会 +public class EquationsPossible { + public boolean equationsPossible(String[] equations) { + int[] parent = new int[26]; + for (int i = 0; i < 26; i++) { + parent[i] = i; + } + for (String str : equations) { + if (str.charAt(1) == '=') { + int index1 = str.charAt(0) - 'a'; + int index2 = str.charAt(3) - 'a'; + union(parent, index1, index2); + } + } + for (String str : equations) { + if (str.charAt(1) == '!') { + int index1 = str.charAt(0) - 'a'; + int index2 = str.charAt(3) - 'a'; + if (find(parent, index1) == find(parent, index2)) { + return false; + } + } + } + return true; + } + //合并x,y所属的集合,这里没有做按秩合并,默认合到index2所在集合 + public void union(int[] parent, int index1, int index2) { + // 先分别找到 index1 和 index2 的根节点,再把 root(index1) 的父指针指向 root(index2) + parent[find(parent, index1)] = find(parent, index2); + } + //查找 index 元素所在集合的根节点(同时做路径压缩) + public int find(int[] parent, int index) { + // 当 parent[index] == index 时,说明已经是根节点 + while (parent[index] != index) { + // 路径压缩:将当前节点直接挂到它父节点的父节点上 + // 这样可以让树变得更扁平,后续查找更快 + parent[index] = parent[parent[index]]; + // 跳到上一级,继续判断是否到根 + index = parent[index]; + } + // 循环结束时,index 即为根节点下标 + return index; + } + +} diff --git a/src/main/java/union_find/FindCircleNum.java b/src/main/java/union_find/FindCircleNum.java new file mode 100644 index 0000000..b0b2bd3 --- /dev/null +++ b/src/main/java/union_find/FindCircleNum.java @@ -0,0 +1,78 @@ +package union_find; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * 题目: 547. 省份数量 (findCircleNum) + * 描述:有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。 + * 省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。 + * 给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。 + * 返回矩阵中 省份 的数量。 + * + 示例 1: + 输入:isConnected = [[1,1,0],[1,1,0],[0,0,1]] + 输出:2 + + * 链接:https://leetcode.cn/problems/number-of-provinces/ + */ +public class FindCircleNum { + //并查集 + int find(int[] parent ,int index){ + while (parent[index]!=index){ + parent[index]=parent[parent[index]]; + index=parent[index]; + } + return index; + } + void union(int[] parent,int index1,int index2){ + parent[find(parent,index1)]=find(parent,index2); + } + public int findCircleNum(int[][] isConnected) { + int res=0; + int[]parent=new int[200]; + Setset=new HashSet<>(); + for (int i = 0; i < 200; i++) { + parent[i]=i; + } + int row=isConnected.length; + for (int i = 0; i < row; i++) { + for (int j = i+1; j < row; j++) { + if(isConnected[i][j]==1) + union(parent,i,j); + } + } + for (int i = 0; i < isConnected.length; i++) { + int father=find(parent,i); + if(!set.contains(father)){ + res++; + set.add(father); + } + } + return res; + } + + //深度优先搜索 + public int findCircleNum2(int[][] isConnected) { + int cities = isConnected.length; + boolean[] visited = new boolean[cities]; + int provinces = 0; + for (int i = 0; i < cities; i++) { + if (!visited[i]) { + dfs(isConnected, visited, cities, i); + provinces++; + } + } + return provinces; + } + + public void dfs(int[][] isConnected, boolean[] visited, int cities, int i) { + for (int j = 0; j < cities; j++) { + if (isConnected[i][j] == 1 && !visited[j]) { + visited[j] = true; + dfs(isConnected, visited, cities, j); + } + } + } +}