有效地将数组的(n-1)个元素相乘

Posted

技术标签:

【中文标题】有效地将数组的(n-1)个元素相乘【英文标题】:Efficiently multiply (n-1) elements of an array [duplicate] 【发布时间】:2012-08-26 11:52:00 【问题描述】:

可能重复:Interview Q: given an array of numbers, return array of products of all other numbers (no division)

我有两个数组 inputArrayresultArray 每个都有 n 元素。 任务是resultArray 中的第 n 个元素应该与 inputArray 中的所有元素相乘,inputArray 中的第 n 个元素除外(n-1 元素中的所有元素)。 例如。 inputArray=1,2,3,4 然后resultArray=24,12,8,6 这很容易......

for(i = 0; i < n; i++)
  for(j = 0; j < n; j++)
    if(i != j) resultArray[i] *= inputArray[j];

但问题是复杂度不应超过 O(n) 我们也不允许使用除法。 我该如何解决?

【问题讨论】:

log10 (inputArray[i])相加算作弊,然后做resultArray[i] = pow(10., sum - log10(inputArray[i])) 如果你能把这个问题转化为除法就很简单了。如果将结果视为除法而不是乘法的结果,结果中的第 i 个元素是什么? 【参考方案1】:

不要过多破坏,您应该尝试使用两个变量来存储乘法的结果:第 i 个元素左侧和第 i 个元素右侧的乘法的累积结果。

【讨论】:

你告诉他标准的方式..为什么不让他用很酷的方式呢? 这种方式比试图找到模 2^32 的乘法逆元要快得多(即使它具有相同的整体算法复杂度) @ronalchn 但它并不酷,唯一的要求是应该是 O(n),而不是尽可能快 在编程比赛中,您希望得到能够尽可能快地编码的解决方案,编程时间和运行时间都很宝贵 @ronalchn 这不是问题所说的。此外,找到乘法逆元并没有那么慢。只需少量乘法。【参考方案2】:

您可以使用 DP 方法,如下所示:

vector<int> products(const vector<int>& input) 
    int N = input.size();
    vector<int> partial(N+1); // partial[i] = input[0]...input[i-1]. partial[0] = 1
    partial[0] = 1;
    for (int i = 0; i < N; ++i) partial[i+1] = input[i]*partial[i];
    vector<int> ans(N);
    int current = 1;
    for (int i = N-1; i >= 0; --i) 
        // current is equal to input[i+1]...input[N-1]
        ans[i] = partial[i]*current;
        current *= input[i];
    
    return ans;

这种方法的一种可能用法是当您处理无法除的事物时(例如,考虑与矩阵相同的问题)。

我使用 STL 向量完成了这个解决方案,但当然可以轻松“翻译”代码以使用 C 数组。

【讨论】:

我才发现这其实和Ben Rujil很像,没有分界线。不错。 DP 的意图是双通道(即双通道,DP)。作业的重要部分是 O(N) 不一定意味着单程;任何固定数量的通行证(在这种情况下为 2 个)都符合 O(N)。【参考方案3】:

您是否知道乘以奇数是可逆的 - 仅使用乘法?请参阅 Hacker's Delight,称为“精确除法”。正如那里解释的那样,这个技巧也可以扩展到偶数。因此,您可以通过几次乘法“除”第 n 个数字 - 由于这是家庭作业,我将由您自己了解如何操作。

【讨论】:

【参考方案4】:
main()


      int i,l,r,x[5]=1,2,3,4,5,y[5]; // x is the initial array, y is the final array

      int n = 5; // n be the size of the array, here already defined as 5

      l = 1; // l is the product of the values of the left side of an index in x
      r = 1; // r is the product of the values of the right side of an index in x

      for (i=0 ; i<5 ; i++) y[i]=1; // initialising all y values to 1

      for (i=0 ; i<5 ; i++)
      
          y[i] = y[i]*l ;
          y[n-i-1] = y[n-i-1]*r;

          l = l*x[i];
          r = r*x[n-i-1];

      

      for (i=0; i<5; i++) printf("%d\n",y[i]);


【讨论】:

【参考方案5】:

看到 Daniel Fleischman 的回答,我决定我必须给出自己的实现,因为他的代码行数太多了!

int i, buffer=1, result[n];
for(result[0]=1,i=1;i<n;i++) result[i] = result[i-1]*inputArray[i-1];
for(i=n-1,buffer=1;i>=0;buffer*=inputArray[i],i--) result[i]*=buffer;

三行代码(去掉所有的肥肉)。

http://ideone.com/EaQiu

【讨论】:

我不知道OP正在为ioccc做作业.. 这不是关于 LOC 而是关于可读性 可读性更多地依赖于函数的良好命名和文档,而不是让简单的函数占用多行代码。 它被标记为作业,所以实际上代码并不受欢迎。

以上是关于有效地将数组的(n-1)个元素相乘的主要内容,如果未能解决你的问题,请参考以下文章

如何有效地将 PySpark 数据框中的行相乘?

如何使用 SSE 更有效地将 A*B^T 或 A^T*B^T(T 表示转置)矩阵相乘?

将多维数组中的元素相乘

如何将两个数组与每个元素相乘作为数字c ++

c# 使用 system.numerics 将数组元素相乘

c语言实现矩阵相乘