首先,反演是无序列表中的数字对,其中两个数字中的较大者在较小数字的左侧。在以下列表中:[1、3、5、2、4、6]有3个反演:(3,2),(5,2)和(5,4)
这是我计算反转的代码:
def num_inv(array):
count = count_left = count_right = 0
if len(array)<=1:
return 0
mid = len(array)//2
left_array = array[:mid]
right_array = array[mid:]
count_left = num_inv(array[:mid])
count_right = num_inv(array[mid:])
i = j = k = 0
while i < len(left_array) and j < len(right_array):
if left_array[i] <= right_array[j]:
array[k] = left_array[i]
i+=1
else:
array[k] = right_array[i]
j +=1
count += len(left_array[i:])
k+=1
while i <len(left_array):
array[k] = left_array[i]
i+=1
k+=1
while j <len(right_array):
array[k] = right_array[j]
j+=1
k+=1
return count + count_left + count_right
在我的测试用例(大多数)中,它给出了正确的结果,但有时是错误的。您能看看一下,告诉我代码有什么问题吗?我花了很多时间进行调试,因此我需要重新看一下代码。
测试用例:t4输出不正确的结果
t1 = [1,3,5,2,4,6]
print("Testing using", t1)
print("Expecting:", 3)
print("Returned:", num_inv(t1))
t2 = [1,5,3,2,4]
print("\nTesting using", t2)
print("Expecting:", 4)
print("Returned:", num_inv(t2))
t3 = [5,4,3,2,1]
print("\nTesting using", t3)
print("Expecting:", 10)
print("Returned:", num_inv(t3))
t4 = [1,6,3,2,4,5]
print("\nTesting using", t4)
print("Expecting:", 5)
print("Returned:", num_inv(t4))
t5 = [1,2,3,4,5,6]
print("\nTesting using", t5)
print("Expecting:", 0)
print("Returned:", num_inv(t5))
答案 0 :(得分:2)
首先,在第一个left_array[i] <= right_array[j]
循环中比较while
,然后从right_array[i]
复制。这一定是一个错误,但这并不是最重要的。
此更正之后,我在您的代码中添加了一行,即第一个while循环中的诊断print()
语句:
while i < len(left_array) and j < len(right_array):
if left_array[i] <= right_array[j]:
array[k] = left_array[i]
i+=1
else:
array[k] = right_array[j]
j +=1
print("Counting as inversions of", array[k], ":", left_array[i:])
count += len(left_array[i:])
k+=1
然后我运行您的测试t4
,并获得以下输出:
Testing using [1, 6, 3, 2, 4, 5]
Expecting: 5
Counting as inversions of 3 : [6]
Counting as inversions of 2 : [6, 3]
Counting as inversions of 4 : [6, 3]
Counting as inversions of 5 : [6, 3]
Returned: 7
明白吗?当您找到一对反向时,就无法像您的代码那样假定left_array
的其余部分都由反向(即,大于array[k]
的数字)组成。这里,4和5相对于3不会倒置。您必须进行不同的计数。
答案 1 :(得分:0)
类似的事情似乎起作用。
(它会生成实际的反演及其索引,而不仅仅是计数。)
def find_inversions(arr):
for i, ival in enumerate(arr):
for j in range(i + 1, len(arr)):
jval = arr[j]
if jval < ival:
yield (i, j), (ival, jval)
for case, expected in (
([1, 3, 5, 2, 4, 6], 3),
([1, 5, 3, 2, 4], 4),
([5, 4, 3, 2, 1], 10),
([1, 6, 3, 2, 4, 5], 5),
([1, 2, 3, 4, 5, 6], 0),
):
n = len(list(find_inversions(case)))
print(case, n, expected)
输出
[1, 3, 5, 2, 4, 6] 3 3
[1, 5, 3, 2, 4] 4 4
[5, 4, 3, 2, 1] 10 10
[1, 6, 3, 2, 4, 5] 5 5
[1, 2, 3, 4, 5, 6] 0 0
编辑:这是另一种不是O(N ^ 2)的方法。例如,速度约为66%。 range(100)
,而range(500)
的速度快2倍。
def find_inversions_2(arr):
seen_indices = defaultdict(set)
for index, value in enumerate(arr):
seen_indices[value].add(index)
for seen_val in seen_indices:
if seen_val > value:
for seen_index in seen_indices[seen_val]:
yield (seen_index, index), (seen_val, value)