lintcode-末尾的零

     主考官看了下,说不对,于是我又开始列举,想了好半天,才发现当20*50的时候,会多产生一个零,然后100本身会产生两个零。我又想当然地认为只要当n小于10时return n/5;或当n为10-100之间时return n/5+n/50或当n为100-1000之间的时候return n/5+n/50+n/500。。。。就可以了,但即使是这样,我还是没办法写出这个函数,后来觉得这样去思考这个问题,有点把问题复杂化的感觉,其实应该从程序的思维出发,利用程序能够循环,能够迭代的特点去简单化一个问题,而不是用数学归纳,把问题越分解越复杂。然后主考官问我n=100的情况有多少个零,我用刚才归纳的n/5+n/50一算得到22,他说答案是24, 我追问我哪儿漏了,他只让我自己回去想。

     结果回到宿舍往床上一躺才突然发现,5与偶数相乘便产生一个0,由于偶数比5要多多了。再想想,原来自己漏掉了25和75这两个数,而这两个数之所以会多产生个0是因为其可以拆分出两个5的相乘,其实所谓的逢5逢10,本质上都是逢5,因为10也是5*2,任何带零的数之所以能够产生尾数0正是因为它能拆出一个5来。 于是问题便简单化了,把所有数字遍历一遍,检验所有的数能拆出几个5来,并将这个数加到一个整数count里便行了,初步的程序为:

 

 int cal_zero(int n)
{
   int count=0;
   while(n>0)
      {
          int m=n;
          n--;
          while(m%5==0 && m>0)
              { 
                  count++;
                  m=m/5;
               }
        }
   return count;
}

 

     分析下这个程序,虽然可以计算出来,但是要遍历1-n中的每一个整数(第一个while循环),然后每个整数都要进行一到多次的除以5运算(第二个while循环) ,非常耗时。后来在迷迷糊糊的睡梦中,又突然想到只要把每个5的倍数进行循环处理不就行了,第一个while循环可以改良为while(n%5==0 && n>0),原来每遍历5个,现在只要1个,但转念一想,既然这所有的5的倍数都肯定可以为count加1, 是不是可以将while循环改为while(n/5)得到1到n整数里能被5整除的个数,将count加上这个数,然后再分析这里这里面能被5整除的数是否除以5以后还能再被5整除。

     我理清下思路,考虑100以内的数,首先将所有能被5整除的数罗列出来,5,10,15,20,25,...,100。然后将这些数都除以5,提取出20个5,故可得到20个零。以后,得到1,2,3,...20。 再将这些数中能被5整除的数罗列出来,5,10,15,20。提取出4个零,得到1,2,3,4。再无法提供,便不再递归。而这递归本质上就是100/5=20,20/5=4, 4/5=0.  20+4+0=24.写程序如下:

int cal_zero_2(int n)
{
    int count=0;
    while(n/5>0)
       {
           count+=n/5;
           n=n/5;
        }
     return count;
}

 

    相比前面的程序,这个要简单多得多。n=100时,前面程序外层while要走100次,内层逢25,50,75,100还要走2次,其他的都1次。第二个程序总共走3次。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值