本题来自LeetCode:357. 计算各个位数不同的数字个数
题目详情
给定一个非负整数
n
,计算各位数字都不同的数字
x
的个数,其中
0≤x10^n
。
示例:
输入: 2
输出: 91
解释: 答案应为除去 11,22,33,44,55,66,77,88,99 外,在 [0,100) 区间内的所有数字。
分析思路
综上可得以下表达式:
count[n] = count[n -1] + A(10, n) * 9 / 10, 0 = n = 10
count[n] = count[10], 10 n
其中A(10, n)是从10个不同元素中取出n个元素的排列数
题目解答
根据以上分析可以轻松写出以下解答:
class Solution {
public int countNumbersWithUniqueDigits(int n) {
// count[n]记录区间[0, 10^n)的个数
int[] count = new int[11];
// n = 0时,区间为[0, 1)
count[0] = 1;
// n至多为10
for(int i = 1; i = Math.min(n, 10); i ++) {
// i位数的排列总数,即区间[10^(i - 1), 10 ^ i)
int arrangeWithI = arrangeWithN(i);
// i位数的累计排列数,即区间[0, 10 ^ i)
count[i] = count[i - 1] + arrangeWithI;
}
return n 10 ? count[10] : count[n];
}
private int arrangeWithN(int n) {
// 首位不能为0,故只剩123456789这九个数字
int arrange = 9;
int remainDigits = 9;
while(--n 0) {
arrange *= remainDigits;
remainDigits --;
}
return arrange;
}
}
进一步可以发现:
class Solution {
public int countNumbersWithUniqueDigits(int n) {
int sum = 1;
// 当前位数数字的排列数
// 初始值:1位数时的排列数
int currentArrange = 9;
// 剩余可选数字数
int remainDigits = 9;
// n至多为10
for(int i = 1; i = Math.min(n, 10); i ++) {
// i位数的累计排列数,即区间[0, 10 ^ i)
sum += currentArrange;
// (i + 1)位数的排列数,即区间[10^i, 10 ^ (i + 1))
currentArrange *= remainDigits;
// 可用数字数减一
remainDigits --;
}
return sum;
}
}
原文始发于微信公众号(xiaogan的技术博客):