题号 | 难度 | 掌握 |
---|---|---|
leetcode721 | middle | 练习 |
leetcode947 | middle | 上手学(实列题) |
原理
-
原理
-
必背模板
class UnionFind{ int[] p; public UnionFind(int n){ p=new int[n]; for(int i=0;i<n;i++){ p[i]=i; } } public void union(int index1,int index2){ p[find(index2)]=find(index1); } public int find(int index){ if(p[index]!=index){ p[index]=find(p[index]); } return p[index]; } }
实例
-
-
题目
给定一个列表 accounts,每个元素 accounts[i] 是一个字符串列表,其中第一个元素 accounts[i][0] 是 名称 (name),其余元素是 emails 表示该账户的邮箱地址。
现在,我们想合并这些账户。如果两个账户都有一些共同的邮箱地址,则两个账户必定属于同一个人。请注意,即使两个账户具有相同的名称,它们也可能属于不同的人,因为人们可能具有相同的名称。一个人最初可以拥有任意数量的账户,但其所有账户都具有相同的名称。
合并账户后,按以下格式返回账户:每个账户的第一个元素是名称,其余元素是 按字符 ASCII 顺序排列 的邮箱地址。账户本身可以以 任意顺序 返回。
e.g: 输入:accounts = [["John", "johnsmith@mail.com", "john00@mail.com"], ["John", "johnnybravo@mail.com"], ["John", "johnsmith@mail.com", "john_newyork@mail.com"], ["Mary", "mary@mail.com"]] 输出:[["John", 'john00@mail.com', 'john_newyork@mail.com', 'johnsmith@mail.com'], ["John", "johnnybravo@mail.com"], ["Mary", "mary@mail.com"]] 解释: 第一个和第三个 John 是同一个人,因为他们有共同的邮箱地址 "johnsmith@mail.com"。 第二个 John 和 Mary 是不同的人,因为他们的邮箱地址没有被其他帐户使用。 可以以任何顺序返回这些列表,例如答案 [['Mary','mary@mail.com'],['John','johnnybravo@mail.com'], ['John','john00@mail.com','john_newyork@mail.com','johnsmith@mail.com']] 也是正确的。
-
解
class Solution { public List<List<String>> accountsMerge(List<List<String>> accounts) { var mailnum=new HashMap<String,Integer>(); var mailname=new HashMap<String,String>(); int num=0; //查看有多少节点 for(List<String> account :accounts){ for(int i=1;i<account.size();i++){ String mail=account.get(i); if(!mailnum.containsKey(mail)){ mailnum.put(mail,num++); mailname.put(mail,account.get(0)); } } } //并查集合并大家 UnionFind uf=new UnionFind(num); for(List<String> account:accounts){ String firstemail=account.get(1); int firstindex=mailnum.get(firstemail); for(int i=2;i<account.size();i++){ uf.union(firstindex,mailnum.get(account.get(i))); } } //整理在一起 var indextoEmails=new HashMap<Integer,List<String>>(); for(String emil:mailnum.keySet()){ int index=uf.find(mailnum.get(emil)); List<String> account=indextoEmails.getOrDefault(index,new ArrayList<String>()); account.add(emil); indextoEmails.put(index,account); } List<List<String>> answer=new ArrayList<List<String>>(); for(List<String> emils:indextoEmails.values()){ Collections.sort(emils); String name =mailname.get(emils.get(0)); List<String> account=new ArrayList<String>(); account.add(name); account.addAll(emils); answer.add(account); } return answer; } } class UnionFind{ int[] p; public UnionFind(int n){ p=new int[n]; for(int i=0;i<n;i++){ p[i]=i; } } public void union(int index1,int index2){ p[find(index2)]=find(index1); } public int find(int index){ if(p[index]!=index){ p[index]=find(p[index]); } return p[index]; } }
-
-
-
题目:
n 块石头放置在二维平面中的一些整数坐标点上。每个坐标点上最多只能有一块石头。
如果一块石头的 同行或者同列 上有其他石头存在,那么就可以移除这块石头。
给你一个长度为 n 的数组 stones ,其中 stones[i] = [xi, yi] 表示第 i 块石头的位置,返回 可以移除的石子 的最大数量。
e.g: 输入:stones = [[0,0],[0,1],[1,0],[1,2],[2,1],[2,2]] 输出:5 解释:一种移除 5 块石头的方法如下所示: 1. 移除石头 [2,2] ,因为它和 [2,1] 同行。 2. 移除石头 [2,1] ,因为它和 [0,1] 同列。 3. 移除石头 [1,2] ,因为它和 [1,0] 同行。 4. 移除石头 [1,0] ,因为它和 [0,0] 同列。 5. 移除石头 [0,1] ,因为它和 [0,0] 同行。 石头 [0,0] 不能移除,因为它没有与另一块石头同行/列。
-
解:
class Solution { public int removeStones(int[][] stones) { int n=stones.length; UnionFind uf=new UnionFind(n); var x=new HashMap<Integer,Integer>(); var y=new HashMap<Integer,Integer>(); for(int i=0;i<n;i++){ if(!x.containsKey(stones[i][0])){ x.put(stones[i][0],i); } else{ uf.union(x.get(stones[i][0]),i); } if(!y.containsKey(stones[i][1])){ y.put(stones[i][1],i); } else{ uf.union(y.get(stones[i][1]),i); } } var all=new HashSet(); for(int i=0;i<n;i++){ int index=uf.find(i); if(!all.contains(index)){ all.add(index); } } return n-all.size(); } } class UnionFind{ int[] p; public UnionFind(int n){ p=new int[n]; for(int i=0;i<n;i++){ p[i]=i; } } public int find(int index){ if(p[index]!=index){ p[index]=find(p[index]); } return p[index]; } public void union(int index1,int index2){ p[find(index2)]=find(index1); } }
-