使用BIT计算反转

时间:2012-07-16 02:33:23

标签: algorithm

我知道之前已经讨论过这个问题,但我有兴趣使用二进制索引树来做这个。我发现了 this 链接以显示如何操作。我没有完全按照说明进行操作。有人可以给我一个解释,为什么以下给出的是真的。

Create a BIT of size greater than n(no of elements). Iterate through array A (
let j be the index of loop),and for each element A[j] do:

1) Add j-sum(A[j]) to the number of inversions
2) add(A[j], 1) (i.e. add 1 to the position A[j] on BIT. This effectively 
counts the number of time value A[j] is seen so far)

我不明白为什么会这样。

1 个答案:

答案 0 :(得分:17)

当元素大于数组中跟随它的某个元素时,就会发生反转。

我们可以通过按第二个元素对它们进行分组来计算反转。例如,在数组[4,3,1,2]中,元素对(4,3),(4,1),(4,2),(3,1)和(3,2)是倒置。我们用第二个元素对它们进行分组,因此:[[(4,1),(3,1)],[(4,2),(3,2)],[(4,3)]]。

我们依次考虑每个元素,并计算它是第二个元素的反转次数。在该示例中,元素4是0反转中的第二个元素,元素3合1反转,元素1和2中的每个反转2个。

为了使任何给定的元素成为反转的第二个元素,在数组之前必须有一个更大的元素。

我们通过从左到右遍历数组来有效地执行计数,并始终使用BIT跟踪到目前为止遇到的每个值的元素数量。最初我们的频率表将是[0,0,0,0],因为我们根本没有看到任何元素。在我们访问4之后,我们更新其频率,给出[0,0,0,1]。在访问3,[0,0,1,1]等之后。

每次我们访问某个职位时,我们都会使用BIT来查明到目前为止访问过的元素数量是多少。因此,例如当我们遇到1时,BIT当前包含[0,0,1,1],表示到目前为止零1和2,一个3和一个4.通过添加值0 + 1 + 1 ,我们计算到目前为止大于1的元素数量。

添加所有这些个别计数会给出反转的总数。

请注意,通常,您必须使用坐标压缩才能使其高效。例如,如果您的初始数组包含A = [92,631,50,7]之类的数字,则不应分配包含数百个元素的BIT。而是对数组进行排序以确定7< 50< 92< 631,这允许我们分配等级7 => 1,50 => 2,92 => 3,631 => 4;然后用它的等级替换每个元素,给出B = [3,4,2,1]。由于B [i]> B,因此该阵列的反转次数与原始阵列的反转次数相同。 B [j]当且仅当A [i]> A [j]的。

(注意:真正的程序员可能会使用从零开始的索引。)