簡體   English   中英

計算變化數組中的反轉

[英]Counting inversions in a changing array

您有一個大小為 (1 ≤ N ≤ 10^5) 的數組A[] 對於i = 0, 1, 2, ..., N - 1 ,如果所有大於i條目都減少到i ,我們希望確定數組中的反轉次數。

反演定義為兩個條目A[i]A[j] ,其中A[i] > A[j]和 i < j。

例子:

A[] = {3, 2, 1, 5, 2, 0, 5}

i = 0: {0, 0, 0, 0, 0, 0, 0}   Inversions: 0
i = 1: {1, 1, 1, 1, 1, 0, 1}   Inversions: 5
i = 2: {2, 2, 1, 2, 2, 0, 2}   Inversions: 7
i = 3: {3, 2, 1, 3, 2, 0, 3}   Inversions: 10
i = 4: {3, 2, 1, 4, 2, 0, 4}   Inversions: 10
i = 5: {3, 2, 1, 5, 2, 0, 5}   Inversions: 10
i = 6: {3, 2, 1, 5, 2, 0, 5}   Inversions: 10

所以你的輸出將是:

0
5
7
10
10
10
10

我知道如何通過 O(NlogN) 中的 MergeSort 找到數組中的反轉次數。 但是,如果我要為i每個值顯式生成每個數組,那將是一個 O(N^2logN) 算法,它不會及時傳遞。

我所做的一項觀察是,隨着i增加,倒數也會增加。 這是有道理的,因為當所有條目都為0 ,將沒有反轉(因為它已排序),但是隨着您不斷增加最大條目值,該條目可能會變得比以前具有相同值的條目大。

所以你可以從一個只有 0 的A[]開始,並不斷增加i 您可以使用您為先前值回答i確定較大的值的回答i 盡管如此,如果您掃描每個數組,您仍然會得到 O(N^2) 算法。

我怎么解決這個問題?

我會嘗試一下。 我們將按降序考慮查詢,因此從 i = N-1, ..., 下降到 0。首先,請注意,當我們將所有 A[j] > i 縮小到 i 時,任何 A [j] = i 將不再導致元素大於它的較小索引的反轉。

例如,假設我們有 A = [1, 2, 5, 4] 並且我們將 A[2] 縮小到 4。然后我們有 A = [1, 2, 4, 4] 並且我們的單個反轉消失了。 因此,對於每個 j,我們可以計算 A 中具有較小索引和較大值的元素的數量,並表示這個 V[j],即“它貢獻的反轉數量”。 我們找到原始數組中的反轉總數,然后對於每個 i = N-1,...,0 我們從所有 j 的反轉總數中刪除 V[j] 使得 V[j] = i .

讓我們將其應用於給出的示例。

A = [3, 2, 1, 5, 2, 0, 5]
V = [0, 1, 2, 0, 2, 5, 0]

然后,通過 i = 6, 5, 4, 3, 2, 1:

i = 6: A = [3, 2, 1, 5, 2, 0, 5], res = 10 (original calculation using merge sort)
i = 5: A = [3, 2, 1, 5, 2, 0, 5], res = 10 (subtract nothing because V[3] = V[6] = 0)
i = 4: A = [3, 2, 1, 4, 2, 0, 4], res = 10 (subtract nothing because no occurrences of 4)
i = 3: A = [3, 2, 1, 3, 2, 0, 3], res = 10 (10 - V[0] = 10)
i = 2: A = [2, 2, 1, 2, 2, 0, 2], res = 7 (10 - V[1] - V[4] = 10 - 1 - 2 = 7)
i = 1: A = [1, 1, 1, 1, 1, 0, 1], res = 5 (7 - V[2] = 7 - 2 = 5)
i = 0: A = [0, 0, 0, 0, 0, 0, 0], res = 0 (5 - V[5] = 5 - 5 = 0)

我們得到了我們想要的輸出。 實施細節可能有所不同; 您可以使用 Fenwick Tree 或類似的東西找到大於 A[j] 且索引較低的元素數量。 該算法在 O(NlogN) 時間內運行。

暫無
暫無

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

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