你得到一个数组[a1 To an],我们必须构造另一个数组[b1 to bn] bi = a1*a2*…*an/ai
。您只能使用恒定空间,时间复杂度为O(n)。不允许任何分歧。
解决方案的逻辑非常简单,从产品中删除bi以获得结果。但是,当我处理解决这个问题时,我发现自己被困了。这是我的疑惑:
根据我的理解,这里的常量空间意味着尽管数组的长度,我可以使用的变量数量必须修复。禁止创建新阵列来解决问题。因为创建新数组会使处理不同数组时变量的数量不同。
我已经在网上搜索了大多数解决方案,但是我能找到的所有解决方案都创建了新的阵列。 那么,我在这里错过了什么吗?有什么想法吗?非常感谢你!
答案 0 :(得分:5)
我将使用从0到N-1的数组索引,因为这就是我们在幕后做事的方式。
你可以像这样重写b i 的等式:b i =(a 0 ×a 1 ×⋯×a i-1 )×(a i + 1 ×a i + 2 ×⋯×a n- 1 ),或更简洁地像这样:b i =(Π j = 0⋯i-1 a j )× (Π j = i + 1⋯n-1 a j )。
(如果你不熟悉它,Π就像Σ,但它会增加术语而不是添加它们。而且,这些公式不是完全与你问题中的公式相同,因为根据你问题中的公式,如果 i 为零,则b i 是未定义的。但是,我将假设意图是取消a i 在分子和分母中,即使它是零。)
无论如何,您可以通过遍历数组a来逐步计算左子产品(Π j = 0 ... i-1 a j ) 0到n-1。您可以通过遍历数组a从n-1到0来计算正确的子产品(Π j = i + 1⋯n-1 a j )。
因此解决方案是使用两遍。
第一遍是从0到N-1。将每个b[i]
设置为a[j]
0 <= j < i
的产品。此过程将b数组设置为左侧子产品。这需要O(N)时间和循环计数器的恒定空间。
第二遍是从N-1到0.通过将b[i]
乘以a[j]
的乘积来更新每个i < j < N
。因此,传递通过将每个元素乘以适当的右子产品来更新b数组。这需要O(N)时间和循环计数器的常量空间和临时。
这是一个Python解决方案:
b[0] = 1
for i in range(1, N):
b[i] = b[i - 1] * a[i - 1]
# Now every b[i] is the product of the a[j] where 0 <= j < i.
t = 1
for i in range(N-1, -1, -1):
b[i] = b[i] * t
t *= a[i]
# Now every b[i] is the product of the a[j] where 0 <= j < i
# and the a[j] where i < j <= N-1. This is the desired output.
答案 1 :(得分:1)
恒定空间要求不禁止创建新数组。它只是意味着您的算法每次运行时都需要使用相同的空间量。由于问题要求您构造一个新数组,我将展示一个以恒定空间和线性时间执行此操作的函数。
您仍然可以创建新阵列。只要确保它是一个恒定的大小。最简单的方法是使其尽可能大。例如,在C ++中,您可以使用
int* b = new int[UINT_MAX];
因为数组中使用的最大索引是UINT_MAX。这是一个既可以是线性时间,也可以是常量空间的解决方案,并根据需要构建一个新数组。
int* prod(int *a, int len) {
int* b = new int[UINT_MAX];
int tmp = 1;
b[0] = 1;
for (int i = 1; i < len; i += 1) b[i] = b[i - 1] * a[i - 1];
for (int i = len - 1; i >= 0; i -= 1) {
b[i] = b[i] * tmp;
tmp *= a[i];
} // for
return b;
} // prod
函数的契约应该是新数组的大小与输入数组相同(即使我们秘密地知道它更大)。当然,这并不像现场计算那么有效,但这不是问题的问题(至少是它的措辞方式)。
答案 2 :(得分:0)
你可以这样做:
/* size = size of the original array*/
/* orgArr = the original array with the numbers*/
int i;
int temp = 1;
int *result = (int *)malloc(sizeof(int) * size);
memset(result, 1, size);
for(i = 0; i < size; i++)
{
result[i] = temp;
temp *= orgArr[i];
}
temp = 1;
for(i= n-1; i >= 0; i--)
{
result[i] *= temp;
temp *= OrgArr[i];
}
空间复杂度=&gt;上) 时间复杂度=&gt;为O(n)
通过将UINT_MAX用于结果而不是大小,可以使其成为一个恒定的空间。
答案 3 :(得分:0)
回顾问题,
天真的方法是使用除法,并计算一切就绪,
#!/bin/env ruby #because I can
n = aray.size - 1
prod = 1
0.upto(n) { |x| prod *= aray[x] }
0.upto(n) { |x| bray[x] = (aray[x]==0) ? 0 : prod/aray[x] }
请注意,我使用了bray [],但可能很容易发出结果,或者替换了aray []
但问题陈述不允许分裂。太糟糕了。
相反,我们需要保持原始值,将结果放入bray [], 我们循环aray []两次,从左到右计算产品,然后 从右到左,
#!/bin/env ruby #because I can
aray = [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31 ]
bray = [ ]
n = aray.size-1
prod = 1
0.upto(n) { |ndx| bray[ndx] = prod; prod *= aray[ndx]; }
prod = 1
n.downto(0) { |ndx| bray[ndx] *= prod; prod *= aray[ndx]; }
打印结果,
print "aray:\n";
aray.each_index { |ndx| print "[#{ndx}] #{aray[ndx]}\n" }
print "bray:\n";
bray.each_index { |ndx| print "[#{ndx}] #{bray[ndx]}\n" }
答案 4 :(得分:0)
这是该计划的核心部分。
给出
a [i]其中i的范围为0到n-1
b [i]其中i的范围从0到n-1。
假设n = 4用于演示目的
CODE从这里开始
int count,sum=1;
for(count = 0; count < n; count++)
{
b[count] = sum;
sum *= a[count];
}
/*
循环,计数= 0
b[0] = 1;
sum = a[0]
循环,计数= 1
b[1] = a[0]
sum = a[0] a[1]
循环,计数= 2
b[2] = a[0] a[1]
sum = a[0] a[1] a[2]
循环,计数= 3
b[3] = a[0] a[1] a[2]
sum = a[0] a[1] a[2] a[3] -- This sum is not used at all
在LOOP结束时
b[0] = 1;
b[1] = a[0]
b[2] = a[0] a[1]
b[3] = a[0] a[1] a[2]
*/
sum = 1;
for(count = n-1; count >= 0; count--)
{
b[count] *= sum;
sum *= a[count];
}
/*
在LOOP开始时
b[3] = a[0] a[1] a[2]
b[2] = a[0] a[1]
b[1] = a[0]
b[0] = 1;
循环,计数= 3
b[3] = a[0] a[1] a[2] -- multiplied with 1 will lead to the same answer
sum = a[3]
循环,计数= 2
b[2] = a[0] a[1] a[3]
sum = a[3] a[2]
循环,计数= 1
b[1] = a[0] a[2] a[3]
sum = a[3] a[2] a[1]
循环,计数= 0
b[0] = a[1] a[2] a[3] -- Multiplied with 1 will lead to the same answer
sum = a[3] a[2] a[1] a[0] -- This sum is not used at all.
在LOOP结束时
b[0] = a[1] a[2] a[3]
b[1] = a[0] a[2] a[3]
b[2] = a[0] a[1] a[3]
b[3] = a[0] a[1] a[2]
* /