题目:https://leetcode-cn.com/problems/count-numbers-with-unique-digits/submissions/
给定一个非负整数 n,计算各位数字都不同的数字 x 的个数,其中 0 ≤ x < 10^n 。
1. 首先想到的是暴力版本:从0开始遍历到 10^n,判断每个数字的每一位是否被重复,没有则计数+1; 显然这种方法遇到大量数据时,会超时。时间复杂度 O(10^n);
/**
* @param {number} n
* @return {number}
*/
var countNumbersWithUniqueDigits = function(n) {
let count=0;
const isRepeat = (numberStr)=>{
if(numberStr.length===1) return false;
for(let i=0; i
2. 回溯:所有的数据都是0-9的数字按不同的顺序组合而成。穷举所有可能的组合,检查组合是否为有效数据: 0 开头的只有0,不会是多位数据,数据是否小于10**n; 每遇到一个有效数据,计数器加1;
有效解的判定: 1. 不是以0开头的多位数,2. 数据小于10**n
每个节点的解空间: 0-9中所有没用过的数字
剪枝函数:数据大于等于10**n, 数据是以0开头的多位数
这种方法的时间复杂度是 O(9n)
/**
* @param {number} n
* @return {number}
*/
var countNumbersWithUniqueDigits = function(n) {
let count=-1;
backTrack = function(cur,dataSource){
if(Number(cur)>= 10 ** n || cur.indexOf("0")===0 && cur.length>1) return;
count++;
dataSource.forEach((data,index)=>{
backTrack(cur+data, dataSource.filter(number=>number!==data));
});
}
backTrack("",[0,1,2,3,4,5,6,7,8,9]);
return count;
};
据说还有一种算法:Dynamic Programming
1. 阶段划分:1 位数,2位数, 一直到n位数,逐渐增加位数。
2. 每个阶段的状态:i 位不重复的数字组合可能性为:9*(10-(i-1))*(10-(i-2))*(10-(i-3)) *(10-(i-(i-1))); 假设 Dp[i] 表示 i 位数的组合, Dp[i-1] 表示i-1 位数的组合。 那所有可能的组合就是:Dp[i] = 9*(10-(i-1))*(10-(i-2))*(10-(i-3)) *(10-(i-(i-1))) + Dp[i-1]
3. 初始状态:Dp[0] =1, Dp[1] = 10, Dp[2] = 9 *9 + 10=91;
/**
* @param {number} n
* @return {number}
*/
var countNumbersWithUniqueDigits = function(n) {
let result =1;;
for(let i=1;i<=n;i++){
let cur = 9;
for(let j=1;j