假设我有一个字符串哈希集的向量:
Vector<HashSet<String>> strSetVector = new Vector<HashSet<String>>();
我有4个包含以下字符串的哈希集:
"A", "B"
"C", "D"
"B", "C"
"E", "F"
我想组合至少有一个共同值的集合,以便最终得到:
"A", "B","C", "D"
"E", "F"
显而易见的解决方案是通过向量和每个hashset多次迭代以找到常见值,但这需要一段时间来处理矢量大小为1000+和HashSets的大小高达100.我还必须去如果我合并一个hashset以查看是否现在有其他可以合并的hashsets,那么再次通过该过程。例如,第一次向量迭代会将B,C组合成A,B,这样我最终会得到:
"A", "B", "C"
"C", "D"
"E", "F"
vector / hashset的下一次迭代:
"A", "B", "C", "D"
"E", "F"
vector / hashset的下一次迭代找不到任何常见的字符串,因此没有任何东西可以合并,我会完成。
我想要一个更优雅的解决方案,看似简单的问题。有什么想法吗?
答案 0 :(得分:2)
我不确定我是否理解正确的一切。我认为“最佳”解决方案也可能取决于集合的大小和列表。 (即,列表是否包含10个集合,其中每个集合包含100000个元素,或者它是否包含100000个集合,其中每个集合包含10个元素)。
但是到目前为止提到的数字(1000套100个元素),我认为可以使用一个相对简单的解决方案:
此代码段基于给定的示例,并打印一些调试信息,这可能会使过程更加清晰。它还存储了一个compactMap
,它将(可能合并的)集合的第一个元素映射到集合本身,以表示每个集合仅出现一次的集合。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class MergeListsTest
{
public static void main(String[] args)
{
List<Set<String>> sets = new ArrayList<Set<String>>();
sets.add(new LinkedHashSet<String>(Arrays.asList("A", "B")));
sets.add(new LinkedHashSet<String>(Arrays.asList("C", "D")));
sets.add(new LinkedHashSet<String>(Arrays.asList("B", "C")));
sets.add(new LinkedHashSet<String>(Arrays.asList("E", "F")));
//sets.add(new LinkedHashSet<String>(Arrays.asList("D")));
//sets.add(new LinkedHashSet<String>(Arrays.asList("D", "X")));
//sets.add(new LinkedHashSet<String>());
Collection<Set<String>> merged = computeMerged(sets);
System.out.println("Resulting sets:");
for (Set<String> s : merged)
{
System.out.println(s);
}
}
private static <T> Collection<Set<T>> computeMerged(List<Set<T>> sets)
{
Map<T, Set<T>> compactMap = new LinkedHashMap<T, Set<T>>();
Map<T, Set<T>> map = new LinkedHashMap<T, Set<T>>();
for (Set<T> set : sets)
{
System.out.println("Handle set "+set);
Set<T> combinedSet = new LinkedHashSet<T>(set);
for (T t : set)
{
Set<T> innerSet = map.get(t);
if (innerSet != null && !innerSet.isEmpty())
{
System.out.println("Element "+t+" was previously mapped to "+innerSet);
T first = innerSet.iterator().next();
compactMap.remove(first);
combinedSet.addAll(innerSet);
System.out.println("Combined set is now "+combinedSet);
}
}
if (!combinedSet.isEmpty())
{
System.out.println("Store a mapping from each element in "+combinedSet+" to this set");
T first = combinedSet.iterator().next();
compactMap.put(first, combinedSet);
for (T t : combinedSet)
{
map.put(t, combinedSet);
}
}
}
return compactMap.values();
}
}
答案 1 :(得分:0)
也许我最终得到了一个等效算法,但我认为这是一个图表,你想要找到connected components的集合。
我将构建大小为nxn的adjacency matrix(n个不同的元素,在这种情况下假定为100),使用它可以找到具有线性时间复杂度算法的连通元素集,例如在this answer中描述,其中包括Java代码。
要构建邻接矩阵,您必须处理每个HashSet并线性连接其元素,意味着O(n),并且任意,例如第一个与第二个,第二个与第三个,...(我不要我认为有必要完全互连所有这些。)
你的元素是字符串而不是字符的事实可能会使事情变得复杂,但你可以事先创建一个HashMap(字符串,整数)来将每个元素映射到给定的基数,并且初始扫描在时间上是线性的。对此映射的后续查找应具有时间复杂度O(1)。