在java中有效地从大量数组中删除重复字符串?
我正在考虑从一个(未排序的)字符串数组中删除重复项的最佳方法-该数组包含数百万或数千万个stringz..该数组已预填充,因此优化目标只是删除DUP,而不是阻止DUP最初填充 我想先进行排序,然后进行二进制搜索,得到一个日志(n)搜索,而不是n(线性)搜索。这将给我nlogn+n搜索,虽然比未排序的(n^2)搜索要好,但这看起来仍然很慢。(也在考虑散列,但不确定吞吐量)在java中有效地从大量数组中删除重复字符串?,java,Java,我正在考虑从一个(未排序的)字符串数组中删除重复项的最佳方法-该数组包含数百万或数千万个stringz..该数组已预填充,因此优化目标只是删除DUP,而不是阻止DUP最初填充 我想先进行排序,然后进行二进制搜索,得到一个日志(n)搜索,而不是n(线性)搜索。这将给我nlogn+n搜索,虽然比未排序的(n^2)搜索要好,但这看起来仍然很慢。(也在考虑散列,但不确定吞吐量) 请帮忙!正在寻找一种既能解决速度问题又能解决内存问题的高效解决方案,因为在不使用Collections API的情况下涉及数百
请帮忙!正在寻找一种既能解决速度问题又能解决内存问题的高效解决方案,因为在不使用Collections API的情况下涉及数百万字符串 直到你的最后一句话,答案对我来说似乎是显而易见的:如果你需要保持秩序,请使用
HashSet
或LinkedHashSet
:
HashSet<String> distinctStrings = new HashSet<String>(Arrays.asList(array));
HashSet distinctStrings=新的HashSet(Arrays.asList(array));
如果不能使用集合API,请考虑建立自己的哈希集…但是,在给出不想使用collections API的原因之前,很难给出更具体的答案,因为这个原因可能会排除其他答案。
您好,您需要将它们放入数组中吗。使用散列值(如集合)来使用集合会更快。这里每个值都是唯一的,因为它的散列值是唯一的 如果将所有条目放入集合类型。你可以使用 HashSet(int initialCapacity)
构造函数来防止运行时内存扩展
Set<T> mySet = new HashSet<T>(Arrays.asList(someArray))
Set mySet=newhashset(Arrays.asList(someArray))
如果不需要扩展内存,Arrays.asList()的运行时为O(n)。我建议您在数组上使用修改后的mergesort。在合并步骤中,添加逻辑以删除重复值。此解决方案的复杂性为n*log(n),如果需要,可以就地执行(在这种情况下,就地执行比使用普通mergesort要困难一些,因为相邻部分可能包含删除的重复项的间隙,在合并时也需要关闭这些间隙)
有关mergesort的更多信息,请参见,因为这是一个面试问题,我认为他们希望您提出自己的实现,而不是使用set api 您可以构建一个二叉树并创建一个空数组来存储结果,而不是先对其进行排序然后再进行比较 数组中的第一个元素将是根
遍历需要O(n),搜索二叉树需要O(logn)(插入只需要O(1),因为您只是附加它,而不是重新分配/平衡树),因此总数应该是O(nlogn)。分析 让我们进行一些分析:
创建一个hashset来处理这个任务太昂贵了。很明显,事实上,他们告诉您不要使用Collections API的全部目的是因为他们不想听到hash这个词。这就剩下下面的代码了 请注意,在对数组排序后,您向他们提供了二进制搜索:这毫无意义,这可能是您的建议被拒绝的原因 备选案文1:
public static void removeDuplicates(String[] input){
Arrays.sort(input);//Use mergesort/quicksort here: n log n
for(int i=1; i<input.length; i++){
if(input[i-1] == input[i])
input[i-1]=null;
}
}
publicstaticvoidremoveduplices(字符串[]输入){
Arrays.sort(输入);//在此处使用mergesort/quicksort:n log n
对于(inti=1;iO.K.,如果他们想要超高速,让我们尽可能多地使用字符串的哈希码
循环遍历数组,获取每个字符串的哈希代码,并将其添加到您喜爱的数据结构中。由于不允许使用集合,请使用位集。请注意,您需要两个位集,一个为正数,一个为负数,它们都将是巨大的
使用另一个位集在数组中再次循环。True表示字符串通过。如果该位集中不存在该字符串的哈希代码,则可以将其标记为True。否则,将其标记为可能重复,或标记为false。在进行此操作时,计算可能重复的数量
将所有可能的重复项收集到一个名为possibleDuplicates的大字符串[]中。对其进行排序
现在检查原始数组中可能存在的重复项,并在可能的重复项中进行二进制搜索。如果存在,那么,您仍然被卡住了,因为您希望只包含一次,而不是所有其他时间。因此,您需要另一个数组。混乱,我必须
public static String[] removeDuplicates(String[] input){
Arrays.sort(input);//Use mergesort here: n log n
int size = 1;
for(int i=1; i<input.length; i++){
if(input[i-1] != input[i])
size++;
}
System.out.println(size);
String output[] = new String[size];
output[0]=input[0];
int n=1;
for(int i=1;i<input.length;i++)
if(input[i-1]!=input[i])
output[n++]=input[i];
//final step: either return output or copy output into input;
//here I just return output
return output;
}
public static String[] removeDuplicates(String[] input){
Arrays.sort(input);//Use mergesort/quicksort here: n log n
int outputLength = 0;
for(int i=1; i<input.length; i++){
// I think equals is safer, but are nulls allowed in the input???
if(input[i-1].equals(input[i]))
input[i-1]=null;
else
outputLength++;
}
// check if there were zero duplicates
if (outputLength == input.length)
return input;
String[] output = new String[outputLength];
int idx = 0;
for ( int i=1; i<input.length; i++)
if (input[i] != null)
output[idx++] = input[i];
return output;
}