9月18日在写了几道笔试题,今天javaeye上有很多人参与讨论,其中有些高手的解法很不错,特此进行总结。面试题在《几个笔试题目(2010-09-18)》上。

1、在一个平面中画999条线,最多可以分为多少部分。写出推导公式。

该题很容易知道通项公式为:f(n)=f(n-1)+n

然而证明却不是那么容易。有一个高手(诸葛不亮)的证明很精彩,还画了图。引用如下:

解:
设当n条直线的时候,最多的面的个数为an。所以a1=2成立。
则:当n-1条直线的时候最多有a(n-1)个面。
现在再增加一条线,即n条线,两条直线只有两种关系,即相交,平行。
首先考虑第n条线与前面的(n-1)都相交的情况。
先看一个简单的例子:第四条直线与前三条都相交的情况,如下图:
北极星为您引航
第四条直线会增加4个区域。
现在考虑第n条与前(n-1)条都相交的情况:如下图:
北极星为您引航
考虑到n-1条直线中间会(n-2)个区域。加上两边的2个区域,一共是n个区域(影印部分)。
所以an=a(n-1)+n
接着考虑与某一条直线平行的情况,可以这样考虑相交会比平行多处一个两条直线围成的区域。
所以平行不会产生最多的区域(可用反正法证明),这样也就证明了产生最多的面的情况是n条直线
两两相交。
最后讨论n条直线两两相交的可能性分析:如下图:
北极星为您引航
考虑平面的无限性。我们可以用一个圆来模拟,这些直线是圆的半径。
设两条相邻直线之间的夹角为b,那么直线的条数最多为360/b。 考虑b趋向无穷小,则,条数最多是无
穷大。
证毕。

2、将正整数的阿拉伯钱数转换为中文形式,如1011→一千零一十一,输出。

传统的方法很多人都会,主要实现是注意一些细节问题,主要是0的处理。回复中有一位(yangguo )的回复很不错。经polaris修改后代码如下(主要增加了注释,原回复没有任何注释)(核心代码,详细可到最后链接下载):

  1. private static String[] ChinaDigit = {"零","一","二","三","四","五","六","七","八","九"};  
  2.     private static String[] UNIT = {"","","十","百","千"};  
  3.     private static String[] BIGUNIT = {"","万","亿"};  
  4.       
  5.     private char[] digit;  
  6.       
  7.     /**  
  8.      * 主函数,负责分组,并循环处理这些分组  
  9.      * @param n  
  10.      * @return  
  11.      */ 
  12.     public String trans(int n){  
  13.         StringBuffer buff = new StringBuffer();  
  14.           
  15.         digit = String.valueOf(n).toCharArray();  
  16.         int length = digit.length;  
  17.           
  18.         // 获得头部分组的下标(从左往右,分组的下标递减,最右边一个分组是0)  
  19.         int pos = (length - 1)/4;  
  20.         // 获得头部分组的长度(即位数)  
  21.         int headLength = (length - 1)%4 + 1;  
  22.           
  23.         // 处理完头分组并在其后加上组间单位,如万、亿  
  24.         buff.append(partTrans(0,headLength) + BIGUNIT[pos--]);  
  25.         // 处理接下来的分组  
  26.         for (int i = headLength;i < length ; i = i + 4) {  
  27.             buff.append(partTrans(i , i + 4) +  BIGUNIT[pos--]) ;  
  28.         }  
  29.         return buff.toString();  
  30.     }  
  31.       
  32.     /**  
  33.      * 处理分组,从高位到低位处理(左到右)  
  34.      * @param start  
  35.      * @param end  
  36.      * @return  
  37.      */ 
  38.     private  String partTrans(int start, int end) {  
  39.         StringBuffer buff = new StringBuffer();  
  40.           
  41.         // 标记上一个处理的数字是不是0  
  42.         boolean isPreDigitZero = false;  
  43.           
  44.         // 循环处理组内所有数字  
  45.         for (int i = start; i < end; i++) {  
  46.             int cur = digit[i] - '0';   // 当前数字  
  47.               
  48.             // 保证多个零连着时只加入一个零,且该零不在组内最后位置  
  49.             if(cur != 0 ){  
  50.                 if(isPreDigitZero == true){  
  51.                     buff.append(ChinaDigit[0]);  
  52.                 }  
  53.                 buff.append(ChinaDigit[cur] + UNIT[end - i]);  
  54.                 isPreDigitZero = false;  
  55.             }  
  56.             else {            
  57.                 isPreDigitZero = true;  
  58.             }             
  59.         }         
  60.         return buff.toString();       
  61.     } 

另外,youaretheboy的思路值得参考,不过还有很多要考虑的地方

第三编程题,其实可以把数字从小到大一个一个push压栈,然后循环出栈pop,判断每次出栈的数据是否为0,如果不是0的话,就判断栈的总数,可以得出位数(如万,千等),如果为0的话,就一直出栈,不做任何处理...大概思路是这样

polaris的回复:不过有一个地方,是0也不能啥也不处理,得输出零字,如果多个零只输出一个,如果零在万、亿之类的位上也要特殊处理;对于非0情况,也有需要另外处理的,比如1在十万位上,万位是0和不是0处理方式也会不一样吧。需要考虑的地方还是蛮多的。不过思路挺好的。

下载类文件MoneyTrans.java