[英]Count Inversion per Element
我想計算某些列表中每個元素的反轉次數 。 如果i < j
和list[i] > list[j]
則對(i, j)
是一個倒置。 許多算法都會計算這些對的總數,而我想對某些列表中的所有元素進行計數,這些元素多久是一次反轉對的一部分。
考慮例如以下列表: [4, 2, 3, 1]
有五個反轉對: (4, 2), (4, 3), (4, 1), (2, 1), (3, 1)
。 我知道您可以通過嵌套的for循環(或使用向量化)來獲取元素計數:
import numpy as np
lst = np.array([4,2,3,1])
inv_count = np.zeros(lst.size)
for i in np.arange(lst.size - 1):
idx = np.where(lst[i] > lst[(i+1):])[0] + i + 1
inv_count[idx] += 1
inv_count[i] += idx.size
產生正確的結果
array([3., 2., 2., 3.])
但這正在O(n^2)
(我認為),我想知道是否可以更有效地解決它。
我知道,例如下面所示的mergesort通常用於計數O(n log n)
總反轉,但是我不確定如何采用它來對每個元素進行計數?
def mergeSortInversions(arr):
if len(arr) == 1:
return arr, 0
else:
a = arr[:len(arr)//2]
b = arr[len(arr)//2:]
a, ai = mergeSortInversions(a)
b, bi = mergeSortInversions(b)
c = []
i = 0
j = 0
inversions = 0 + ai + bi
while i < len(a) and j < len(b):
if a[i] <= b[j]:
c.append(a[i])
i += 1
else:
c.append(b[j])
j += 1
inversions += (len(a)-i)
c += a[i:]
c += b[j:]
return c, inversions
您可以使用combinations()
和filter()
函數來構建帶反轉的列表:
from itertools import combinations
l = [4, 2, 3, 1]
list(filter(lambda x: x[0] > x[1], combinations(l, 2)))
# [(4, 2), (4, 3), (4, 1), (2, 1), (3, 1)]
您可以使用defaultdict()
來計算反轉:
from itertools import combinations
from collections import defaultdict
l = [4, 2, 3, 1]
dd = defaultdict(int)
for i, j in combinations(l, 2):
if i > j:
dd[i] += 1
dd[j] += 1
print(dd)
# defaultdict(<type 'int'>, {1: 3, 2: 2, 3: 2, 4: 3})
您可以瀏覽np.greater.outer()。 ufunc的外部方法。
import numpy as np
a = np.array([ 4, 2, 3, 1])
為所有i和j生成a [i]> a [j]的方陣
arr = np.greater.outer(a,a)*1
arr
Out[24]:
array([[0, 1, 1, 1],
[0, 0, 0, 1],
[0, 1, 0, 1],
[0, 0, 0, 0]])
我們只對右上角的三角形感興趣。
arr = np.triu(arr)
arr
Out[25]:
array([[0, 1, 1, 1],
[0, 0, 0, 1],
[0, 0, 0, 1],
[0, 0, 0, 0]])
arr += arr.T # add the transposition. arr is symmetrical about the diagonal.
arr
Out[9]:
array([[0, 1, 1, 1],
[1, 0, 0, 1],
[1, 0, 0, 1],
[1, 1, 1, 0]])
對行求和以得到計數。
arr.sum(axis = 0)
Out[28]: array([3, 2, 2, 3])
所有循環都隱藏在外部方法中。
根據@Andrew Scott的評論,這是所需的更改:
import numpy as np
def mergeSortInversions(arr, counts):
if len(arr) == 1:
return arr, counts
else:
a = arr[:len(arr)//2]
b = arr[len(arr)//2:]
a, ai = mergeSortInversions(a, counts)
b, bi = mergeSortInversions(b, counts)
c = []
i = 0
j = 0
inversions = ai + bi
while i < len(a) and j < len(b):
if a[i] <= b[j]:
c = np.concatenate([c, a[i, None]])
i += 1
else:
c = np.concatenate([c, b[j, None]])
inversions[a[i:].astype(np.int) - 1] += 1
inversions[b[j].astype(np.int) - 1] += (len(a)-i)
j += 1
c = np.concatenate([c, a[i:]])
c = np.concatenate([c, b[j:]])
return c, inversions
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.