一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情。
357. 统计各位数字都不同的数字个数
题目描述
给你一个整数
n,统计并返回各位数字都不同的数字x的个数,其中0 <= x < 10^n。
示例
示例一:
输入:n = 2
输出:91
解释:答案应为除去 11、22、33、44、55、66、77、88、99 外,在 0 ≤ x < 100 范围内的所有数字。
示例二:
输入:n = 0
输出:1
提示
0 <= n <= 8
题解
方法一
表哥我出来了喔~~(狗头.jpg)
public int countNumbersWithUniqueDigits(int n) {
switch (n) {
case 0:
return 1;
case 1:
return 10;
case 2:
return 91;
case 3:
return 739;
case 4:
return 5275;
case 5:
return 32491;
case 6:
return 168571;
case 7:
return 712891;
case 8:
return 2345851;
default:
return 0;
}
}
方法二
首先第一步,读懂题目,题目要求传入一个数字 n,返回从 0 到 10^n 之间(大于等于0,小于 10^n )各位数字都不同的数字个数。
例如输入 2,则返回 0 到 100 之间(大于等于 0,小于 100 )各位数字都不同的数字个数,需要排除 11,22,33,44,55,66,77,88,99。所以输入 2,返回91。
思路:
输入 0 时,数字有[0],则返回答案为 1
输入 1 时,数字有[0,1,2,3,4,5,6,7,8,9],则返回答案为 10
输入 2 时,这时候数字区间是 [0, 100),那么要一个个排列出来就很困难了,而到了后面就更不现实,所以就需要开始找规律了,已经知道 0 到 9 都是一位数,那么就从两位数开始,由于 0 不能作为第一位数,所以第一位数的就只能是 1~9。
当第一位数是 1 时,第二位数可以是:[0,2,3,4,5,6,7,8,9]
当第一位数是 2 时,第二位数可以是:[0,1,3,4,5,6,7,8,9]
当第一位数是 3 时,第二位数可以是:[0,1,2,4,5,6,7,8,9]
依次类推,可以发现,当第一位数字不一样时,第二位数字分别都有 9 种,那么从 10~99一共就有 9 * 9 = 81 个,然后再加上 0~9 的 10 个,就是:10 + 9 * 9 = 91
输入 3 时,这时候数字区间是 [0, 1000),同样的 0~99 的答案是 91,那么就直接从三位数开始就可以了。
当第一位数是 1 时,第二位数是 2 时,第三位数可以是:[0,3,4,5,6,7,8,9]
当第一位数是 1 时,第二位数是 3 时,第三位数可以是:[0,2,4,5,6,7,8,9]
当第一位数是 1 时,第二位数是 4 时,第三位数可以是:[0,2,3,5,6,7,8,9]
依次类推,可以发现,当第一位数是 0~9 时,第二位数有 9 种不同的选择,而当第一位和第二位确定后第三位数就只有 8 种不同的选择,这样就可以得出在三位数中一共有 9 * 9 * 8个,然后再加上 0~ 99 的 91 个,就是 91 + 9 * 9 * 8,也就是10 + 9 * 9 + 9 * 9 * 8。
这样的话当 n = 4 时,答案为:10 + 9 * 9 + 9 * 9 * 8 + 9 * 9 * 8 * 7
整体规律:
n = 2:10 + 9 * 9 = 91
n = 3:10 + 9 * 9 + 9 * 9 * 8
n = 4:10 + 9 * 9 + 9 * 9 * 8 + 9 * 9 * 8 * 7
……
所以基于以上规律,可得到如下代码:
public int countNumbersWithUniqueDigits(int n) {
// 当n=0和1时,直接返回
if (n == 0) {
return 1;
}
if (n == 1) {
return 10;
}
int cur = 9;
int res = 10;
for (int i = 0; i < n - 1; i++) {
cur *= 9 - i;
res += cur;
}
return res;
}
代码详解:
cur 默认赋值 9,用于计算每一次递减的乘积,当循环时 i 递增,则 9 - i 就依次递减,然后与 cur 相乘得到每一轮的结果,最后将每一轮得到的 cur 加到 res,res 默认赋值 10,表示 n = 1 的答案为 10,再依次相加。