簡體   English   中英

確定數組是否包含重復值的最快方法是什么?

[英]What is the fastest way to determine if an array contains a repeated value?

該數組只能有一個重復項或根本沒有。

我需要該算法通過一些單元測試並有不同的版本通過不同的測試。

如果您能發現這兩種解決方案有任何問題或知道任何更快的解決方案,我將不勝感激。

散列:

對於大小為 UInt16.MaxValue 的數組,無論是否包含重復值,這都會導致持續時間測試失敗。

通過 - 空數組不包含重復
通過 - 沒有重復的小數組
通過 - 帶有重復的小數組(重復)
通過 - 帶有重復的小數組(重復)
通過 - 沒有重復的大數組(重復)
失敗 - 沒有重復的大數組(持續時間)
通過 - 帶有重復的大型數組(重復)
通過 - 帶有重復的大型數組(重復)
失敗 - 帶有重復的大型數組(持續時間)
失敗 - 合並

public bool ContainsRepeat(UInt16[] values, out UInt16 repeat)
        {
            //HASH SET//
            var set = new HashSet<UInt16>();
            repeat = 0;
            foreach (UInt16 value in values)
            {
                if (!set.Add(value))
                {
                    repeat = value;
                    return true;
                }
            }
            return false;
         }

排序然后二進制搜索重復項:

對於大小為 UInt16.MaxValue 的相同數組的持續時間測試失敗,但僅在沒有重復時才會失敗,但在有重復值時也無法返回正確的重復值,即使它適用於較小的數組。

通過 - 空數組不包含重復
通過 - 沒有重復的小數組
通過 - 帶有重復的小數組(重復)
通過 - 帶有重復的小數組(重復)
通過 - 沒有重復的大數組(重復)
失敗 - 沒有重復的大數組(持續時間)
通過 - 帶有重復的大型數組(重復)
失敗 - 帶有重復的大型數組(重復)
通過 - 帶有重復的大型數組(持續時間)
失敗 - 合並

public bool ContainsRepeat(UInt16[] values, out UInt16 repeat)
        {
            int findRepeatingElement(UInt16[] arr, int low, int high)
            {
                if (low > high)
                    return -1;

                int mid = (low + high) / 2;

                if (arr[mid] != mid + 1)
                {
                    if (mid > 0 && arr[mid] == arr[mid - 1])
                        return mid;

                    return findRepeatingElement(arr, low, mid - 1);
                }

                return findRepeatingElement(arr, mid + 1, high);
            }

            repeat = 0;
            if (values.Length <= 1)
            {
                return false;
            }

            Array.Sort(values);

            int index = findRepeatingElement(values, 0, values.Length - 1);

            if (index != -1)
            {
                repeat = values[index];
                return true;
            }
            else
            {
                return false;
            }


        }

這是我的第一篇文章,因此也歡迎任何有關格式化未來問題的意見:)

創建 UInt16.MaxValue 元素的新 bool 數組。 使用此數組(而不是 HashSet)作為探針來標記已看到的值並檢測后續重復項。

public bool ContainsRepeat(UInt16[] values, out UInt16 repeat)
{
  var seen = new bool[UInt16.MaxValue]; // O(k) space/time; fixed with very small C
  foreach (UInt16 value in values)      // O(n) time; n <= k, with small C
  {
    if (seen[value]) {
      repeat = value;
      return true;
    }
    seen[value] = true;
  }
  repeat = 0;
  return false;
}

這具有 O(n+k) 時間和 O(k) 空間(k = 范圍)的特性,固定。 在這種情況下,k = 2^16 ~ 65k 並且 n <= k 作為第一個重復項會終止搜索。

雖然兩種探測實現都是 O(n),但由於常數 (C) 較小,這應該比使用 HashSet 執行更好。 但是,對於具有 UInt32 范圍值(k = 范圍,其中 k >> n)的數據集,不建議使用這種方法,因為這樣會支付常量初始化和 memory 成本。

此特性類似於基數排序,並且與一般排序相關的空間與時間權衡。

也可以應用微優化(確保在實際條件下進行基准測試)。 清除現有數組與創建新數組; 或使用 int 和 increment+check vs. boolean check+set; 或者通過使用 unsafe 來避免索引范圍保護。

如果在“大”數組的情況下失敗了......祝“最快”好運。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM