方法一:
抛开前导零考虑,只要0不是首位,则0与其他数字无异,
所以通过数字长度划分每种情况:
长度为1,第一位可以取0~10,共10种。
长度为2,必须为两位数,则第一位可以取1~9,第二位可以取剩下9种(这时可以取0),9*9共81种。
长度为3,9*9*8。
以此类推。
最后求和即可。
class Solution {
public:
int countNumbersWithUniqueDigits(int n) {
if(n==0) return 1;
int ans = 10;
int now = 9;
int key = 9;
for(int i = 1;i<n;i++){
now *= key;
ans += now;
key --;
}
return ans;
}
};
方法二:
状态转移思路:比较麻烦,通过n位数量来求出n+1位的数量。
如图,每个树分支上权值乘积,再分支求和即是答案。
简单说说这颗二叉树是如何构造的,
靠上的权值是当前位可以取1~9中数的个数,
靠下的权值是当前位取0的个数,
如果出现中间0,则之后不可再分裂。
class Solution {
public:
// n所求树高,level当前树层数,now当前树节点值,flag是否会出现中间0
int dfs(const int n,int level,int now,bool flag){
if(level == n) return now;
if(flag){
int sum = 1;
int key = now;
for(int i=level;i<n;i++){
sum *= key;
key--;
}
return sum + now*dfs(n,level+1,now-1,true);
}
return dfs(n,level+1,9,true) + dfs(n,level+1,1,false);
}
int countNumbersWithUniqueDigits(int n) {
return dfs(n,0,1,false);
}
};