剑指offer编程题解法汇总31-整数中1出现的次数(从1到n整数中1出现的次数)

题目描述

求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。

 

我是这样拆分的:

首先是有规律的,比如当前数为n,则N的范围如下是,1的数量如下

0~9:只有1个,0到9只存在1个1。

10~19:拆分为0到9,和10到N。1+N+1;

20~99:比如N=33,则拆分为4*1 和10到19(不包含11中的第二个1)。其中0到99为20

100~109:拆分为0到99和100到N

110~119:拆分为0到99,100到109,110到N

120~199:拆分为0到99,110到119(同样不包含最前面的1),100到N

200~999:比如351,拆分为0到299,300到349,350到351。

举个实际例子,3135,

先求3130到3135,只算个位的,为1;

再求十位的,为3,则个位上出现次数为3,十位上的出现次数为10,则和为13。0到99为20次。

在求百位的,为1,则先求0到99的出现次数为20,加上百分位上出现的次数35,加上100出现的次数1,则和为56。0到999为300次

最终求千分位上的,为0到999出现了三次,则为3*300次,以及1000到1999上千分位上的1的次数,求和为1900。

 

import java.util.*;
import java.util.function.Supplier;

public class Test {
    static int maxLevel = 0;

    public static void main(String[] args) {
        int i = new Test().NumberOf1Between1AndN_Solution(103);
        System.out.println(i);
    }


    HashMap<Integer, Integer> map = new HashMap<>();

    public int NumberOf1Between1AndN_Solution(int n) {

        int mask = 1;
        int figure = 1;
        int last = 0;
        int times = 0;
        while (n / mask > 0) {
            int current = n / mask % 10;
            times += getTimes(n, figure++, current, last, mask);
            last = current;
            mask = mask * 10;
        }
        return times;
    }

    /**
     * @param figure  几位
     * @param current 当前位值
     * @param mask    掩码
     * @return
     */
    private int getTimes(int n, int figure, int current, int last, int mask) {
        int times = 0;
        Integer lasttime = map.get(figure - 1);
        if (lasttime == null) {
            lasttime = 0;
        }
        if (current == 0) {

        } else if (current == 1) {
            times = lasttime + n % mask + 1;
        } else {
            times = current * lasttime + mask;
        }
        map.put(figure, lasttime * 10 + mask);
        System.out.println("figure:" + figure + ",current:" + current + ",last:" + last + ",mask:" + mask + ",times:" + times);
        return times;
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

失落夏天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值