http://blog.csdn.net/codearhat/article/details/6839897
a[0]变为a[1]到a[n-1]的积,a[1]变为a[0]和a[2]到a[n-1]的积,……a[n-1]为a[0]到a[n-2]的积。要求:具有线性复杂度。不能使用除法运算符。”
讨论:最后两项要求恰好排除了最直观的两种方法"两层循环乘法"、“求全部元素的积P,然后New[i] = P / Old[i]”,卡死了思路,完全没想出来
后来参考了 帖子 16楼 qq120848369 的答案才明白。(第一次还没看懂,跳过去了)
倒推出解题思路:新数组每个元素都是前、后两段“部分积”相乘的结果。前方的部分积很容易想到用数组保存结果,在O(n)的时间内计算。
关键是后方的部分积也可以同样算出,只是要反向累乘。逆向思维……
- #include <iomanip>
- #include <iostream>
- using namespace std;
- void show(int v[], int n, char const * name)
- {
- cout << name << ": ";
- for(int i = 0; i < n; ++i){
- cout << setw(7) << v[i];
- }
- cout << '\n';
- }
- int main()
- {
- int a[] = {2, 3, 5, 7, 11}; // 用质数测试保证每个积都唯一。
- int const N = sizeof(a) / sizeof(a[0]);
- int prod_fore[N];
- int prod_back[N];
- prod_fore[0 ] = 1;
- prod_back[N-1] = 1;
- for(int i = 1; i < N; ++i){
- prod_fore[i] = a[i-1] * prod_fore[i-1];
- }
- for(int i = N-2; i >= 0; --i){
- prod_back[i] = a[i+1] * prod_back[i+1];
- }
- show(a , N, "source ");
- for(int i = 0; i < N; ++i){
- a[i] = prod_fore[i] * prod_back[i];
- }
- show(prod_fore, N, "prod_fore");
- show(prod_back, N, "prod_back");
- show(a , N, "result ");
- }
注意:题目中未对空间复杂度做要求。不能一开始就武断认为只能申请一个长度为N的数组。
其实,只需要一个长度为N的辅助数组就可以,如下题(其中数组b[N]可认为是辅助数组):
问题描述:两个数组a[N],b[N],其中A[N]的各个元素值已知,现给b[i]赋值,b[i] = a[0]*a[1]*a[2]...*a[N-1]/a[i];
要求:
1.不准用除法运算
2.除了循环计数值,a[N],b[N]外,不准再用其他任何变量(包括局部变量,全局变量等)
3.满足时间复杂度O(n),空间复杂度O(1)
算法实现:
- int main(int argc, char* argv[])
- {
- int i;
- int a[10] = {1, 2, 1, 2, 1, 2, 1, 2, 1, 2};
- int b[10];
- b[0] = 1;
- for(i = 1; i < 10; i++)
- {
- b[0] *= a[i - 1];
- b[i] = b[0];
- }
- b[0] = 1;
- for(i = 8; i > 0; i--)
- {
- b[0] *= a[i + 1];
- b[i] *= b[0];
- }
- b[0] *= a[1];//注意下这个地方
- for(i = 0; i < 10; i++)
- {
- cout << b[i] << " ";
- }
- cout << endl;
- return 0;
- }