最近偶然看见了这道微软的面试题目,题目是:
统计从1至400亿之间的自然数中含有多少个1?比如1-11中,有1,10,11这三个自然数有4个1。
参考了dmh2002 大大的解题思路,自己总结了一套更高效的方法,现在拿出来给大家品评一下,如有建议请发帖转告。
好了,我们来看看这道题目的解题思路:
* 如果是1位数即1-9 则一定有1个1
* 如果是2位数即1-99 则10-19中一定有10个1,
* 然后10-99会有9个1位数上所计算出来的1的数量,即11,21...91会有9个1,
* 再加上各位上的1个1,
* 则为10+9*1+1=20,
* 如果是3位数即1-999 则100-199中一定有100个1,
* 然后从200-999之间会有9个2位数上算出来的个数,
* 再加上2位数上算出来的个数的数量与各位数的数量,
* 则为100+9*(20)+20=300
根据以上的实际数据我们可以使用大学学过的“递推方法”得到以下公式:
[1] x = n10(n-1)+1 (适用于10的次方数的情况,如:100、1000、10000……)
[2] x = 10n(1+nl/10) (适用于带系数的数字:40、400、4000)
其中:1.n 表示当前数字所在位数,比如:拿4234 中的4做例子,那么4处于千位,则4*103 那么n=3;
2.l表示当前数字的系数,还是拿4234做例子,那么l=4;
故由上面公式我们能过很容易推导出以下的程序(使用flex4):
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx">
<s:layout>
<s:BasicLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import mx.collections.ArrayList;
protected function button1_clickHandler(event:MouseEvent):void
{
countNum(Number(input.text));
}
private function countNum(num:Number):void//计算1-num中存在的1的总个数
{
var toStringNumSource:String=num.toString(); //目标数字转化为字符
var median:int=0; //位数
var onesNum:int=0; //目前有几个1在前面
var oneSum:Number=0; //1得总数
var nowNum:int=0; //当前系数
for (var i:int=toStringNumSource.length; i > 0; i--)
{
median=i - 1;
nowNum=int(toStringNumSource.charAt(toStringNumSource.length - i));
if(nowNum != 0){//当前数字不为0时
if (median == 0)//当前位数为0时
{
oneSum+=onesNum * nowNum+1;//在此位之前的1的个数*当前数字+1(这个1是个位数1-9中独有的1个1)
}
else if(nowNum!=1&&median!=0){//当当前数字不为1且位数不为0的时候调用 公式:
oneSum+=(Math.pow(10, median)) * (1 +onesNum * nowNum + (median * nowNum) / 10);
}
else if(nowNum==1&&median!=0){//当当前数字为1且位数不为0的时候调用 公式:
oneSum+=median * (Math.pow(10, (median - 1))) +onesNum * nowNum*Math.pow(10,median)+1;
}
if(nowNum==1){
onesNum++;//当当前数字是1则onesNum加1
}
}
else if(nowNum == 0){//该步没有意义,只是为了好理解故留下来
oneSum+=onesNum * nowNum;
}
}
output.text=oneSum.toString();
}
]]>
</fx:Script>
<fx:Declarations>
<!-- 将非可视元素(例如服务、值对象)放在此处 -->
</fx:Declarations>
<s:Button x="111" y="167" label="按钮" click="button1_clickHandler(event)"/>
<s:TextInput id="input" x="64" y="26"/>
<s:TextArea id="output" x="64" y="56" width="171" height="94"/>
<s:Label x="20" y="29" text="输入:" height="22" width="36"/>
<s:Label x="20" y="59" text="结果:" width="36" height="18"/>
<s:Label x="259" y="31" text="位数:" height="19" width="37"/>
<s:TextInput x="304" y="26" id="medianNum"/>
<s:Label x="259" y="58" text="个数:" width="38"/>
<s:TextInput x="304" y="56" id="oneNumShow"/>
</s:WindowedApplication>
由于适用公式直接得出结果,故比较递归的方式更加快速。使用多组数据测试没有发现问题,欢迎各位能有改进意见,不胜荣幸!