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

C++ 高效地将数组的(n-1)个元素相乘,c++,c,performance,C++,C,Performance,可能重复: 我有两个数组inputArray和resultArray,每个数组都有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) result

可能重复:

我有两个数组
inputArray
resultArray
,每个数组都有
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];
(i=0;i 对于(j=0;j 但问题是复杂性不应该超过O(n)
此外,我们不允许使用除法。

如何解决这个问题?

你知道奇数乘法是可逆的吗?只使用乘法?看到黑客的喜悦,被称为“精确划分”。这个技巧也可以扩展到偶数,正如这里所解释的。所以你可以用几次乘法来“除”第n个数-既然这是家庭作业,我就让你自己去弄清楚如何除。

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

您可以使用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;
}
向量积(常量向量和输入){
int N=input.size();
向量部分(N+1);//部分[i]=输入[0]…输入[i-1]。部分[0]=1
部分[0]=1;
对于(int i=0;i=0;--i){
//电流等于输入[i+1]…输入[N-1]
ans[i]=部分[i]*电流;
电流*=输入[i];
}
返回ans;
}
这种方法的一个可能用法是,当您处理无法除以的事物时(例如,思考矩阵的相同问题)


我使用STL vector实现了这个解决方案,但是代码当然可以很容易地“翻译”成C数组。

看到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;
inti,缓冲区=1,结果[n];
对于(result[0]=1,i=1;i=0;buffer*=inputArray[i],i--)result[i]*=buffer;
三行代码(去掉所有脂肪)

main()
{
int i,l,r,x[5]={1,2,3,4,5},y[5];//x是初始数组,y是最终数组
int n=5;//n是数组的大小,此处已定义为5
l=1;//l是x中索引左侧值的乘积
r=1;//r是x中索引右侧值的乘积

对于(i=0;我将把求和
log10(输入阵列[i])
,然后做
resultArray[i]=pow(10.,求和-log10(输入阵列[i]),算作作弊)
?如果你能将这个问题转化为除法,这很简单。如果结果中的第i个元素被视为除法而不是乘法的结果,那么它是什么?你告诉了他标准的方法。为什么不让他用冷静的方法来做呢?这种方法比试图找到模2^32的乘法逆要快得多(即使它的整体算法复杂度相同)@ronalchn但它并不酷,唯一的要求是应该是O(n),而不是尽可能快在编程竞赛中,您想要的解决方案是,您可以尽可能快地编写代码,无论是编程时间还是运行时间都是valuable@ronalchn问题不是这么说的。而且,求乘法逆也不是那么慢。只是几个乘法。我不知道OP在做作业对于ioccc..它不是关于LOC,而是关于可读性可读性更依赖于函数的良好命名和文档,而不是让简单函数占用许多行代码。它被标记为家庭作业,所以实际上代码并不受欢迎。我刚刚意识到这实际上与Ben Rujil相似,没有分割。很好。通过DP,目的是什么ded是两次通过(即双次通过,DP)。作业的重要部分是O(N)不一定意味着单次通过;任何固定数量的通过(本例中为2次)都符合O(N)。
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]);

}