打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
腾讯2012年4月笔试题附加题

问题描述:两个数组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)

谈谈自己的解题思路吧,拿到这道题的时候,我首先注意到题目的3个要求:1.不准用除法2.不允许使用额外变量;3.o(n)的时间复杂度。由于不允许使用额外变量,所以我想到应该是在b[n]上做文章,结合不能用除法,我想到A^A=0,于是又A^A&1 = 1。再乘以剩下的各个乘子就得到b[i]。

本来以为到这里就结束了,后来发现这个方法有问题,因为这样只解决了不用除法做/a[i]的问题,没有解决如何乘上除了a[i]以外的数的问题。继续观察b[i]的结构发现,b[i]可以写成BaBb,其中Ba=a[0]*a[1]…*a[i-1],Bb=a[i+1]*a[i+2]…*a[n-1],自然的就联想到了分别从头和尾部遍历a[n]计算Ba,Bb的方法,话不多说,代码如下:

1 void foo(int a[],int b[],int n){
2         int i;
3         b[0] = 1;//用b[0]做辅助变量;
4         for(i = 1; i < n; i++)
5         {
6             b[0] *= a[i - 1];//从前往后乘得到Ba;
7             b[i] = b[0];
8         }
9         b[0] = 1;
10         for(i = n-2; i > 0; i–)
11         {
12             b[0] *= a[i + 1];//从后往前乘得到Bb;
13             b[i] *= b[0];
14         }
15         b[0] *= a[1];//不能忘记算出b[0];
16         for(i = 0; i < n; i++)
17         {
18             cout << b[i] << ” “;
19         }
由这道题联想到两类题型:

一.对运算方法有限制的题。

例如 题目1:不用乘法或者加法将一个数N增加8/7倍.

思  路:考虑到8为2的倍数,对一个数乘以/除以2就是对其进行左/右移,于是有

增加 8倍:n<<3; 增加7倍(n<<3)-n;

题目2:求1+2+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字以及条件判断语句。

思  路:1+2+…+n=(n^2+n)/2,由上题知道n/2可以通过移位运算获得,只要想办法求n^2。模拟手算乘法的思路,不难得出结果。

#define T(X,Y,i)((Y & 1<<i)) && X+=(Y<<i)//(Y & 1<<i)取出n2进制中为1的那一位,分别乘以N并相加,即得到n^2
int foo(int n)
{
int i,r=n;
T(r,n,0);T(r,n,1);T(r,n,2);T(r,n,3);…T(r,n,31);
return r>>1;
}
这类题的典型思路是,在不能使用四则运算符时,考虑数在计算机中进行运算的方式,可以使用移位,与,或,异或等等位运算符得到结果。

二:可以对所求或所处理内容分块考虑的问题。

例如:

题目:定义字符串的做旋转操作:把字符串前面的若干个字符移动到字符串尾部。

如把字符串abcdef做旋转2位得到字符串cdefab。

实现字符串做旋转的函数,要求对长度为n的字符串操作的时间复杂度为o(n),空间复杂度为o(1).

思路:不妨令S=abcdef,于是根据题目要求可以将S划分为Sa=ab,Sb=cdef;题目转化为:将S=SaSb,中的SaSb即交换位置,是不是瞬间简单了很多。代码如下:

char* LeftRotateString(char* pStr, unsigned int n)
{
if(pStr != NULL)
{
int nLength = static_cast<int>(strlen(pStr));
if(nLength > 0 && n > 0 && n < nLength)
{
char* pFirstStart = pStr;
char* pFirstEnd = pStr + n – 1;
char* pSecondStart = pStr + n;
char* pSecondEnd = pStr + nLength – 1;

// reverse  Sa
ReverseString(pFirstStart, pFirstEnd);
// reverse Sb
ReverseString(pSecondStart, pSecondEnd);
// reverse S
ReverseString(pFirstStart, pSecondEnd);
}
}

return pStr;
}
void ReverseString(char* pStart, char* pEnd)
{
if(pStart != NULL && pEnd != NULL)
{
while(pStart <= pEnd)
{
char temp = *pStart;
*pStart = *pEnd;
*pEnd = temp;

pStart ++;
pEnd –;
}
}
}

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
字符串的全排列和组合算法
经典面试题(一)附答案 算法+数据结构+代码 微软Microsoft、谷歌Google、百度、腾讯
char * 与 string 类型相互转换方法
C语言实现去除字符串中空格的简单实例
微软经典面试测试题和参考答案(变态) - TOMB RAIDER - CSDNBlog
C#字符串截取,字符串分割
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服