给定一组数字,返回所有其他数字的产品数组(无分区)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了给定一组数字,返回所有其他数字的产品数组(无分区)相关的知识,希望对你有一定的参考价值。

我在求职面试中被问到这个问题,我想知道其他人如何解决这个问题。我对Java最熟悉,但欢迎使用其他语言的解决方案。

给定一组数字,nums,返回一组数字products,其中products[i]是所有nums[j], j != i的产物。

Input : [1, 2, 3, 4, 5]
Output: [(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)中执行此操作而不使用除法。

答案

polygenelubricants方法的解释是:诀窍是构造数组(在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];
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
p=1;
for(int i=0;i<N;++i) {
  products[i]=p;
  p*=a[i];
}

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

这是O(n ^ 2),但f#非常漂亮:

List.fold (fun seed i -> List.mapi (fun j x -> if i=j+1 then x else x*i) seed) 
          [1;1;1;1;1]
          [1..5]
另一答案

整蛊:

使用以下内容:

public int[] calc(int[] params) {

int[] left = new int[n-1]
in[] right = new int[n-1]

int fac1 = 1;
int fac2 = 1;
for( int i=0; i<n; i++ ) {
    fac1 = fac1 * params[i];
    fac2 = fac2 * params[n-i];
    left[i] = fac1;
    right[i] = fac2; 
}
fac = 1;

int[] results = new int[n];
for( int i=0; i<n; i++ ) {
    results[i] = left[i] * right[i];
}

是的,我确信我错过了一些i-1而不是i,但这就是解决问题的方法。

另一答案

还存在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。

另一答案
public static void main(String[] args) {
    int[] arr = { 1, 2, 3, 4, 5 };
    int[] result = { 1, 1, 1, 1, 1 };
    for (int i = 0; i < arr.length; i++) {
        for (int j = 0; j < i; j++) {
            result[i] *= arr[j];

        }
        for (int k = arr.length - 1; k > i; k--) {
            result[i] *= arr[k];
        }
    }
    for (int i : result) {
        System.out.println(i);
    }
}

我提出了这个解决方案,我发现它很清楚你怎么想!?

另一答案

预先计算每个元素左侧和右侧的数字乘积。对于每个元素,期望的价值是它的neigbors产品的产物。

#include <stdio.h>

unsigned array[5] = { 1,2,3,4,5};

int main(void)
{
unsigned idx;

unsigned left[5]
        , right[5];
left[0] = 1;
right[4] = 1;

        /* calculate products of numbers to the left of [idx] */
for (idx=1; idx < 5; idx++) {
        left[idx] = left[idx-1] * array[idx-1];
        }

        /* calculate products of numbers to the right of [idx] */
for (idx=4; idx-- > 0; ) {
        right[idx] = right[idx+1] * array[idx+1];
        }

for (idx=0; idx <5 ; idx++) {
        printf("[%u] Product(%u*%u) = %u
"
                , idx, left[idx] , right[idx]  , left[idx] * right[idx]  );
        }

return 0;
}

结果:

$ ./a.out
[0] Product(1*120) = 120
[1] Product(1*60) = 60
[2] Product(2*20) = 40
[3] Product(6*5) = 30
[4] Product(24*1) = 24

(更新:现在我仔细观察,这使用与Michael Anderson,Daniel Migowski和上面的polygenelubricants相同的方法)

另一答案
def productify(arr, prod, i):
    if i < len(arr):
            prod.append(arr[i - 1] * prod[i - 1]) if i > 0 else prod.append(1)
            retval = productify(arr, prod, i + 1)
            prod[i] *= retval
            return retval * arr[i]
    return 1

arr = [1,2,3,4,5] prod = [] productify(arr,prod,0)print prod

另一答案

这里完整的是Scala中的代码:

val list1 = List(1, 2, 3, 4, 5)
for (elem <- list1) println(list1.filter(_ != elem) reduceLeft(_*_))

这将打印出以下内容:

120
60
40
30
24

该程序将过滤掉当前的elem(_!= elem);并使用reduceLeft方法将新列表相乘。如果你使用scala视图或Iterator进行懒惰eval,我认为这将是O(n)。

另一答案

基于Billz回答 - 抱歉我无法发表评论,但这里有一个scala版本正确处理列表中的重复项目,可能是O(n):

val list1 = List(1, 7, 3, 3, 4, 4)
val view = list1.view.zipWithIndex map { x => list1.view.patch(x._2, Nil, 1).reduceLeft(_*_)}
view.force

收益:

List(1008, 144, 336, 336, 252, 252)
另一答案

在这里添加我的javascript解决方案,因为我没有找到任何人建议这一点。什么是除法,除了计算从另一个数字中提取数字的次数?我经历了计算整个数组的乘积,然后迭代每个元素,并将当前元素减去零:

//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;
}
另一答案

我习惯使用C#:

    public int[] ProductExceptSelf(int[] nums)
    {
        int[] returnArray = new int[nums.Length];
        List<int> auxList = new List<int>();
        int multTotal = 0;

        // If no zeros are contained in the array you only have to calculate it once
        if(!nums.Contains(0))
        {
            multTotal = nums.ToList().Aggregate((a, b) => a * b);

            for (int i = 0; i < nums.Length; i++)
            {
                returnArray[i] = multTotal / nums[i];
            }
        }
        else
        {
            for (int i = 0; i < nums.Length; i++)
            {
                auxList = nums.ToList();
                auxList.RemoveAt(i);
                if (!auxList.Contains(0))
                {
                    returnArray[i] = auxList.Aggregate((a, b) => a * b);
                }
                else
                {
                    returnArray[i] = 0;
                }
            }
        }            

        return returnArray;
    }
另一答案

这是一个小的递归函数(在C ++中)来进行修改。它需要O(n)额外空间(在堆栈上)。假设数组在a中并且N保持数组长度,我们有

int multiply(int *a, int fwdProduct, int indx) {
    int revProduct = 1;
    if (indx < N) {
       revProduct = multiply(a, fwdProduct*a[indx], indx+1);
       int cur = a[indx];
       a[indx] = fwdProduct * revProduct;
       revProduct *= cur;
    }
    return revProduct;
}
另一答案

那么,这个解决方案可以被认为是C / C ++的解决方案。假设我们有一个包含n个元素的数组“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];
  }
另一答案

还有一个解决方案,使用除法。两次遍历。将所有元素相乘,然后按每个元素开始分割。

另一答案
{-
Recursive so

以上是关于给定一组数字,返回所有其他数字的产品数组(无分区)的主要内容,如果未能解决你的问题,请参考以下文章

回溯 - 给定一组数字,找到总和等于 M 的所有子集(给定 M)

acm

78. 子集

给定一组正数,找出最接近给定常数的加法组合?

LeetCode Largest Number

LeetCode Largest Number