腾讯2013的一道实习生笔试题
题目
给定一个数组a[N],我们希望构造数组b[N],其中b[i]=a[0]*a[1]*...*a[N-1]/a[i]。 在构造过程:不允许使用除法; 要求:O(1)空间复杂度和O(n)时间复杂度; 除遍历计数器与a[N] b[N]外,不可使用新的变量(包括栈临时变量、对空间和全局静态变量等); 请用程序实现并简单描述。
题目解析
本身这个题是很容易实现的,但是加了诸多限制,就比较有意思了。 我们一个一个来分析 1.不能使用除法,这个好解决,只要乘的过程中不乘a[i]即可,那么整个a数组就被分成了两部分, 一个是i位置前,一个是i位置后,注意:这个思考很关键,后面的实现都是基于它的,也可以说是 用了一点点分治吧 2.O(1)空间复杂度,没什么说的。 3.O(n)时间复杂度,就是说只能一重循环,注意:只能用一重循环, 但是没说用几次一重循环,也就是说可以多次,一次一重循环谁也做不出来。 4.除遍历计数器与a[N] b[N]外,不可使用新的变量(包括栈临时变量、对空间和全局静态变量等), 这个就厉害了,不能用变量存储值,就只能存在数组中,不能用栈临时变量,也就是不能用递归了, 没有这个条件的话用递归和一重循环也不是很难就可以做到。
逻辑思维好的可以直接看代码
分析过程
这个题目我们主要是运用迭代的思想,不断更新数据,首先前面我们说了a数组被分成两部分,前一部分和后一部分; 首先解决前一部分,当然是用b数组来存储结果, b[1] = a[0] b[2] = a[0]a[1] … b[i] = a[0]a[1]a[2]…a[i-1] 通过演算我们发现b[i]都要比a[i]多一个a[i-1],那么可以写成b[i] = b[i-1] + a[i-1],至于b[0], 就赋值1就好啦,这样我们就把前半部分解决了。这就是迭代的思想 后半部分还是得用迭代的思想,我们用b[0]来存后半部分,并迭代更新,只要逆序就好了, 看代码更直观,有了前面的铺垫相信很快就能看懂
/*
以三个元素举例
*/
#include <stdio.h>
#define N 3
int a[N] = {5,4,3};
int b[N];
void Translate(int a[], int b[],int n)
{
b[0] = 1;
for(int i = 1; i < n; i++)
{
b[i] = b[i-1] * a[i-1]; //b[i]保存的是a[0]一直到a[i-1]的乘积,也就是a在i位置之前所有元素的乘积
}
for(int i = n-1; i > 0; i--)
{
b[i] *= b[0]; //b[0]存储的是a[i+1]到a[n]的乘积,也就是a在i位置之后所有元素的乘积
b[0] *= a[i]; //b[0]的值迭代更新
}
}
int main()
{
int i;
Translate(a,b,N);
for(i = 0; i < N; i++)
printf("%d ",b[i]);
return 0;
}