剑指offer(三十一)-整数中1出现的次数(从1到n整数中1出现的次数(Java版)

描述

输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数

例如,1~13中包含1的数字有1、10、11、12、13因此共出现6次

示例1

输入:13

返回值:6

第一种解法

最简单的暴力方式,遍历每一个数字,判断是否包含1,不过多解释,代码如下

public int firstNumberOf1Between1AndN_Solution(int n) {
        int result = 0;
        if(n < 1){
            return result;
        }
        for (int i = 1; i <= n; i++) {
             String str =  String.valueOf(i);
            char[] chars = str.toCharArray();
            for (char c : chars) {
                if(c == '1'){
                    result++;
                }
            }
        }
        return result;
    }

第二种解法

这种方法非常的有意思,需要先理解清楚,才好写代码,将 1 ~ n 的个位、十位、百位、...的 1 出现次数相加,即为 1出现的总次数。假设一个n位数num,规定num的第i为ni,那我们就可以将num写为nx nx-1..n2n1。我们把当前ni规定为cur,低于当前位的数字记为low,高于当前位的数字记为high,10的i次方为10i 记为dight,举个例子我们以3105为例,某一位中出现1的次数,根据cur值的不同,可以分为以下三种情况,

  1. 若cur = 0,此时1的出现次数只由高位决定,即high决定,公式为 high * dight,3105的high为32,low为5,dight为10,经过公式计算31*10 = 310个,即0010-0099,0110-0199一直到3010-3099一共有31组,每组10个1(这里只计算十位上的1)和公式完全符合。
  2. 若cur = 1时,此为1的出现次数由高位high和低位low决定,计算公式为high * dight + low + 1 ,3105的high为3,低位为05,dight为100 经过计算公式计算3*100 + 5 +1 = 306,即0100-0199,1100-1199一直到2100-2199一共三组 加上额外的3100-3105,每组100个1(这里只计算百位上的1)和公式完全符合
  3. 若cur > 1时,此时1的出现次数只由高位high出现,计算公式为(high + 1) * dight, 3105的cur为5,即high为310,dight为1,经过计算公式计算为(310+1)*1 = 311,即0000-0009,0010-0019一直到3000-3099共310+1 = 311组。和公式符合

有了以上逻辑,代码如下

public int secondNumberOf1Between1AndN_Solution(int n) {
        int result = 0;
        if(n < 1){
            return result;
        }
        //i是位数
        for (int i = 1; i <= n; i*=10) {
            int high = n /(i*10);
            int low = n % i;
            int cur = (n/i) % 10;
            if(cur == 0){
                result += high*i;
            }else if(cur == 1){
                result += high*i + (low + 1);
            }else {
                result += (high + 1) * i;
            }
        }
        return result;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值