腾讯一道面试题

128 篇文章 4 订阅
36 篇文章 1 订阅

28)给定一数组a[N],我们希望构造数组b [N],其中b[j]=a[0]*a[1]…a[N-1] / a[j],在构造过程中,不允许使用除法:
要求O(1)空间复杂度和O(n)的时间复杂度;
除遍历计数器与a[N] b[N]外,不可使用新的变量(包括栈临时变量、堆空间和全局静态变量等);
实现程序(主流编程语言任选)实现并简单描述。
先忽略题目所给的任何限制,天马行空想象一下,能想象到什么解法?
1.最简单的办法,将a[0]到a[N-1]全乘起来,再遍历数组,依次除以a[j]即可,这是最简单的办法,但是,不允许使用除法,此法不可行.
2.既然不能使用除法,我们可以换一种思维方式:先将a[j]左边的数全乘一遍,a[j]右边的数全乘一遍,二者再乘起来,就可以避免除法,得到了a[j]的值.这样子,显然要求得每一个a[i]都需要遍历一遍数组,时间复杂度为o(n),求完所有的a[0]到a[N-1],时间复杂度为o(n^2).不符合题意.但是,这个办法给我们提供了一种可能性,那就是,能不能在二层嵌套循环中整合成一层嵌套循环?这个问题暂时不得而知,但是,我们可以知道的是,我们可以实现这个o(n^2)的方法,先实现出来再看看接下来能不能降低时间复杂性.
o(n^2)时间复度性的代码:

void ConstructArray(int* A,int* B,int N)
{
	for(int i=0;i<N;++i)
	{
		B[i]=1;
		for(int j=0;j<N;++j)
		{
			if(j != i)
			{
				B[i]=B[i]*A[j];
			}
		}
	}
}

即: | 为分割线.
表:1-1
A[0]=1|*A[1]*A[2]*........*A[N-1]
A[1]=A[0]*|*A[2]*A[3].......A[N-1]
A[2]=A[0]*A[1]*|*A[3]*......A[N-1]
......
A[j]=A[0*A[1]*...A[j-1]|A[j+1]*A[j+2]*...A[N-1]
上面的代码实现思路是这样子的:将问题分为两部分:对于A[0],A[1].....到A[N-1]的每一个A[i],通过一遍的循环遍历数组得出结果.这样子就形
成二层嵌套.
现在,我们需要换一个角度想,能不能将分割线|左右两边的结果全算出来保存在一个数组中,然后,两个数组对应相乘就可以解决问题了.中间,我们不需要两个暂时数组,可以利用B[N]数组的特点来完成这种累积的过程.

void ConstructArray(int* A,int* B,int N)
{
	if(!A || !B) return ;
	B[0]=1;
	for(int i=0;i<=N-2;++i)
	{
		B[i+1]=B[i]*A[i];//对比表:1-1容易知道,构造分割线左边部分
	}
	//上面已经建立了一个金字塔式的左分割线部分,现在自底向上重复上面的操作就能建立右分割线部分
	
	for(int i=N-1;i>=1;--i)
	{
		B[i]=B[i]*B[0];
		B[0]=B[0]*A[i];
	}
}

总结:

        题目要求比较苛刻,思维方式是利用B[i]构造左边金字塔型的数组,再构造右边的金字塔型.中间的转换比较巧妙.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Raise

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值