wpcockroach

导航

谈一谈实际项目中的一个摇号需求

有多少人认为公司笔试的时候出的算法题(类似于leetCode上的题目)是极其无聊的东西?围脖上好像也有很多人认为这种笔试题毫无意义,不能反映一个程序员实际的工程能力。当然,我是从来不这么认为的。但是也不得不承认,实际的工作中确实遇不到这种笔试题中的场景。

不过,今天在工作中居然就遇到了这么一个问题,堪称一道经典笔试题。在说这道题之前,先把问题说清楚。

这是一个摇号程序。如果你熟悉股票相关的知识,可以知道新股申购会有一个配号。摇号程序的一个基本功能就是计算中签率。我们这里中签的意思是指配号的尾号为指定的的尾号。比方说中签尾号为53,那么所有尾号为53的配号申购成功。这个中签率的计算就是看配号中有多少个以指定尾号结束的配号。

把问题再说直白一点就是:给定一个数字A和一个正整数区间(B到C),问该区间中有多少个数字(求个数即可)以A结尾。同时,提供测试数据测试你写的程序(问题到这里就算描述清楚了,你可以自己写程序来试一试。如果觉得还有细节没交代清楚,请先自己假设,然后再看后文)。

这个程序之前长什么样子,我没看到。我就知道项目负责人对程序的健壮性非常怀疑,所以在群里动员大家提供测试用例。如果测试用例发现一个bug,奖励烧饼一个(可见我司多么地屌丝)...

故事既然是从测试用例说起的,那我们这里也从测试的角度先来看这个问题。

要提供测试用例,首先我们要完全明白题意。“以数字A结尾的数”,这个数字A能划分出等价类么,有边界值或者临界情况么?从这几个简单的测试角度出发的问题,就足够我们发现这个问题的一些陷阱。

最通常的情况,A=23,12等等,比较特殊的边界数字是0。由此我们还可以想到00、01、002、000325等以0开头的尾号。所以,等价类划分我们可以将A分为以0开头的尾号和非0开头的尾号。边界值就是0、00、000等。

第二,我们假定区间为[1,100],那么以02为尾号的数字的个数到底是多少?答案是1个,数字2。也就是说区间[1,100]这时应该看成是[001,100]。这也是一个坑。

出于上述几点讨论,我们可以看出这个函数的返回值和签名绝对不是简单的int match(int tail, int begin, int end)。可能的一种声明应该是int match(const string& strTail, int begin, int end)。那我们再来看怎么解决这个问题。

对于给定的一个尾号,我们假定它是XYZ,如果不考虑配号的范围,我们知道第一符合要求的数字是XYZ,第二个是1XYZ,第三个是2XYZ。所以同一尾号的数字相距的距离就是10^N,其中N为尾号的十进制位数(如果尾号以0开头,0也要算在其中)。

 基本上,该说的都已经说了,我再提供一段伪代码吧。

 1 int match(const string& strTail, int begin, int end)
 2 {
 3     int tail = stoi(strTail);
 4     size_t tailLen = strTail.length();
 5     int distance = pow(10, tailLen);
 6 
 7     int minMatch = begin;
 8     minMatch /= distance;
 9     minMatch *= distance;
10     minMatch += tail;
11 
12     if (minMatch < begin)
13     {
14         minMatch += distance;
15     }
16 
17     int maxMatch = end;
18     maxMatch /= distance;
19     maxMatch *= distance;
20     maxMatch += tail;
21 
22     if (maxMatch > end)
23     {
24         maxMatch -= distance;
25     }
26 
27     if (minMatch > maxMatch)
28     {
29         return 0;
30     }
31 
32     return (maxMatch - minMatch) / distance + 1;
33 }

 

posted on 2014-06-11 23:18  wpcockroach  阅读(691)  评论(0编辑  收藏  举报