目录结构
1.题目
给定一个整数 n,计算所有小于等于 n 的非负整数中数字 1 出现的个数。
示例:
输入: 13
输出: 6
解释: 数字 1 出现在以下数字中: 1, 10, 11, 12, 13 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-digit-one
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2.题解
找规律,如下图所示:
- 纵向表示n有多少位数,假设以size表示;
- 横向表示最高位的数值,假设以high表示;
- 于是对于table[size][high]的数值表示1~high*10^(size-1)中1的个数;比如size=2, high = 1表示1~10中1的个数为2(即1和10包含的1);
- 注:数值为10时,表示1~10^size-1中1的个数。
对于一个数n,算法如下:
- 若当前最高位为high=1,位数为size,则结果加上10^(size-1)~n的1的个数n-10^(size-1) + 1+table[size-1][10](其中n-10^(size-1) 表示在该区间上最高位为1的个数,table[size-1][10]表示除去最高位后其余位1的个数);
- 否则,结果加上table[size][high],即加上1~high*10^(size-1)中1的个数;
- 然后n为移除n的最高位后的值
public class Solution233 {
@Test
public void test233() {
System.out.println(countDigitOne(199999));
}
long[][] table;
public Solution233() {
table = new long[11][11];
for (int i = 1; i < 11; i++) {
table[1][i] = 1;
}
int base = 10;
for (int i = 2; i < 11; i++) {
long val = table[i - 1][10];
for (int j = 1; j < 11; j++) {
if (j == 1) {
table[i][j] = val + 1;
} else if (j == 2) {
table[i][j] = base + 2 * val;
} else {
table[i][j] = table[i][j - 1] + val;
}
}
base *= 10;
}
}
public int countDigitOne(int n) {
int count = 0, i = String.valueOf(n).length(), base = (int) Math.pow(10, i - 1);
while (n > 0) {
int t = n / base;
if (t == 1) {
count += n - base + 1 + table[i - 1][10];
} else {
count += table[i][t];
}
i--;
n %= base;
base /= 10;
}
return count;
}
}
- 时间复杂度:
- 空间复杂度: