找到小于右边某个元素的每个元素

时间:2014-04-17 20:29:04

标签: arrays performance matlab optimization vectorization

我需要找到一个向量的元素,这个元素少于它之后的一个或多个元素。循环很容易:

x = some_vector_values;
for m = 1 : length(x)
  if( any( x(m+1:end) > x(m) )
    do_such_and_such;
  end
end

但是速度正在扼杀我。我正试图想出一个有效的解决办法但是我的空白。数组长度可以是数千种,我需要为许多不同的数组执行此操作。

6 个答案:

答案 0 :(得分:10)

这使用divide-and-conquer方法(类似于二分搜索):

  1. 找到矢量的最大值。
  2. 接受左侧的所有元素,而最大值本身则被拒绝。
  3. 对于最大值右侧的元素,请应用步骤1.
  4. 虽然我没有仔细分析,但我认为平均复杂度为 O n ),或者最多 O n log n )。内存 O n )。

    结果是一个逻辑向量ind,其中包含已接受元素的true和已拒绝元素的false。最终结果为x(ind)

    x = [3 4 3 5 6 3 4 1];
    n = numel(x);
    ind = false(1,n); %// intiallization
    s = 1; %// starting index of the part of x that remains to be analyzed
    while s <= n %// if s > n we have finished
        [~, m] = max(x(s:end)); %// index of maximum within remaining part of x
        ind(s:s-2+m) = true; %// elements to its left are accepted
        s = s+m; %// update start of remaining part
    end
    

    while条件更改为while s < n可以缩短运行时间,因为最后一个元素总是被拒绝。

答案 1 :(得分:6)

单线版

comparisons = any(triu(bsxfun(@gt,x(:).',x(:))),2)

答案 2 :(得分:6)

您的算法速度很慢,因为if any(...)必须在第一次迭代时检查n个项目,然后在第二次迭代时检查n-1个项目......直到检查最后一个项目中的单个项目迭代。因此,它必须进行大约n^2/2次比较,因此它的运行时间是输入向量长度的二次方![/ p>

一个时间和内存呈线性的解决方案可能是首先计算从该点到结束的最大值的向量,可以在一个向后传递中计算 (你可以称之为反向累积最大值,cannot be vectorized)。在此之后,此向量将直接与x(未经测试)进行比较:

% calculate vector mx for which mx(i) = max(x(i:end))
mx = zeros(size(x));
mx(end) = x(end);
for i = length(x)-1:-1:1 % iterate backwards
    mx(i) = max(x(i), mx(i+1));
end

for i = 1:length(x) - 1
    if mx(i) > x(i)
        do_such_and_such(i);
    end
end

如果您不关心执行do_such_and_such的顺序,这些for循环甚至可以这样组合:

mx = x(end);
for i = length(x)-1:-1:1 % iterate backwards
    if x(i) < mx
        do_such_and_such(i);
    end
    mx = max(x(i), mx); % maximum of x(i:end)
end

答案 3 :(得分:6)

这应该是一个需要O(n)时间和O(n)内存的算法:将数组中的最后一个元素标记为最大元素。向后遍历数组。每当元素小于最大值时,请保存。否则,它将成为您的新的最大值。这可以通过一次传递为您提供所需的所有元素。

答案 4 :(得分:1)

如果你想找到比右边某个元素少的元素,你也可以这样做:

x = some_values'; % x should be a column vector to use this
h = hankel(x);
m = max(h,[],2);
f = find(x<m) %returns indices or f = (a<m) %returns true/false

汉克尔矩阵将向下显示向右行的元素。

然后您可以使用indices或true / false来迭代for循环并执行一些操作。这是一个例子:

x =

     9
     8
    16
    16
     4
    10
     9
    13
    15
     1

>> h = hankel(x)

h =

     9     8    16    16     4    10     9    13    15     1
     8    16    16     4    10     9    13    15     1     0
    16    16     4    10     9    13    15     1     0     0
    16     4    10     9    13    15     1     0     0     0
     4    10     9    13    15     1     0     0     0     0
    10     9    13    15     1     0     0     0     0     0
     9    13    15     1     0     0     0     0     0     0
    13    15     1     0     0     0     0     0     0     0
    15     1     0     0     0     0     0     0     0     0
     1     0     0     0     0     0     0     0     0     0

>> m = max(h,[],2)

m =

    16
    16
    16
    16
    15
    15
    15
    15
    15
     1

>> f = find(a<m)

f =

     1
     2
     5
     6
     7
     8

答案 5 :(得分:0)

@NKN没错。排序

x = some_vector_values;  

[Y,I]=sort(x);  %sort in order, get indices
dy=gradient(Y); %get difference vector same size as input vector
ind=find(dy~=0);%ignore places that are equal to the value of interest

for m = 1 : length(ind)
    do_such_and_such to Y(ind(m));
end

祝你好运