剑指Offer - JZ43 整数中1出现的次数(从1到n整数中1出现的次数)

描述

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

例如,输入12,1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。

思路:

1出现的总次数 = 个位上1的个数 + 十位上1的个数 + ……
故:简化问题,考虑第 i 位(从低到高)上1的个数:
令cur为当前位的数字,base为数量级,high为高位的数字,low为低位的数字,res为1出现的总次数,
若:
  情况1、cur = 1,则固定第 i 位,满足小于等n的数均为符合条件的数,即res += high * base + low + 1;
  情况2、cur ≠ 1,将该位退化到1,退化的时候考虑到低 i 位只有base个数第 i 含有1:
    · cur = 0,则:high -= 1,res += base;
    · cur > 1,则:low = 0,res += base - 1(不包含低位全0的情况);
    此时,cur退化到1,再用情况1;

下面用n = 1214,1234分别对上述步骤进行说明,为简化步骤,只考虑十位:
1)对于n = 1214,cur = 1,base = 10,high = 12,low = 4,
因为cur = 1,所以固定该位,考虑小于n的个数,而此时:只要[high, low] <= 124,即为满足该条件的数([high, low]表示由高位、低位组成的数,相当于擦除该位),即res += 125;

2)对于n = 1234,cur = 3,base = 10,high = 12,low = 4,
因为cur = 3,所以要做退化处理:考虑低2位,只有10~19十个数在十位上有1,故只要low = 0、res += 9,十位便能退化到1,再用情况1,有:res += 121(总:res += (high + 1) * base = 130);

代码:

class Solution {
public:
    int NumberOf1Between1AndN_Solution(int n) {
        int cur = n % 10, high = n / 10, low = 0, base = 1, res = 0;
        while (base <= n) {
            if (cur == 0)
                res += high * base;
            else if (cur == 1)
                res += high * base + low + 1;
            else
                res += (high + 1) * base;
            
            base *= 10;
            cur = high % 10;
            high /= 10;
            low = n % base;
        }
        return res;
    }
};

参考:

https://leetcode-cn.com/problems/1nzheng-shu-zhong-1chu-xian-de-ci-shu-lcof/solution/mian-shi-ti-43-1n-zheng-shu-zhong-1-chu-xian-de-2/

你可能感兴趣的:(C++,剑指Offer,算法)