947. Most Stones Removed with Same Row or Column
问题:
在坐标系中,给定一组坐标点。
我们假设,可以删除一个点,若存在与该点,x坐标相同or y坐标相同的其他点。
删除动作连续进行,最多可以有多少次删除动作?
Example 1: Input: stones = [[0,0],[0,1],[1,0],[1,2],[2,1],[2,2]] Output: 5 Example 2: Input: stones = [[0,0],[0,2],[1,1],[2,0],[2,2]] Output: 3 Example 3: Input: stones = [[0,0]] Output: 0 Note: 1 <= stones.length <= 1000 0 <= stones[i][j] < 10000
解法:并查集(Disjoint Set)
由本题题意可知:
拥有相同x坐标 or y坐标的点,可以进行删除动作。
我们将这些点连为一个组,从边缘开始删除,即可使删除动作最多,为point总数-1,最后留下一个点。
那么每个联通组,最后都剩下一个点,
总共的删除动作则为,总点数-联通组个数。
连通图问题,仍使用 并查集 来求解。
对每一个点,去判断已遍历过的点,是否与自己联通,若联通,则merge
最后计算联通组个数。
代码参考:
1 class Solution { 2 public: 3 int removeStones(vector<vector<int>>& stones) { 4 DisjointSet DS(stones.size()); 5 for(int i=1; i<stones.size(); i++) { 6 for(int j=0; j<i; j++) { 7 if(stones[i][0] == stones[j][0] || stones[i][1] == stones[j][1]) { 8 DS.merge(i,j); 9 } 10 } 11 } 12 //each group may leave 1 point, number of moves is sum(group point)-1 13 //move from leaf node. can make number of moves lagger. 14 return stones.size()-DS.getGroupCount(); 15 } 16 };
并查集 代码参考:
1 class DisjointSet { 2 public: 3 DisjointSet(int n):root(n,0), rank(n,0) { 4 for(int i=0; i<n; i++) { 5 root[i] = i; 6 } 7 } 8 int find(int i) { 9 if(i!=root[i]) { 10 root[i] = find(root[i]); 11 } 12 return root[i]; 13 } 14 bool merge(int x, int y) { 15 int x_root = find(x); 16 int y_root = find(y); 17 if(x_root == y_root) return false; 18 if(rank[x_root] > rank[y_root]) { 19 root[y_root] = x_root; 20 } else if(rank[y_root] > rank[x_root]) { 21 root[x_root] = y_root; 22 } else { 23 root[x_root] = y_root; 24 rank[y_root] ++; 25 } 26 return true; 27 } 28 int getGroupCount() { 29 int res=0; 30 for(int i=0; i<root.size(); i++) { 31 if(i==root[i]) res++; 32 } 33 return res; 34 } 35 private: 36 vector<int> root; 37 vector<int> rank; 38 };