当n = 216;

  • 个位上为1,216/10 + 1 * 1即01,11,21,..201; 211;
  • 十位上为1:设x代表一个(0-9)的数字。先不考虑210-216上十位的1。
    在1x-11x个位上可以取0-9即(21/10)*10。
    最后考虑21X的情况,因为X不一定能取到0-9。即210-216 共7个 216%10+1。
  • 其他位置类似。

当n = 206;

  • 个位上为1,206/10 + 1 。
  • 十位上为1:设x代表一个(0-9)的数字。先不考虑200-206上十位的1。
    在1x-11x个位上可以取0-9即(20/10)*10。
    最后考虑20X的情况,因为20%10 ==0,21X取不到,不考虑相加。

当n = 226;

  • 个位上为1,226/10 + 1 。
  • 十位上为1:设x代表一个(0-9)的数字。先不考虑220-226上十位的1。
    在1x-11x个位上可以取0-9即(22/10)*10。
    最后考虑22X的情况,因为22%10>1,210-219都可以取到,共10个;

因此当低位为1,0,大于1,判断的条件不同。

  • 当为1时和后面数字有关。
  • 当为0时和后面数字无关。
  • 当大于1时和后面数字无关。

+8是为了来减少当a的低位大于1的情况的判断,仅此而已。
+9是混淆当a的低位为1和>1的不同相加情况。

当a的低位为1时,补8不会进位,a/10==(a+8)/10,但需要a的后面数字的值。
当a的低位>1,补8会产生进位,效果等同于(a/10+1)*m,不需要再加。
当a的低位为0,补8不会进位,效果等同于a/10==(a+8)/10,也不需要再加。

cnt += (a + 8) / 10 * m + (a % 10 == 1 ? b + 1 : 0); 
等价 
cnt += a  / 10 * m + (a % 10 == 1 ? b + 1 : 0)+ (a % 10 > 1 ? m : 0);
class Solution{
public :
    int NumberOf1Between1AndN_Solution(int n) {
    int cnt = 0; // 统计1的个数
    for (int m = 1; m <= n; m *= 10) {
        int a = n / m, b = n % m;
        cnt += (a + 8) / 10 * m + (a % 10 == 1 ? b + 1 : 0);
    }
    return cnt;
}
};