最大化数组中的反转计数

时间:2018-07-09 13:36:53

标签: arrays algorithm data-structures

我们得到了一个未排序的整数数组A(可能有重复项),大小为N可能很大。我们可以计算索引为i < j的对的数量,为此我们将其称为A[i] < A[j]。{p>

我们可以从数组中更改最大一个元素,其成本等于绝对值之差(例如,如果将索引X上的元素替换为新的数字k,则成本{ {1}}是K)。 我们只能将此元素替换为数组中找到的其他元素。

我们要找到Y的最小可能值。

一些例子:

  • [1,2,2]应该返回1(将1更改为2,以便数组变为[2,2,2])
  • [2,2,3]应该返回1(将3更改为2)
  • [2,1,1]应该返回0(因为不需要更改)
  • [1,2,3,4]应该返回6(这已经是最小的可能值)
  • [4,4,5,5]应该返回3(这可以通过将前4更改为5或将4中的最后5更改为完成)

可通过朴素的| A[k] - K |解决方案找到对数,此处为Python:

X + Y

很容易编写暴力解决方案,例如:

O(n²)

def calc_x(arr): n = len(arr) cnt = 0 for i in range(n): for j in range(i+1, n): if arr[j] > arr[i]: cnt += 1 return cnt 中,我们可以使用AVL树或合并排序的某些变体为每个元素计算比其本身大的项目数。 但是,我们仍然必须搜索要更改的元素以及可以实现的改进。

这是一个面试问题,我想获得一些提示或见解,以了解如何有效地解决此问题(数据结构或算法)。

1 个答案:

答案 0 :(得分:0)

计算倒数时绝对会导致O(n log n)复杂度。

我们可以看到,当您更改索引k处的值时,您可以:

1)增加它,然后可能减少元素大于k的反演次数,但增加元素小于k的反演次数

2)降低它(发生相反的事情)

让我们尝试每次更改值时都不计数x。您需要知道什么?

在情况1):

您必须知道左边有多少个元素比新值v小,右边有多少个元素比您的值大。您可以很容易地在O(n)中进行检查。那么,你现在的x是多少?您可以使用以下公式对其进行计数:

prev_val - your previous value
prev_x - x that you've counted at the beginning of your program
prev_l - number of elements on the left smaller than prev_val
prev_r - number of elements on the right bigger than prev_val
v - new value
l - number of elements on the right smaller than v
r - number of elements on the right bigger than v

new_x = prev_x + r + l - prev_l - prev_r

在第二种情况下,您几乎要做相反的事情。

现在,您得到的像是O(n ^ 3)而不是O(n ^ 3 log n),这可能仍然很糟糕。不幸的是,这就是我现在想的全部。我一定会告诉你我是否会提出更好的建议。

编辑:内存限制如何?有没有?如果不是,则可以仅对数组中的每个元素在当前元素之前和之后设置两个元素集。然后,您可以在O(log n)中找到较小/较大的数量,从而使时间复杂度为O(n ^ 2 log n)。

编辑2:我们还可以尝试检查对于每个可能的值v,哪个元素最适合更改为值v。然后可以制作两组并在检查每个元素时从中添加/删除元素,使得时间复杂度为O(n ^ 2 log n)而不占用太多空间。因此算法为:

1)确定可以更改任何元素的每个值v,计算x

2)为每个可能的值v:

  • 制作两套,将所有元素压入第二套
  • 对于数组中的每个元素e: 在第一个集合中添加前一个元素(如果有),并从第二个集合中删除元素e,然后计算集合1和2中较大/较小元素的数量,并计算新的x

编辑3:您可以使用前缀sum作为值,而不是进行两组设置。已经是O(n ^ 2),但我认为我们可以做得更好。