思路
可以把所有在同一行和同一列的石子连起来,这样就能构成若干个连通分量。而根据题意,不难想到每一个连通分量最后都能删到只剩一颗石子,所以答案显然就是石子总数减去连通分量的个数。
用并查集来维护连通关系。
代码
第一种是最直接的O(n²)连图。
class Solution { private: unordered_map<int, int> father; unordered_map<int, int> rank; public: int cnt; void init(int n) { cnt = n; for(int i = 0; i < n; i++) { father[i] = i; rank[i] = 1; } } int find(int x) { return father[x] == x ? x : father[x] = find(father[x]); } void merge(int x, int y) { int rootx = find(x); int rooty = find(y); if (rootx != rooty) { if (rank[rootx] < rank[rooty]) { swap(rootx, rooty); } father[rooty] = rootx; if (rank[rootx] == rank[rooty]) rank[rootx] += 1; cnt--; } } int removeStones(vector<vector<int>>& stones) { const int N = stones.size(); init(N); // for(int i = 0; i < N; i++) { // cout <<stones[i][0] <<" " << stones[i][1] << endl; // } for(int i = 0; i < N; i++) { for(int j = i + 1; j < N; j++) { if (stones[i][0] == stones[j][0] || stones[i][1] == stones[j][1]) { // printf("%d's father is %d\n", i, j); merge(i, j); } } } return N - cnt; } };
第二种是根据映射原理,直接对点的xy坐标链接,这样做的复杂度是O(n).
class Solution { private: int n = 20005; // 根据坐标范围而定 int father[20005]; // 并查集初始化 void init() { for (int i = 0; i < n; ++i) { father[i] = i; } } // 并查集里寻根的过程 int find(int u) { return u == father[u] ? u : father[u] = find(father[u]); } // 将v->u 这条边加入并查集 void join(int u, int v) { u = find(u); v = find(v); if (u == v) return ; father[v] = u; } // 判断 u 和 v是否找到同一个根 bool same(int u, int v) { u = find(u); v = find(v); return u == v; } public: int removeStones(vector<vector<int>>& stones) { init(); for (int i = 0; i < stones.size(); i++) join(stones[i][0], stones[i][1] + 10000); unordered_map<int, bool> umap; for (int i = 0; i < stones.size(); i++) { umap[find(stones[i][0])] = true; umap[find(stones[i][1] + 10000)] = true; } return stones.size() - umap.size(); } };
评论
还没有任何评论,你来说两句吧!