几个笔试题分析

一位网友说参加了迅雷的笔试,题目在这里:

http://topic.youkuaiyun.com/u/20090912/20/8c60e06e-321c-49a6-b2cc-59248ba9cf36.html

 

第一道是将一幅牌随机发给四个玩家。Lz对这个问题有这样的一个描述:

我的想法就是穷举52张扑克牌分4份的所有可能,并存储起来,然后rand()%(可能性数目)产生一个索引,索引到对应的某种可能性。这种概率问题似乎可用递归方式解决?这个算法在扑克游戏里应该经常用到。

52张牌分四份有多少种可能呢?

上过高中的人都应该知道的吧,共有计算公式,整理一下为52!/(13!)^4,用系统自带的计算器算一下的结果是

53644737765488792839237440000.021,忽略小数点。到这里我们就可以否定lz的这个想法了。

 

其实stl中有个函数random_shuffle(begin, end);可以将容器中的从begin 到end的数据打乱,用这个函数将1~52打乱后按顺序发给每个玩家就可以了。这个函数的原来是什么?你可以看一下源码。这里我引用http://bbs.pediy.com/showthread.php?t=55582中的分析:

 程序中设置一个变量,记住末发牌数,假设为n,每次发牌时,就是在 0...(n-1) 的范围内产生一个随机数,这个随机数就是内存中那幅牌中的第几张牌,然后将这张牌抽出,发给玩家后,再将余下牌中的最后一张牌(索引号:n-1)放到这张牌的位置上来。
    这样,产生的随机数虽然可能相同,那只是表示要抽取的牌的位置是相同的,由于牌已经被更换,所以每次抽取的牌肯定是不一样的。

这是widows自带的小游戏红心大战中的发牌算法,很精妙,原帖作者是看着汇编代码分析的,这还挺有耐心的。产生随机数还是要用52次。笔试题中说“已有随机整数生成函数rand(),但开销较大”,言下之意是要少用了,那怎么办?微软都这样用了,我就无视这个限制好了。

 

第二题,将一个字符串逆转,如"hello"变成"olleh",不许调用任何已有的字符串库函数,要求尽量高效,以及占用尽量少的存储空间。

其实就是不用中间变量将两个整数型或字符型变量交换。你可以用+活*来完成,数值太大的话可能会溢出,所以用异或^来操作最好了,引用一位回帖的代码:

void swap( unsigned char& l, unsigned char& r )
{
    l
^= r;
    r
^= l;
    l
^= r;
}
void invert( unsigned char* str, const unsigned int length )
{
    unsigned
char* head = str;
    unsigned
char* tail = str+n;
   
while ( tail-- != head )
    {
        swap(
*head, tail );
       
++head;
    }
}

 


第三个题,有10亿个无符号整数存储在文件中,取值范围是0-1000万,给定值value返回大于该数的个数。完成以下类函数的实现:
class order_calculator
{
  order_calculator();
  ~order_calculator();
  unsigned get_bigger_count(unsigned value);
}
已有函数get_value_by_index(unsigned index)根据index索引值返回值可以调用,但此函数开销较大。

在文件中的数据是无序的,那么只能遍历了吧,数据量比较多,可以分几次加载到内存。有序的话二分查找第一个大于value的值,马上就可以根据下标算出所有大于value的数的个数了。如果把这些数据加载到数据库中,那对于我们来说这个任务就是一个select语句的问题了,呵呵~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值