357. 计算各个位数不同的数字个数

给定一个非负整数 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;
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值