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]);
}