一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第11天,点击查看活动详情。
题目描述
给你一个整数 n ,统计并返回各位数字都不同的数字 x 的个数,其中 0 <= x < 10 。
示例
输入: n = 2
输出: 91
解释: 答案应为除去 11、22、33、44、55、66、77、88、99 外,在 0 ≤ x < 100 范围内的所有数字。
输入: n = 0
输出: 1
提示
0 <= n <= 8
数学
我们可以将数值n理解为一个数值的长度,该长度每增加一位,相当于我们新增多一层区间[0-9]的for循环,将其与前面的结果集进行拼接。
同时,由于题目要求的是统计各位数都不同的数字,那么数值新增的每一位,都需要与前面所有位数的数字不同,模拟代码如下所示:
public static void main(String[] args) {
for (int one = 0; one < 10; one++) {
for (int two = 0; two < 10; two++) {
if (two == one) {
continue;
}
for (int three = 0; three < 10; three++) {
if (three == one || three == two) {
continue;
}
for (int four = 0; four < 10; four++) {
if (four == one || four == two || four == three) {
continue;
}
for (int five = 0; five < 10; five++) {
if (five == one || five == two || five == three || five == four) {
continue;
}
for (int six = 0; six < 10; six++) {
if (six == one || six == two || six == three || six == four || six == five) {
continue;
}
for (int seven = 0; seven < 10; seven++) {
if (seven == one || seven == two || seven == three || seven == four || seven == five || seven == six) {
continue;
}
for (int eight = 0; eight < 10; eight++) {
if (eight == one || eight == two || eight == three || eight == four || eight == five || eight == six || eight == seven) {
continue;
}
System.out.println("" + one + two + three + four + five + six + seven + eight);
}
}
}
}
}
}
}
}
}
上面的代码太冗余了,有多个重复的步骤,我们可以以这个为基础,将重复的步骤抽离,优化。
例如:当n == 2的时候,我们新增的那些数字需要排除掉与n == 1时已有的数字,当n == 3的时候,我们新增的那些数字需要排除掉与n == 2时已有的数字,以此类推。
区间[0,9]有10个数字,每增加一位,我们计算的时候则相对的也要把需要排除的范围增加一位。
class Solution {
public int countNumbersWithUniqueDigits(int n) {
// 边界处理
if(0 == n){
return 1;
}
// n == 2时,需要去除的元素为9个,设基数为9
int count = 9, res = 10;
for(int i = 1; i < n; ++i){
// 基数 * 后续增加的范围数
count *= 10 - i;
// 结果累加
res += count;
}
return res;
}
}