[英]How to modify my method to search and then remove duplicates in O(N) or O(N * log N)?
我創建了一個方法來搜索重復項,然后將重復項索引存儲到另一個數組中。 然后我遍歷我的大數組並移動所有條目而不重復。
現在,我的問題是這使用了 O(N*N) 並且我正在使用額外的 memory 空間,因為我正在添加額外的數組。
這怎么可能呢? 假設我需要了解如何在不使用其他庫或 HashSet 的情況下完成此操作。
任何提示表示贊賞。
public void dups()
{
int[] index = new int[100];
int k = 0;
int n = 0;
int p = 0;
for (int i = 0; i < elements; i++)
for (int j = i + 1; j < elements; j++)
if(a[j].equals(a[i]))
index[k++] = i;
for (int m = 0; m < elements; m++)
if (m != index[p])
a[n++] = (T) a[m];
else
p++;
elements -= k;
}
通常,您無法在O(n)
找到重復項。
但是,可以在O(n*log n)
。 只需對數組排序( O(n*log n)
),然后可以在O(n)
掃描重復項。
另一方面,如果您可以使用哈希表(您可能不想做什么,如果您不想使用任何其他庫),則可以掃描數組並計算每個元素在數組中出現的頻率。 之后,您可以遍歷哈希表中的每個元素,並找到出現多次的那些元素。 這將花費預期的O(n)
運行時間,而不是確定性O(n)
。
最后,為什么我寫到您通常無法在O(n)
中找到重復項?
可以想象幾種特殊情況,在O(n)
可以找到重復項。 例如,您的數組只能包含0到99之間的數字。在這種情況下,您可以使用另一個數組(大小為100)來計算每個元素在數組中出現的頻率。 這與哈希表的工作方式相同,但其運行時間將是確定性O(n)
。
如果數組已經排序,則當然可以在O(n)
中查找重復項的另一個示例。
使用HashSet
在O(n)時間內執行此操作:
public <T> int removeDups(T[] original) {
HashSet<T> unique = new HashSet<T>();
for (T item: original) {
unique.add(item);
}
int size = unique.size();
int curr = 0;
for (int i = 0; i < original.length; i += 1) {
if (unique.remove(original[i])) {
original[curr] = original[i];
curr++;
}
}
return size;
}
請注意,這取決於您的列表元素的hashCode
方法,是否可以在HashSet
的存儲桶中正確分配元素以實現O(n)。 在最壞的情況下,這是O(n * m),其中m是唯一元素的數量,因此您絕對應該對其進行測量。
此實現在適當的位置修改數組,並返回唯一元素的數量。 盡管數組可能大於此數組,但超出該點的元素應視為垃圾。
它在列表上進行了一次遍歷以將項目添加到HashSet
(添加一項為O(1)),另一遍進行了更新以更新數組,因此為O(n)(同樣,假設哈希函數良好)。
array1 = [1,2,2,3,3,3,4,5,6,4,4,5,5,5,5,10,10,8,7,7,9,10]
array1.sort() # sorting is must
print(array1)
current = NONE
count = 0
# overwriting the numbers at the frontal part of the array
for item in array1:
if item != current:
array1[count] = item
count +=1
current=item
print(array1)#[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 5, 5, 5, 5, 6, 7, 7, 8, 9, 10, 10, 10]
print(array1[:count])#[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
最有效的方法是:
array1 = [1,2,2,3,3,3,4,5,6,4,4,5,5,5,5,10,10,8,7,7,9,10]
array1.sort()
print(array1)
print([*dict.fromkeys(array1)])#[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
#OR#
aa = list(dict.fromkeys(array1))
print( aa)#[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
由於哈希和等於比較,它不是O(n),它使用LinkedHashSet,它是Java標准庫的一部分,但可能足夠接近:
public void dups() {
Set<Integer> uniques = new LinkedHashSet<>();
for (int i = 0; i < elements.length; i++) {
uniques.add(elements[i]);
}
// todo: copy the set into a list, then call toArray() to get an array.
}
HashMap的默認實現是基於數組的,並且為O(n)。 因此,如果您想進行有趣的練習,則可以篩查HashMap的實現,以准確了解其哈希處理其鍵的方式。 基本上,它使用鍵的hashCode並使用它在預定位置(hashCode和arraylength-1)對數組進行索引,並將值存儲在該索引處。 如果要重復使用概念,將值用作鍵和值,則數組中將只有唯一的條目。
但是,如果您有大量重復項,但只有唯一值,那么最終將得到一個帶有許多空插槽的數組。 填充陣列后,只需循環遍歷一次即可刪除所有空插槽。 (例如:將所有非空條目復制到列表中)
這將是O(n),但需要2次傳遞-一次填充陣列,一次移除空插槽。 它還將需要一個與現有數組長度相同的附加數組,並需要一個較小的數組(或列表)來獲得唯一值的最終列表。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.