我在一次工作面试中被问到这个问题,我想知道其他人是如何解决这个问题的。我最擅长使用Java,但也欢迎使用其他语言的解决方案。

给定一个数字数组nums,返回一个数字数组products,其中products[i]是所有nums[j]的乘积,j != i。 输入:[1,2,3,4,5] 输出:[(2 * 3 * 4 * 5),(1 * 3 * 4 * 5),(1 * 2 * 4 * 5),(1 * 2 * 3 * 5),(1 * 2 * 3 * 4)] = [120, 60, 40, 30, 24] 你必须在O(N)中不使用除法来做这个。


当前回答

这个解决方案可以被认为是C/ c++的。 假设我们有一个包含n个元素的数组a 像a[n]一样,那么伪代码将如下所示。

for(j=0;j<n;j++)
  { 
    prod[j]=1;

    for (i=0;i<n;i++)
    {   
        if(i==j)
        continue;  
        else
        prod[j]=prod[j]*a[i];
  }

其他回答

多基因润滑剂方法的一个解释是:

诀窍是构造数组(在4个元素的情况下):

{              1,         a[0],    a[0]*a[1],    a[0]*a[1]*a[2],  }
{ a[1]*a[2]*a[3],    a[2]*a[3],         a[3],                 1,  }

这两种方法都可以在O(n)中分别从左右边开始。

然后,将两个数组逐个元素相乘,得到所需的结果。

我的代码看起来是这样的:

int a[N] // This is the input
int products_below[N];
int p = 1;
for (int i = 0; i < N; ++i) {
    products_below[i] = p;
    p *= a[i];
}

int products_above[N];
p = 1;
for (int i = N - 1; i >= 0; --i) {
    products_above[i] = p;
    p *= a[i];
}

int products[N]; // This is the result
for (int i = 0; i < N; ++i) {
    products[i] = products_below[i] * products_above[i];
}

如果你也需要空间中的解是O(1),你可以这样做(在我看来不太清楚):

int a[N] // This is the input
int products[N];

// Get the products below the current index
int p = 1;
for (int i = 0; i < N; ++i) {
    products[i] = p;
    p *= a[i];
}

// Get the products above the current index
p = 1;
for (int i = N - 1; i >= 0; --i) {
    products[i] *= p;
    p *= a[i];
}

在这里添加我的javascript解决方案,因为我没有发现任何人建议这样做。 除法是什么,除了数从另一个数中得到一个数的次数吗?我计算了整个数组的乘积,然后遍历每个元素,并减去当前元素直到0:

//No division operation allowed
// keep substracting divisor from dividend, until dividend is zero or less than divisor
function calculateProducsExceptCurrent_NoDivision(input){
  var res = [];
  var totalProduct = 1;
  //calculate the total product
  for(var i = 0; i < input.length; i++){
    totalProduct = totalProduct * input[i];
  }
  //populate the result array by "dividing" each value
  for(var i = 0; i < input.length; i++){
    var timesSubstracted = 0;
    var divisor = input[i];
    var dividend = totalProduct;
    while(divisor <= dividend){
      dividend = dividend - divisor;
      timesSubstracted++;
    }
    res.push(timesSubstracted);
  }
  return res;
}
    int[] arr1 = { 1, 2, 3, 4, 5 };
    int[] product = new int[arr1.Length];              

    for (int i = 0; i < arr1.Length; i++)
    {
        for (int j = 0; j < product.Length; j++)
        {
            if (i != j)
            {
                product[j] = product[j] == 0 ? arr1[i] : product[j] * arr1[i];
            }
        }
    }

下面是一个C实现 O(n)时间复杂度。 输入

#include<stdio.h>
int main()
{
    int x;
    printf("Enter The Size of Array : ");
    scanf("%d",&x);
    int array[x-1],i ;
    printf("Enter The Value of Array : \n");
      for( i = 0 ; i <= x-1 ; i++)
      {
          printf("Array[%d] = ",i);
          scanf("%d",&array[i]);
      }
    int left[x-1] , right[x-1];
    left[0] = 1 ;
    right[x-1] = 1 ;
      for( i = 1 ; i <= x-1 ; i++)
      {
          left[i] = left[i-1] * array[i-1];
      }
    printf("\nThis is Multiplication of array[i-1] and left[i-1]\n");
      for( i = 0 ; i <= x-1 ; i++)
      {
        printf("Array[%d] = %d , Left[%d] = %d\n",i,array[i],i,left[i]);
      }
      for( i = x-2 ; i >= 0 ; i--)
      {
          right[i] = right[i+1] * array[i+1];
      }
   printf("\nThis is Multiplication of array[i+1] and right[i+1]\n");
      for( i = 0 ; i <= x-1 ; i++)
      {
        printf("Array[%d] = %d , Right[%d] = %d\n",i,array[i],i,right[i]);
      }
    printf("\nThis is Multiplication of Right[i] * Left[i]\n");
      for( i = 0 ; i <= x-1 ; i++)
      {
          printf("Right[%d] * left[%d] = %d * %d = %d\n",i,i,right[i],left[i],right[i]*left[i]);
      }
    return 0 ;
}

输出

    Enter The Size of Array : 5
    Enter The Value of Array :
    Array[0] = 1
    Array[1] = 2
    Array[2] = 3
    Array[3] = 4
    Array[4] = 5

    This is Multiplication of array[i-1] and left[i-1]
    Array[0] = 1 , Left[0] = 1
    Array[1] = 2 , Left[1] = 1
    Array[2] = 3 , Left[2] = 2
    Array[3] = 4 , Left[3] = 6
    Array[4] = 5 , Left[4] = 24

    This is Multiplication of array[i+1] and right[i+1]
    Array[0] = 1 , Right[0] = 120
    Array[1] = 2 , Right[1] = 60
    Array[2] = 3 , Right[2] = 20
    Array[3] = 4 , Right[3] = 5
    Array[4] = 5 , Right[4] = 1

    This is Multiplication of Right[i] * Left[i]
    Right[0] * left[0] = 120 * 1 = 120
    Right[1] * left[1] = 60 * 1 = 60
    Right[2] * left[2] = 20 * 2 = 40
    Right[3] * left[3] = 5 * 6 = 30
    Right[4] * left[4] = 1 * 24 = 24

    Process returned 0 (0x0)   execution time : 6.548 s
    Press any key to continue.

还有一个O(N^(3/2))非最优解。不过,这很有趣。

首先预处理大小为N^0.5的每个部分乘法(这在O(N)时间复杂度中完成)。然后,计算每个数字的其他值的倍数可以在2*O(N^0.5)时间内完成(为什么?因为您只需要将其他((N^0.5) - 1)数字的最后一个元素相乘,并将结果与属于当前数字组的((N^0.5) - 1)数字相乘。对每一个数都这样做,可以得到O(N^(3/2))时间。

例子:

4, 6, 7, 2, 3, 1, 9, 5, 8

部分结果: 4*6*7 = 168 2*3*1 = 6 9*5*8 = 360

要计算3的值,需要将其他组的值乘以168*360,然后乘以2*1。