像这样的东西应该工作。
版本 #2,第一个有错误。
我会使用Pair类,因为我们将从地图中提取所有条目并将它们放在Pair的向量中。
private static class Pair {
public Pair(Integer k, List<Integer> l) {
this.k = k;
this.s = new HashSet<Integer>();
this.s.addAll(l);
}
public Integer k;
public Set<Integer> s;
}
接下来,我们需要一个方法来检查两个集合是否有一些共同的元素。
public static boolean intersect(Set<Integer> a, Set<Integer> b) {
Set<Integer> tmp = new HashSet<Integer>(a);
tmp.retainAll(b);
return !tmp.isEmpty();
}
reduce 方法接受一个映射并返回一个新的缩减映射。
public static Map<Integer, List<Integer>> reduce(Map<Integer, List<Integer>> m) {
首先,我们将地图转换为Pair数组;这将允许有效地迭代和消除键。
int cnt = 0;
Pair[] entries = new Pair[m.size()];
for (Integer k : m.keySet()) {
List<Integer> l = m.get(k);
entries[cnt] = new Pair(k, l);
++cnt;
}
然后我们针对任何其他条目测试每一对;如果它们有共同的元素,我们删除后者,但首先我们将其合并到前者中。
for (int i = 0; i < m.size(); ++i) {
for (int j = i + 1; j < m.size(); ++j) {
if (entries[i] != null && entries[j] != null && intersect(entries[i].s, entries[j].s)) {
Set<Integer> si = entries[i].s;
Set<Integer> sj = entries[j].s;
si.addAll(sj);
entries[j] = null;
}
}
}
最后,我们将数组转换回映射,跳过删除的元素。
Map<Integer, List<Integer>> r = new HashMap<Integer, List<Integer>>();
for (int i = 0; i < m.size(); ++i)
if (entries[i] != null)
r.put(entries[i].k, new ArrayList<Integer>(entries[i].s));
return r;
}