闲逛CSDN看到MoreWindows大神博客的《【白话经典算法系列之十四】腾讯2012年实习生笔试加分题》立马截图题目部分(首先自己思考的习惯)
MoreWindows大神博客地址:http://blog.csdn.net/morewindows/article/details/8742666
阅读题目我们可以得出几点:
1、构造过程中不能使用除法(*重要)2、要求O(1)空间复杂度和O(N)时间复杂度(*重要)3、除遍历记数器与a,b数组不能使用任何第三方变量(必须的)
一、首先不能使用除法运算,我们分析题目需求得出 b[j] 的数值其实是数组 a[N] 中除了元素 a[j] 的其他所有元素的乘积
二、要求O(1)空间复杂度和O(N)时间复杂度:
1、O(1)的空间复杂度这点很好满足 a[N],b[N] 数组随便当临时变量使用
2、O(N)的时间复杂度根据题目分析如果使用for,while的话免不了两次for或者while.根据自己编写习惯认为这样就时间复杂度为O(2N)(腾讯的加分题应该会思考这点吧-个人看法)
3、转回来想来想去只有递归算法能够满足题目需求,递归遍历时候利用函数返回可以做到媲美两此for或者while的过程.刚才我们已经得出数组 b[N]的每个元素的数值都是数组 a[N] 中除了元素 a[j] 的其他所有元素的乘积,在只能使用遍历计数器、a[N],b[N]这三种变量的情况下怎么来实现呢?
我们再来分析数组 b[N] 中每个元素的数值例如:
b[j]=a[0]*a[1]*a[2]...*a[j]...*a[N-1]/a[j]
转化一下得出:
b[j]=(a[0]*a[1]*a[2]...*a[j-1]*a[j]*a[j+1]...*a[N-1])/a[j]
一个很简单的数学公式,简化一下(去掉标记的 a[j])就是:
b[j]=a[0]*a[1]*a[2]...*a[j-1]*a[j+1]...*a[N-1] 备注:即不乘 a[j]就不用除 a[j]
根据上面的公式我们注意到下表 a[j-1] 与 a[j+1] 根据这两个节点我们发现 b[j] 可以这样构造:
b[j]=(a[0]*a[1]*a[2]...*[j-1]) * (a[j+1]...*a[N-1])
这个时候我们把 b[j] 的构造分成了两个部分然后再把两个部分相乘积就是我们想要的结果[j下标前面的乘积 * j下标
后面的乘积]下面开始编码
三、在不使用其他第三方变量前提下开始编码工作:
eg code:
1.首先声明数组A,B
int A[N]={......}; int B[n]={0};
总结:2.函数入口处处理,我们使用 B[j] 来保存 A[j]前面部分的乘积
int Recur(int i) { if(i==0) B[i]=1; /*当下标为0时候,b[0]前面部分的乘积为1*/ if(i==N-1) return A[i]; /*当i为最后一个下标时候开始推出递归函数*/ B[i+1]=B[i]*A[i]; /*B[i+1]的前面部分乘积=B[i]*A[i]*/ B[i]=B[i]*Recur(i+1); /*B[i]的真正数值=B[i]前面部分乘积(此时就是B[i])*B[i]后面部分 的乘积(此时递归函数Recur()就是返回的对应下标 i 时候后面部分的元素乘积*/ return A[i]*=A[i+1]; /*返回 A[i] 后面部分元素的乘积*/ }
代码中只是用了遍历数组的下标计数器 i,函数执行完毕数组 A[N] 中的元素数值已经被全部改变.如果想保持原来数值可以使用 A[0]来作为临时变量还原
相对于使用for或者while来实现的话上面我觉得更能够满足腾讯题目的需求.做完之后找到MoreWindows大神的博客看到没有这种实现便写下自己的思路
鉴于自己语言描述能力有限,以上若有含糊大家指教!!!