给定一个非负整数 n,计算各位数字都不同的数字 x 的个数,其中 0 ≤ x < 10^n
https://leetcode-cn.com/problems/count-numbers-with-unique-digits/
//1.动态规划法,对于i位数字的数来说,如果前i-1位有重复,那么第i位(最低位)放0-9都会重复,得到重复数字dp[i - 1] * 10个;
//如果前i-1位没有重复,共有9 * 10 ^ (i - 2) - dp[i - 1]种可能,这时第i位放前i-1位中数字的一个就会重复,
//所以dp[i] = dp[i - 1] * 10 + 9 * 10 ^ (i - 2) - dp[i - 1].
//对于0 ≤ x < 10^n,x包含重复数字的情况为dp数组元素之和
public int countNumbersWithUniqueDigits1(int n){
if (n == 0){
return 1;
}
int[] dp = new int[n + 1];
int sum = 0;
dp[0] = 0;
dp[1] = 0; //1位数字无重复
for (int i = 2; i <= n; i++){
dp[i] = dp[i - 1] * 10 + (9 * (int)Math.pow(10,i - 2) - dp[i - 1]) * (i - 1);
sum += dp[i];
}
return (int)Math.pow(10, n) - sum;
}
//2.回溯法
int count = 0; //记录不重复数字数的个数
public int countNumbersWithUniqueDigits(int n) {
int[] arr = new int[n];
put(arr,0,n);
return count;
}
//放入第cur个数
public void put(int[] arr, int cur, int n){
//如果cur = n,说明得到了一个没有重复数字的数
if (cur == n){
count++;
return;
}
//从0到10依次放到arr[cur]里,如果arr[cur]无论放什么都重复(本题不可能),就结束了这个循环,返回到调用它的函数,
// 即放cur - 1个数的函数,修改arr[cur - 1]
for (int i = 0; i < 10; i++){
arr[cur] = i;
//如果没有重复,就继续放第cur+1个数字,如果有重复,就换下一个数字
if (check(arr,cur)){
put(arr,cur + 1, n);
}
}
}
//检查当前放入的数字是否有重复
public boolean check(int[] arr, int high){
int index = 0;
//忽略数组最前面的0
while (index < high && arr[index] == 0){
index ++;
}
for (int i = index; i < high; i++){
//若和前面的数字有重复,就返回false
if (arr[i] == arr[high]){
return false;
}
}
//走到这里说明没有重复,返回true
return true;
}