1.如何获取每一位数字的 左边数字 和 右边数字?
数字3101592,假如现在cur = 0,base = 10000(是当前考虑的位数), high是cur左边的部分、cur是当前位的数字、low是cur右边的部分。
high = n / (base * 10) = n / 100000 = 31
cur = (n / base) % 10 = (n / 10000) % 10 = 0
low = n % base = n % 10000 = 1592
2.出现的次数取决于小于n的那些数,分情况讨论。
计算1出现的次数需要计算所有位上1出现的次数的加和,所以要遍历每一位,不断更新当前位前后的数字是什么。假设当前位是1时,计算1出现的次数。
- 当cur = 0时
还是拿31 0 1592举例子,如果当前位出现1了,那必然是high是0-30区间内,因为如果是311开头就比n要大了。当high是0-30的时候,无论low怎么选都比n小,所以low的选法可以有0-9999种,而low的选法正好=base10000。将high * base就是这种情况下1出现的次数。
- 当cur = 1时
cur = 1时 比如说310 1 592,需要分类讨论:
high从0 - 309时,low可以是0-999。所以是和cur = 0的情况一样的 => high * base
high是310时(1种选法),low只能是0 - 592(593种选法,是low + 1),low如果再大于592就比n要大了。 => 1 * (low + 1)
所以1的出现次数是(high * base) + (low + 1)
- 当cur > 1时
cur大于1时,不需要再去考虑high和low怎么选不会比n大了。比如3101 5 92,high可以从 0 - 3101 而 low 可以从 0 - 99,所以直接就是 (high + 1) * base。
class Solution { public: int NumberOf1Between1AndN_Solution(int n) { int base = 1; int cnt = 0; while(base <= n) { int high = n / (base * 10); int low = n % base; int cur = (n / base) % 10; if(cur == 0) { cnt += high * base; } else if(cur == 1) { cnt += (high * base) + (low + 1); } else { cnt += (high + 1) * base; } base *= 10; } return cnt; } };