Problem
https://leetcode.com/problems/most-stones-removed-with-same-row-or-column/
分析
本质是个连通图问题,最大移动石头的个数 = total - islands
解法:Union-Find 或者 DFS
注意:
- 题目有ij的范围以及stones长度范围,需要注意空间使用大小,2D转1D的索引范围过大,存储上考虑用HashMap代替数组;
- String作为key是一个新思路,避免了每次转换1D;
- 需要使用权重来避免UF树过高
解法
public class MostStonesRemovedWithSameRowOrColumn {
private final Map<Integer, String> rows = new HashMap<>();
private final Map<Integer, String> cols = new HashMap<>();
private Map<String, String> union;
private Map<String, Integer> height;
private int rootsTotal = 0;
private int stonesTotal = 0;
public int removeStones(int[][] stones) {
union = new HashMap<>();
height = new HashMap<>();
for (int[] stone : stones) {
int i = stone[0];
int j = stone[1];
String index = i + " " + j;
union.put(index, index);
height.put(index, 0);
}
stonesTotal = stones.length;
rootsTotal = stones.length;
for (int[] stone : stones) {
int i = stone[0];
int j = stone[1];
String index = i + " " + j;
union.put(index, index);
if (rows.putIfAbsent(i, index) != null) {
union(index, rows.get(i));
}
if (cols.putIfAbsent(j, index) != null) {
union(index, cols.get(j));
}
}
return stonesTotal - rootsTotal;
}
private String root(String i) {
while (union.get(i) != i) {
i = union.get(i);
}
return i;
}
private void union(String i, String j) {
if (!connected(i, j)) {
String rootI = root(i);
String rootJ = root(j);
if (height.get(rootI) < height.get(rootJ)) {
union.put(rootI, rootJ);
Integer h = height.get(rootJ);
height.put(rootJ, ++h);
} else {
union.put(rootJ, rootI);
Integer h = height.get(rootI);
height.put(rootI, ++h);
}
rootsTotal--;
}
}
private boolean connected(String i, String j) {
String rootI = root(i);
String rootJ = root(j);
return rootI.equals(rootJ);
}
public static void main(String[] args) {
int[][] stones = new int[][]{{0, 0}, {0, 1}, {1, 0}, {1, 2}, {2, 1}, {2, 2}};
MostStonesRemovedWithSameRowOrColumn m = new MostStonesRemovedWithSameRowOrColumn();
StdOut.println(m.removeStones(stones));
}
}