这是我参与8月更文挑战的第21天,活动详情查看:8月更文挑战
剑指 Offer 43. 1~n 整数中 1 出现的次数
题目
输入一个整数 n
,求1~n这n个整数的十进制表示中1出现的次数。
例如,输入12,1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。
示例 1:
输入:n = 12
输出:5
示例 2:
输入:n = 13
输出:6
限制:
1 <= n < 2^31
方法一
计数问题:假设给定的数为abcdefg
-
当枚举到
c
时, -
如果
c=0
- c前面,我们可以选择的范围是
0~ab-1
,c后面可以选择的范围是0~9999
- c前面,我们可以选择的范围是
-
如果
c=1
- c前面,可以选择的范围是
0~ab-1
,c后面可以选择的范围是0~9999
;c前面还可以选择ab
,后面选择的范围是0~defg
- c前面,可以选择的范围是
-
如果
c>1
,前面可以选择的范围是0~ab
,后面范围是0~9999
根据上述规律,枚举每一位即可;
class Solution {
public int countDigitOne(int n) {
List<Integer> num = new ArrayList<>();
while(n != 0) {
num.add(n % 10);
n /= 10;
}
Collections.sort(num, (a, b)->{
return -1;
});
if (num.size() == 1) return 1;
int pre = 0, res = 0;
for (int i = 0; i < num.size(); i ++ ) {
int cur = num.get(i);
if (cur == 0) {
res += pre * Math.pow(10, num.size() - i - 1);
pre = pre * 10 + cur;
}
else if (cur == 1) {
int cnt = 0;
int j = i + 1;
while(j < num.size()) cnt = cnt * 10 + num.get(j ++);
res += pre * Math.pow(10, num.size() - i - 1) + cnt + 1;
pre = pre * 10 + cur;
}else {
res += (pre + 1) * Math.pow(10, num.size() - i - 1);
pre = pre * 10 + cur;
}
}
return res;
}
}
剑指 Offer 44. 数字序列中某一位的数字
题目
数字以0123456789101112131415…的格式序列化到一个字符序列中。在这个序列中,第5位(从下标0开始计数)是5,第13位是1,第19位是4,等等。
请写一个函数,求任意第n位对应的数字。
示例 1:
输入:n = 3
输出:3
示例 2:
输入:n = 11
输出:0
限制:
0 <= n < 2^31
方法一
数位分析:
-
找出第
n
个是几位数- 每次将
n
减去所有长度为digit
位数的长度,直到不够减
- 每次将
-
找出第
n
个是在digit
位数里的第几个数,即(n - 1) / digit
-
找出第
n
位是在digit
位数里的第几个数字,即(n - 1) % digit
class Solution {
public int findNthDigit(int n) {
long digit = 1, start = 1, count = 9;
while(n > count) {
n -= count;
digit += 1;
start *= 10;
count = 9 * digit * start;
}
long num = start + (n - 1) / digit;
String number = String.valueOf(num);
char[] res = number.toCharArray();
return res[(int)((n - 1) % digit)] - '0';
}
}