计算数组中下 n 个元素的乘积

Posted

技术标签:

【中文标题】计算数组中下 n 个元素的乘积【英文标题】:Compute the product of the next n elements in array 【发布时间】:2017-01-12 01:48:38 【问题描述】:

我想计算矩阵的下一个n 相邻元素的乘积。要相乘的元素数量n 应该在函数的输入中给出。 例如对于这个输入,我应该计算每 3 个连续元素的乘积,从第一个开始。

[p, ind] = max_product([1 2 2 1 3 1],3);

这给出了[1*2*2, 2*2*1, 2*1*3, 1*3*1] = [4,4,6,3]

有什么实用的方法吗?现在我这样做:

for ii = 1:(length(v)-2)
    p = prod(v(ii:ii+n-1));
end

其中v 是输入向量,n 是要相乘的元素数。

在此示例中为 n=3,但可以采用任何正整数值。

根据n 是奇数还是偶数或length(v) 是奇数还是偶数,我有时会得到正确答案,但有时会出错。 例如参数:

v = [1.35912281237829 -0.958120385352704 -0.553335935098461 1.44601450110386 1.43760259196739 0.0266423803393867 0.417039432979809 1.14033971399183 -0.418125096873537 -1.99362640306847 -0.589833539347417 -0.218969651537063 1.49863539349242 0.338844452879616 1.34169199365703 0.181185490389383 0.102817336496793 0.104835620599133 -2.70026800170358 1.46129128974515 0.64413523430416 0.921962619821458 0.568712984110933] 
n = 7

我得到错误:

Index exceeds matrix dimensions.
Error in max_product (line 6)  
p = prod(v(ii:ii+n-1));

有没有正确的通用方法?

【问题讨论】:

我怀疑你没有得到错误的答案,你得到一个 index out of bounds 错误,对吗? 对,我得到索引超出矩阵维度。 max_product 中的错误(第 6 行) p=prod(v(ii:ii+n-1)); 这是因为ii 的范围限制不正确。提示:当ii 处于最大值时,ii+n-1 应该为您提供v 的最后一个元素。 @beaker 并没有真正的帮助。我在 ii 达到最大值之前很久就得到了错误。如果 ii=1:15,我已经从第 10 次迭代中得到错误。没错,我的问题是如何组织 ii 的范围。让它依赖于 length(v) 是错误的,试图找出 n 为奇数或偶数的情况也是错误的。 您的代码中只有一个错误。您应该将 for 循环的开头更改为 for ii = 1:(length(v)-n+1),然后它应该可以工作。 【参考方案1】:

基于Fast numpy rolling_product 中的解决方案,我想建议它的MATLAB 版本,它利用了R2016a 中引入的movsum 函数。

数学推理是数字的乘积等于它们对数之和的指数:

上述可能的 MATLAB 实现可能如下所示:

function P = movprod(vec,window_sz)
  P = exp(movsum(log(vec),[0 window_sz-1],'Endpoints','discard'));
  if isreal(vec)   % Ensures correct outputs when the input contains negative and/or
    P = real(P);   %   complex entries.
  end
end

几点说明:

    我没有对此解决方案进行基准测试,也不知道它与其他建议的性能相比如何。 它应该可以正确处理包含零和/或负和/或复杂元素的向量。 它可以轻松扩展以接受要操作的维度(用于数组输入)以及movsum 提供的任何其他自定义。 第一个st 输入假定为doublecomplex double row 向量。 输出可能需要四舍五入。

【讨论】:

【参考方案2】:

更新

受到answer of Dev-iL 的启发,提供了这个方便的解决方案,它不需要Matlab R2016a 或更高版本

out = real( exp(conv(log(a),ones(1,n),'valid')) )

基本思想是将乘法转换为和,可以使用移动平均,而这又可以通过convolution 来实现。


旧答案

这是使用gallery 获取循环矩阵并在乘以元素之前索引结果矩阵的相关部分的一种方法:

a = [1 2 2 1 3 1]
n = 3

%// circulant matrix
tmp = gallery('circul', a(:))
%// product of relevant parts of matrix
out = prod(tmp(end-n+1:-1:1, end-n+1:end), 2)

out =

     4
     4
     6
     3

更节省内存的替代方案如果输入中没有零

a = [10 9 8 7 6 5 4 3 2 1]
n = 2

%// cumulative product
x = [1 cumprod(a)] 
%// shifted by n and divided by itself
y = circshift( x,[0 -n] )./x 
%// remove last elements 
out = y(1:end-n) 

out =

    90    72    56    42    30    20    12     6     2

【讨论】:

向量 a 和 n 可以改变。它们是输入参数。如果我给出 a=[10 9 8 7 6 5 4 3 2 1] 并且 n=2 我应该得到 j=[90 72 56 42 30 20 12 6 2]。在你的功能中,我得到了一些非常不同的东西 我稍后看看 @AstrikSahakyan 我进行了更正。现在它应该可以工作了。 @erfan 感谢您的更正,我做了另一个更改以避免翻转 @AstrikSahakyan 我添加了一个您应该考虑的内存效率更高的解决方案。【参考方案3】:

你的方法是正确的。您只需将 for 循环更改为 for ii = 1:(length(v)-n+1) 即可。

如果您不打算处理大量输入,另一种方法是使用gallery,如@thewaywewalk's answer 中所述。

【讨论】:

【参考方案4】:

我认为问题可能与您的索引有关。声明 for ii = 1:(length(v)-2) 的行没有提供正确的 ii 范围。

试试这个:

function out = max_product(in,size)
    size = size-1;                 % this is because we add size to i later
    out = zeros(length(in),1)      % assuming that this is a column vector
    for i = 1:length(in)-size
        out(i) = prod(in(i:i+size));
    end

您的代码在重述时有效:

for ii = 1:(length(v)-(n-1))
    p = prod(v(ii:ii+(n-1)));
end

这应该解决索引问题。

【讨论】:

请不要乞求接受您的回答。 OP 将选择最适合他/她的答案。【参考方案5】:

使用 bsxfun 创建一个矩阵,它的每一行都包含连续的 3 个元素,然后获取矩阵的第二维。我认为这是最有效的方式:

max_product = @(v, n) prod(v(bsxfun(@plus, (1 : n), (0 : numel(v)-n)')), 2);
p = max_product([1 2 2 1 3 1],3)

更新: 更新了其他一些解决方案,并且一些诸如 @Dev-iL 的答案优于其他解决方案,我可以建议 fftconv 在 Octave 中优于 conv

【讨论】:

【参考方案6】:

如果您可以升级到 R2017a,则可以使用新的 movprod 函数来计算窗口乘积。

【讨论】:

以上是关于计算数组中下 n 个元素的乘积的主要内容,如果未能解决你的问题,请参考以下文章

如何找到 Numpy 数组的 M 个元素的 N 个最大乘积子数组?

华为OD机试 - 计算最大乘积(Java) | 机试题+算法思路+考点+代码解析 2023

华为OD机试 - 计算最大乘积(Java) | 机试题+算法思路+考点+代码解析 2023

lintcode50 数组剔除元素后的乘积

66 构建乘积数组

华为机试真题 C++ 实现计算最大乘积