百度笔试题10

来源:互联网 发布:先锋网络av功放接收机 编辑:程序博客网 时间:2024/04/28 18:02

题目一:中国有13亿人,怎样找出重复最多的名字?

http://topic.csdn.net/u/20071111/14/c9d61173-ba2e-4ab9-9d8b-439c47597646.html

 

Answer1

首先,排除那些长度大于3的名字,因为生活中最常见的名字是2个字或3个字的,长度大于3的名字不常见。

然后,从姓分析。

最常见的名字的姓必然在百家姓中排名靠前,因此只要考虑名字的姓以百家姓中的就可以了。

然后考虑其他的。

找一些名字中的常用字,这些字基本上都是好字,数量不会很多,并将这些字建一个Hash表(按汉字编码来hash,若这个字是好字,那么将对应位置置1,否则置0)。

 

扫一遍全国人民的名字,分析其中的姓是否在百家姓中、名字中的字是否是好字。若两个条件满足,则按姓氏留下该名字(即同姓的放在一个文件中),否则,剔除该名字。

 

 GB 2312-80 把收录的汉字分成两级。第一级汉字是常用汉字,计 3755 个,置于1655区,按汉语拼音字母/笔形顺序排列

 

GB 231280 图形字符代码表

 

01-07 08-15 16-23 24-31 32-39 40-47

48-55 56-63 64-71 72-79 80-87 88区以下略

 

结合汉字编码表,可以设计一个算法来解决问题。

 

因为名字一般是常用汉字,所以在剩下的按姓氏分的名字中,由于同一个文件姓一样,所以同一个文件中的名只能有3755*3755种可能,为方便计算,我们将它放大为4096*4096,因此,可以开一个长度为 4096*4096 Hash表:

int Hash[4096*4096],每一个可能的名字对应着表的一个下标索引。

 

对每一个姓文件,都进行如下操作:

开始时将Hash[]全部清零。

然后就开始扫描,将每个名字转化为一个数字index++Hash[index]

最后,在Hash[]中找到最大者及其对应的下标索引k就可以了,那么,在这个姓中出现次数最多的名,可以由下标索引k得到。

 

空间要求是4096*4096*4=16777216*4=64M,不算太大。

 

Answer2:

试试这个算法:  线性的

 

假设汉字编码为GB2312十六进制编码,那么一个名字在计算机内存储表示为一系列的二进制位。譬如 “张三“,应当是一个32位的二进制位串,“张三丰”应当是一个48位的二进制位串。(一个汉字占用两个字节)由于编码严格,所以名字不同,编码绝对不同。

 

算法思想:

 

建立一棵二叉树,类似哈夫曼编码树,遇0转向左子树,遇1转向右子树。每个节点设置一个计数器 count, 保存从根节点到该节点路径所代表的位串(其实代表一个名字)的重复次数。

 

对于每个名字,转化为位串,沿二叉树到达对应节点,将其计数器加一,若比当前最大重复还大,则更新当前最大。当然同时这也是一个建树的过程,如果第一次遇到就建立路径了。

 

相信中国人名字都不长,平均长度为3个汉字吧,则访问该树的平均深度为3*16 = 48,常数级。

 

复杂度分析: 时间复杂度 O(n) ,这里n为中国人的名字总个数;

            空间复杂度,一棵深度不大的树而已,不会超过 2^m ,这里m为最大二进制位串长,即最大深度。

 

进一步提高效率:

 

将二进制串转化为八进制串或十六进制串,可以减小深度。当然这时候就是B树了。

 

八进制串时平均访问深度为 6

十六进制串时平均访问深度为 3

 

 

 

 

题目二:

http://blog.csdn.net/dremi/archive/2008/09/22/2963912.aspx

 

百度笔试题:

 

#include <stdio.h>

 

int main()

{

     int x;

     x = 4;

     x += x-=x-x--;

     cout<<x<<endl;

     return 0;

 }

x得结果是什么?

 

Answer1

让我们来分析一下:

首先执行到07行代码时,先是取出x的数据即为4,然后执行x-x ,4 - 4 = 0;

其实这个时候 x -= x-x--)中第一个x得值也为4,即他们3个值刚开始是相同的,也就是这个等式得

x = x - (x - x--);

所以执行到(x -= x-x--)时,x的值变为4 此时在执行x += x,所以x现在变为8,但别忘了最后还有一个x--要执行。

所以最终结果是7

 

所以这个等式最终可以化成这样的:

x = x + (x = x - (x - x--));

 

vc2005的汇编代码可以得出:x = x + (x = x - (x - x--)) x += x-=x-x--;是一模一样的:

00414BFE  mov         dword ptr [x],4

    x += x-=x-x--;

00414C05  mov         eax,dword ptr [x]  

00414C08  sub         eax,dword ptr [x]  //x -x

00414C0B  mov         ecx,dword ptr [x] 

00414C0E  sub         ecx,eax            //x -= (x-x)

00414C10  mov         dword ptr [x],ecx  //更新x

00414C13  mov         edx,dword ptr [x]  //取出x的值

00414C16  add         edx,dword ptr [x]  //计算x += x;

00414C19  mov         dword ptr [x],edx  //更新x

00414C1C  mov         eax,dword ptr [x] 

00414C1F  sub         eax,1   //x--

00414C22  mov         dword ptr [x],eax //更新x

    cout<<x<<endl;

 

    00414BFE  mov         dword ptr [x],4

    x = x + (x = x - (x - x--));

00414C05  mov         eax,dword ptr [x]

00414C08  sub         eax,dword ptr [x]

00414C0B  mov         ecx,dword ptr [x]

00414C0E  sub         ecx,eax

00414C10  mov         dword ptr [x],ecx

00414C13  mov         edx,dword ptr [x]

00414C16  add         edx,dword ptr [x]

00414C19  mov         dword ptr [x],edx

00414C1C  mov         eax,dword ptr [x]

00414C1F  sub         eax,1

00414C22  mov         dword ptr [x],eax

    cout<<x<<endl;

 

当把x += x-=x---x)时,答案就变成6

他可以扩展成这样:x = x + (x = x - (x - (--x)));

即:x = x + (x = 3 - (3 - 3));

    x = 3 + 3;

    x = 6;

这个的汇编代码如下:它首先把x1

    00414BFE  mov         dword ptr [x],4

    x += x-=x-(--x);

00414C05  mov         eax,dword ptr [x]

00414C08  sub         eax,1 //取出值就把x1

00414C0B  mov         dword ptr [x],eax //更新x

00414C0E  mov         ecx,dword ptr [x] //

00414C11  sub         ecx,dword ptr [x] //x - x

00414C14  mov         edx,dword ptr [x]

00414C17  sub         edx,ecx          x -= (x -x)

00414C19  mov         dword ptr [x],edx  //更新x

00414C1C  mov         eax,dword ptr [x]

00414C1F  add         eax,dword ptr [x]  x += x

00414C22  mov         dword ptr [x],eax  //更新x

    cout<<x<<endl;

原创粉丝点击