Multiplication of numbers
1. 题目:给定一个整数数组,要求输出一个数组,使新数组的第i位是原数组中除去第i位剩余数字的乘积。如输入{4,3,2,1,2},输出{12,16,24,48,24}。要求时间复杂度为:O(n),且不能使用除法运算。
2. 分析:如果可以使用除法运算很容易想到的算法是将原数组中所有数字相乘,然后遍历,每次除以原数组中的第i位,即得到新数组中的第i位。但是这个算法有一个问题,要是原数组中存在一个数字为0,那么乘积自然也为0,那么新数组中的所有数字都是0,结果不对,而且除以0会导致异常。文章中给出了一个采用O(n)空间的算法,即定义数组B为原数组从左向右相乘的结果{1,4,12,24,24}(第一个数为1,最后一个数为前面4个数相乘)。然后从右向左遍历原数组,将遍历到的数相乘得到p(p初始值为1),过程如下:
第4个数:B[i]*p=B[4]*p=B[4]*p=24*1=24 p=1
第3个数:B[i]*p=B[3]*p=B[3]*p=24*2=48 p=1*2=2
第2个数:B[i]*p=B[2]*p=B[2]*p=12*2=24 p=1*2*1=2
第1个数:B[i]*p=B[1]*p=B[1]*p=4*4=16 p=1*2*1*2=4
第0个数:B[1]*12=12 p=1*2*1*2*3=12
上面的算法需要O(n)空间,文章中最后给出了常数空间的算法:
1 void array_multiplication(int A[], int OUTPUT[], int n) { 2 int left = 1; 3 int right = 1; 4 for (int i = 0; i < n; i++) 5 OUTPUT[i] = 1; 6 for (int i = 0; i < n; i++) { 7 OUTPUT[i] *= left; 8 OUTPUT[n - 1 - i] *= right; 9 left *= A[i]; 10 right *= A[n - 1 - i]; 11 cout<<"OUTPUT["<<i<<"]="<<OUTPUT[i]<<endl; 12 cout<<"OUTPUT["<<n-1-i<<"]="<<OUTPUT[n-1-i]<<endl; 13 cout<<"left="<<left<<endl; 14 cout<<"right="<<right<<endl<<endl; 15 } 16 } 17 18 int main() 19 { 20 enum{aLength=5}; 21 int a[aLength]={4,3,2,1,2}; 22 int output[aLength]; 23 array_multiplication(a,output,aLength); 24 for (int i=0;i<aLength;i++) 25 { 26 cout<<output[i]<<" "; 27 } 28 cout<<endl; 29 return 0; 30 }
3. 对于上面O(1)空间的算法还不是很理解,这样的算法是怎么想到的啊???
4. 参考文章:
http://www.leetcode.com/2010/04/multiplication-of-numbers.html