Algorithm 问题解决面试问题(数组)
有一个整数数组,比如说3,5,7,9。您应该创建另一个数组并填充它,以便第二个数组的第0个位置应该是第一个数组中所有数字的乘积,不包括第0个位置的数字,这意味着它应该是5x7x9(不包括3),第二个数组索引1处的数字将是3x7x9(不包括5)的乘积 我想到的第一个答案是有2个for循环,这将导致O(n2)的时间复杂度。后来我想: 将第一个数组(3x5x7x9)中的所有数字相乘,在填充第二个数组时,我将此乘积除以该位置的数字。如果我填充第0个位置,则除以3;如果我填充第1个位置,则除以5,依此类推。这将使复杂性从O(n2)降低到O(2n) 但采访者表示,不允许分裂。除了在某种数据结构中存储不同的可能倍数并在填充时使用它之外,我想不出其他任何东西。我放弃了,但当被问到答案时,他说他将保留两个正向和反向倍数数组。当被问及解决方案的空间复杂性问题时,他说可以对其进行优化。我想我可以用O(n log n)来完成 存储前半个数字和后半个数字的乘积 同时存储第一季度、第二季度、第三季度和第四季度的产品 还应储存前八分之一、后八分之一。。。第八 等等 你可以通过计算每一对的乘积,然后是每一对的乘积,依此类推,从头开始构建这个模型 这里的额外数据总量是O(n),需要计算O(n)(易于显示) 现在,为了计算(比如)元素0的输出,取下半部分的乘积,第二季度的乘积(即第一季度的下半部分),第八季度的下半部分的乘积,等等,然后将它们相乘。有logn这样的数字,所以这个操作是logn 要计算元素k的乘积,请将k写入二进制并翻转其位。然后高位告诉你从哪一半开始;下一位告诉您下一步使用剩余一半中的哪一半;下一位告诉您下一步使用剩余季度的哪一半;等等 因此,任何输出元素都可以在logn时间内计算。对n个输出元素中的每一个执行此操作,您将得到O(n logn) [编辑] 当然,“向前和向后倍数”方法也能起作用。我想我应该更仔细地阅读这个问题。:-) [编辑2] 至于面试官(和大卫)的解决方案,你实际上不需要构建一个额外的数组。。。假设您可以编辑输出数组中的值 首先,构造输出数组B,使得B[i]=A[0]A[1]…*A[i-1]和B[0]=1。您可以增量执行此操作,因此这是线性时间:Algorithm 问题解决面试问题(数组),algorithm,Algorithm,有一个整数数组,比如说3,5,7,9。您应该创建另一个数组并填充它,以便第二个数组的第0个位置应该是第一个数组中所有数字的乘积,不包括第0个位置的数字,这意味着它应该是5x7x9(不包括3),第二个数组索引1处的数字将是3x7x9(不包括5)的乘积 我想到的第一个答案是有2个for循环,这将导致O(n2)的时间复杂度。后来我想: 将第一个数组(3x5x7x9)中的所有数字相乘,在填充第二个数组时,我将此乘积除以该位置的数字。如果我填充第0个位置,则除以3;如果我填充第1个位置,则除以5,依此类推
B[0] = 1;
for (i=1 ; i < n ; ++i) {
B[i] = B[i-1] * A[i];
}
这解决了O(n)中的问题,而无需构建额外的阵列
A[i]
是元素1到元素i的乘积B
,其中B[i]
为元素i到元素n的乘积我不确定问题是关于空间还是关于解决方案本身。因为每个人都在提供解决方案,这让我觉得他们不理解面试官的解决方案,所以这里有一个解释: 我们维护两个阵列。第一个是原始数组数的运行乘积。因此,位于
i
位置的元素将是原始数组中第一个i
元素的乘积(没有latex,但i
th条目的值为pi{j=0到i}j
)。第二个数组只是与之相反的方向,因此i
th条目将有值:pi{j=N-i到N}j
为了构造所需的最终数组,我们只需沿着两个数组中的每一个运行并乘以条目。因此,最后一个数组中的i
th值将是所有条目的乘积,即0
到i-1
乘以i+1
到N
的乘积,这是第一个数组的i-1
条目和第二个数组的i+1
条目的乘积
总时间和空间
O(n)
我相信他的意思是,给定一个数组A={A_1,…,A_n},他将创建两个新数组:
F_A={A_1,A_1*A_2,…,A_1*…*A_n}
可通过在数组上向前迭代时保持累积乘积在线性时间内构造,以及
B_A={A_1*..*A_n,…,A_n*A_(n-1),A_n}
它可以在线性时间内构造,方法是在数组上以相反方向迭代时保持累积乘积
现在,要在结果数组中填充索引i,只需将F_A[i-1]乘以B_A[i+1]:
F_A[i-1]*B_A[i+1]=[A_1*…*A_(i-1)]*[A_(i+1)*…*A_n]关于省略对数呢。不是除法而是减法 但是,如果您可以修改第一个数组,您可以执行以下操作
//pop arr2
r=1
for(i=len-1;i>=0;i--)
{
r=r*arr1[i]
arr2[i]=r
}
//modify arr1
r=1
for(i=0;i<len;i++)
{
r=r*arr1[i]
arr1[i]=r
}
//fix arr2
arr2[0]=arr2[1];
for(i=1;i<len-1;i--)
{
arr2[i]=arr2[i+1]*arr1[i-1];
}
arr2[len-1]=arr1[len-2];
//pop arr2
r=1
对于(i=len-1;i>=0;i--)
{
r=r*arr1[i]
arr2[i]=r
}
//修改arr1
r=1
对于(i=0;iOne)一个小小的技术诡辩:O(2n)正是O(n)。也许他的意思是在某种意义上它是最优的,因为这个问题的空间复杂度是O(n)
,而这个解决方案又增加了一个O(n)
,总的来说仍然是O(n)
。@Charlie知道你的意思……他是说O(2n)和O(3n)是一样的
//pop arr2
r=1
for(i=len-1;i>=0;i--)
{
r=r*arr1[i]
arr2[i]=r
}
//modify arr1
r=1
for(i=0;i<len;i++)
{
r=r*arr1[i]
arr1[i]=r
}
//fix arr2
arr2[0]=arr2[1];
for(i=1;i<len-1;i--)
{
arr2[i]=arr2[i+1]*arr1[i-1];
}
arr2[len-1]=arr1[len-2];