计数问题
- 问题背景
- 分析,通过
count(int n, int x)来算出1 ~ n中出现了多少次x,x从0取到9
-
对于七位数
n = a b c d e f g,其中a ~ g为n上的每一位数,现在我要计算d这个位置上出现了几次x- 情况1:当
a b c取0 0 0 ~ a b c-1时,这时候d这个位置上的x出现了abc * 1000次 - 情况2:当
a b c取a b c时- 情况2.1:若
d < x,这时候d这个位置上的x出现了0次 - 情况2.2:若
d = x,这时候d这个位置上的x出现了efg + 1次 - 情况2.3:若
d > x,这时候d这个位置上的x出现了1000次
- 情况2.1:若
- 注意,如果
x取的是0,那么情况1中的a b c就只能从0 0 1 ~ a b c-1中取,因此这种情况还要减去1000次
- 情况1:当
-
上面只是例举了
count(int n, int x)中的一个情况,下面进行抽象描述整个计算的过程,计算1 ~ n中一共出现了多少次x- 长度为
size容器num中从小到大存放着n的每一位数字,即num[0]存放个位,num[size-1]存放最高位 ;res存计算结果,即1 ~ n中一共出现了多少次x - 定义
get(vector<int> num,int l,int r),获取num中区间[l, r]表示的数,例如n = a b c d e f g,get(num, 4, 6) = efg - 定义
power10(int i),返回10^i^ - 循环从最高位
i = size - 1 - !x开始,i >= 0,每次i--。为什么要减去!x?如果x取0,意味着计算最高位出现0的次数,显然最高位不可能出现0,因此减去了!x防止这种情况的发生- 情况1:
res += get(num, i + 1, size - 1) * power10(i); - 注意点:
if (x == 0) {res -= power10(i)} - 情况2.1:可以省略
- 情况2.2:
if (num[i] == x) {res += get(num, 0, i - 1) + 1}; - 情况2.3:
else if (num[i] > x) {res += power10(i)}
- 情况1:
return res;
- 长度为
-
代码
-
public static int count(int n, int x) { ArrayList<Integer> num = new ArrayList<>(); while (n != 0) { num.add(n % 10); n /= 10; } n = num.size(); int res = 0; for (int i = n - 1 - (x == 0 ? 1 : 0); i >= 0; i--) { //情况1 res += get(num, i + 1, n - 1) * Math.pow(10, i); //注意点 if (x == 0) { res -= Math.pow(10, i); } //情况2.2 if (num.get(i) == x) { res += get(num, 0, i - 1) + 1; } else if (num.get(i) > x) { //情况2.3 res += Math.pow(10, i); } } return res; }
-
练习
01 计数问题
- 题目
- 题解
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
while (true) {
String[] str1 = br.readLine().split(" ");
int a = Integer.parseInt(str1[0]);
int b = Integer.parseInt(str1[1]);
if (a == 0 && b == 0) {
break;
}
if (a > b) {
int t = a;
a = b;
b = t;
}
for (int i = 0; i < 10; i++) {
//区间和
pw.print(count(b, i) - count(a - 1, i) + " ");
}
pw.println();
}
pw.close();
br.close();
}
public static int count(int n, int x) {
ArrayList<Integer> num = new ArrayList<>();
while (n != 0) {
num.add(n % 10);
n /= 10;
}
n = num.size();
int res = 0;
for (int i = n - 1 - (x == 0 ? 1 : 0); i >= 0; i--) {
//情况1
res += get(num, i + 1, n - 1) * Math.pow(10, i);
//注意点
if (x == 0) {
res -= Math.pow(10, i);
}
//情况2.2
if (num.get(i) == x) {
res += get(num, 0, i - 1) + 1;
} else if (num.get(i) > x) { //情况2.3
res += Math.pow(10, i);
}
}
return res;
}
//获取num中区间[l, r]表示的数,例如 n = a b c d e f g get(num, 4, 6) = efg
public static int get(ArrayList<Integer> num, int l, int r) {
int x = 0;
for (int i = r; i >= l; i--) {
x = x * 10 + num.get(i);
}
return x;
}
}