1到40亿中存在的1的个数

最近偶然看见了这道微软的面试题目,题目是:

统计从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>

 

由于适用公式直接得出结果,故比较递归的方式更加快速。使用多组数据测试没有发现问题,欢迎各位能有改进意见,不胜荣幸!

 


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值