-
Notifications
You must be signed in to change notification settings - Fork 7
305. Number of Islands II #329
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Notes: 1- LeetCode's own Union-Find solution has a bug and does not work. 2- In our solution, we did not need to create a grid as we can use the Union-find's parent array ( |
|
Die Programmlesbarkeit ist ziemlich gut. Es war mir leicht zu verstehen, auch aufgrund der Tatsache, dass das Programm für dessen Aufgabe einfach aufgebaut und moduliert ist. |
Es freut mich sehr, dass es dir gefällt, Erdem. |
|
I tried applying the rank system here, but it only made the code slower to 8 ms for some reason. class Solution {
public final static int[][] DIRECTIONS = { { 0, -1 }, { 0, 1 }, { -1, 0 }, { 1, 0 } };
int m = 0, n = 0;
int totalNode = 0;
int roots[];
int ranks[];
public List<Integer> numIslands2(int m, int n, int[][] positions) {
List<Integer> output = new ArrayList<>();
this.m = m;
this.n = n;
roots = new int[m * n + 1];
ranks = new int[m * n + 1];
for (int[] position : positions) {
int nodeId = getNodeId(position[0], position[1]);
if (roots[nodeId] != 0) {
output.add(totalNode);
continue;
}
roots[nodeId] = nodeId;
ranks[nodeId] = 1;
++totalNode;
countComponents(nodeId, generateNeigbors(nodeId, position));
output.add(totalNode);
}
return output;
}
int getNodeId(int x, int y) {
return n * x + y + 1;
}
final int INVALID_VERTEX = -1;
int[] generateNeigbors(int nodeId, int[] position) {
int[] neighbors = new int[4];
for (int i = 0; i < DIRECTIONS.length; i++) {
int x = position[0] + DIRECTIONS[i][0];
int y = position[1] + DIRECTIONS[i][1];
int adjacentNodeId = getNodeId(x, y);
if (!isValidNode(x, y, adjacentNodeId)) {
neighbors[i] = INVALID_VERTEX;
continue;
}
neighbors[i] = adjacentNodeId;
}
return neighbors;
}
boolean isValidNode(int x, int y, int adjacentNodeId) {
return (x >= 0 && x < m && y >= 0 && y < n && roots[adjacentNodeId] != 0);
}
public int countComponents(int nodeId, int[] neigbors) {
for (int neighbor : neigbors) {
if (neighbor == INVALID_VERTEX) {
continue;
}
int r1 = findRoot(nodeId);
int r2 = findRoot(neighbor);
if (r1 != r2) {
if (ranks[r1] <= ranks[r2]) {
roots[r1] = r2;
ranks[r2] += ranks[r1];
} else {
roots[r2] = r1;
ranks[r1] += ranks[r2];
}
totalNode--;
}
}
return totalNode;
}
private int findRoot(int key) {
if (key != roots[key]) {
roots[key] = roots[roots[key]];
key = roots[key];
return findRoot(key);
} else {
return key;
}
}
} |
|
I've found this solution that runs in 5ms. It does exactly the same things that the ranks solution I've commented above does, seemingly it should be even slower because of its extra calculations and usage of classes and such. It is unfortunately a bit illegible. class Solution {
public List<Integer> numIslands2(int m, int n, int[][] positions) {
List<Integer> ans = new ArrayList<>();
UnionFind uf = new UnionFind(m, n);
for (int[] position : positions) {
ans.add(uf.connect(position[0], position[1]));
}
return ans;
}
class UnionFind {
int sets;
int[] parent;
int[] size;
int col;
int row;
// int[] help;
public UnionFind (int m, int n) {
int len = m * n;
parent = new int[len];
size = new int[len];
col = n;
row = m;
sets = 0;
}
private int index(int r, int c) {
return r * col + c;
}
public int find(int i) {
if (parent[i] != i) {
parent[i] = find(parent[i]);
}
return parent[i];
}
private void union (int r1, int c1, int r2, int c2) {
if (r1 < 0 || r1 == row || c1 < 0 || c1 == col || r2 < 0 || r2 == row || c2 < 0 || c2 == col) {
return;
}
int i1 = index(r1, c1);
int i2 = index(r2, c2);
if (size[i1] == 0 || size[i2] == 0) {
return;
}
int f1 = find(i1);
int f2 = find(i2);
if (f1 != f2) {
if (size[f1] >= size[f2]) {
size[f1] += size[f2];
parent[f2] = f1;
} else {
size[f2] += size[f1];
parent[f1] = f2;
}
sets--;
}
}
public int connect(int r, int c) {
int index = index(r, c);
if (size[index] == 0) {
sets++;
parent[index] = index;
size[index] = 1;
union(r - 1, c, r, c);
union(r + 1, c, r, c);
union(r, c - 1, r, c);
union(r, c + 1, r, c);
}
return sets();
}
private int sets() {
return sets;
}
}
} |
Co-authored-by: ErdemT09 <63192680+ErdemT09@users.noreply.github.com>
I was going to say: It seems logically more efficient as we would create tree like faster paths under the node with higher rank. I think we should disregard the tests of LeetCode and actually add this. Creating an entire array that has as many elements as the total grid size might be perhaps slow. The Union class solutions does this too though. Whether to add this rank solution is remains at your decision then @altayhunoglu . |
Of course, we can add Erdem. Thanks for your help and nice idea about ranking. |
Fixes by Erdem: -adds ranking, formats code, renames methods with a more meaningful approach.
ErdemT09
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Problem itself is just another example of the "Union-find" problems. Even though I haven't really taken part in jobs and such, the code here is I think some fine example of production-business code. Easy to debug, easy to modify, easy to understand etc.
Approved.

Resolves: #234
When we add a new land; in some cases, it can decrease the total number of islands.
Because it can connect two distinct islands as a united component.
This reminds a quote by @ErdemT09, in the PR #200:
It means, this question can be interpreted as a variant of #200 and we can use Union-find here as well.
We use almost the same code with #200.
This time, instead of edge pairs of nodes, we have x, y
positionsarray.Therefore, we need to generate
edgeslist using these positions.We can interpret each tile in the grid, as a node. We need a
getNodeIdmethod to convert a position into anode-id.In this case, an edge is only possible between a node and its
validadjacent nodes.It is why we need the
DIRECTIONSarray.