在Matlab中找到反转次数

时间:2015-09-24 17:04:41

标签: arrays performance matlab optimization inversion

在通过分而治之的方法查找数组中的反转次数的过程中我遇到了实现merge-step的问题:我们有两个排序的数组,任务是计算一个元素的数量第一个数组大于第二个数组中的元素。

例如,如果数组是v1 = [1,2,4], v2 = [0,3,5],我们应该计算4次反转。

所以,我在Matlab中实现了合并步骤,但我坚持如何快速实现它的问题。

首先,我用

尝试了蛮力方法
tempArray = arrayfun(@(x) length(find(v2>x)), v1)

它和下一个片段

的效果太慢了
l = 1;
s = 0;
for ii = 1:n1 
    while(l <= n2 && p1(ii)>p2(l))
        l = l + 1;
    end
    s = s + l - 1;
end

有没有一种方法可以让它更快?

修改

感谢您的回答和方法!我为进一步的工作找到了有趣的东西。

这是片段,应该是我尝试过的最快

n1 = length(vec1); n2 = length(vec2);

uniteOne = [vec1, vec2];

[~, d1] = sort(uniteOne);
[~, d2] = sort(d1); % Find ind-s IX such that B(IX) = A, where B = sort(A)
vec1Slice = d2(1:n1);
finalVecToSolve = vec1Slice - (1:n1);

sum(finalVecToSolve)

3 个答案:

答案 0 :(得分:6)

另一种使用bsxfun的蛮力方法 -

sum(reshape(bsxfun(@gt,v1(:),v2(:).'),[],1))

或者,正如@thewaywewalk在评论中提到的那样,使用nnz替换summing -

nnz(bsxfun(@gt,v1(:),v2(:).'))

答案 1 :(得分:4)

代码

n = numel(v1);
[~, ind_sort] = sort([v1 v2]);
ind_v = ind_sort<=n;
result = sum(find(ind_v))-n*(n+1)/2;

说明

n表示输入向量的长度。 ind_v是一个长度为2*n的向量,表示排在一起的v1v2的值,其中一个表示{{1}的值}和表示来自v1的值。对于你的例子,

v2

我们有

v1 = [1,2,4];
v2 = [0,3,5];

ind_v = 0 1 1 0 1 0 的第一个条目。这意味着ind_vv1v2)的最低值属于0。然后有一个一个,因为第二低的值(v2)属于1v1的最后一项是,因为输入向量的最大值(ind_v)属于5

从这个v2可以很容易地计算结果。也就是说,我们只需要计算每个一个左侧有多少,并将所有这些数量相加

我们甚至不需要做那些计数;我们可以从每个一个 的位置推断它们。第一个一个左侧的的数量是一个减去ind_v的位置。第二个 one 左侧的的数量是其位置减去1。等等。因此2将给出期望的结果。但sum(find(ind_v)-(1:n))仅为sum(1:n),因此结果可简化为n*(n+1)/2

复杂性

对向量进行排序是限制操作,需要sum(find(ind_v))-n*(n+1)/2算术比较。相反,蛮力需要O(2*n*log(2*n))比较。

答案 2 :(得分:3)

一种明确的方法可能是减去你的元素,看看它们在哪里是否定的:

v1 = [1,2,4];
v2 = [0,3,5];

mydiffs = zeros(length(v1), length(v2));
for ii = 1:length(v1)
    mydiffs(ii,:) = v2 - v1(ii);
end

test = sum(reshape(mydiffs,[],length(v1)*length(v2)) < 0)

返回:

test =

     4

这不是最漂亮的方法,而且肯定有改进的余地。我也怀疑它比bsxfun方法更快。

Edit1:arrayfun方法,看起来更整洁,但不一定比循环更快。

test = arrayfun(@(x) (v2 - x) < 0, v1, 'UniformOutput', false);
inversions = sum([test{:}]);

Edit2:repmat方法

inversions = nnz(repmat(v2, length(v2), 1) - repmat(v1', 1, length(v1)) < 0)