LeetCode每日一题

计算各个位数不同的数字个数(357题)

难度:中等 (编程新手,共同学习)

题目描述

给定一个非负整数 n,计算各位数字都不同的数字 x 的个数,其中 0 ≤ x < 10^n 。

示例分析

示例

输入: 2
输出: 91
解释: 答案应为除去 11,22,33,44,55,66,77,88,99 外,在 [0,100) 区间内的所有数字。

也应该注意到:如果一个数字位数大于等于3,只要前面的某几位有重复数字,我们都应该把他们排除掉。

代码思路(动态规划dp):

方法一:计算n位数字重复的个数

因为是非负整数,所以我们要考虑0的情况。当位数为0时,默认不重复个数是1。
接下来先定义一个数组dp[n+1],其中每一个存放对应位数n的重复数字个数,n+1是因为要预留一个位置位dp[0].
⭐当n=0和n=1时,重复个数都为0.所以dp[0]=0、dp[1]=0.

如果已经知道n位的结果,如何获得n+1位的结果呢,可以这样考虑。
对于n位的数字重复有两种可能:
①前边的n-1位已经有了重复,那么最后一位0-9都可以。
②前边的n-1位数字是没有重复的,那么最后一位可以是这n-1位数字中的任何一位。

对于①情况的重复个数就是dp[i-1] * 10;
对于②情况的重复个数就是{9*[10^(i-2)] - dp[i-1]} * (i-1)
②中公式说明: 其中9*[10^ (i-2)] 是前n-1位所有的情况(包括重复和不重复的全部),dp[i-1]是前n-1位重复的,所以9*[10^(i-2)] - dp[i-1]就是②中的前半句情况。因为前面有i-1个不相同的数字,所以我们最后乘以i-1就是②中的后半句情况。

最后我们把dp数组中个数相加得到全部的重复个数sum,用位数为n的总个数10^n减去sum即可。

 int countNumbersWithUniqueDigits(int n) {
        if(n == 0) return 1;
        int dp[n+1];
        dp[0] = 0; dp[1] = 0;
        for(int i = 2;i <= n;i++){
            dp[i] = dp[i-1]*10 + (9 * pow(10,i-2) - dp[i-1]) * (i-1);
        }
        int sum = 0;
        for(int i = 0;i <= n;i++){
            sum+=dp[i];
        }
        return pow(10,n) - sum;
    }

方法二: 直接计算不重复的个数

我们还要建立一个数组dp[i],但此时dp[i]表示增加长度为i位的数字一共有多少不同的数。
转移矩阵:
dp[i] = dp[i - 1] * (10 - (i - 1))
新增第i位时,长度为i位的所有数字不同的个数 = 长度为i-1位所有数字不同的个数* 剩余可供选择的个数;

 int countNumbersWithUniqueDigits(int n) {
        if(n == 0){
            return 1;
        }

        if(n == 1){
            return 10;
        }

        vector<int> dp = vector<int>(n + 1, 0);
        dp[0] = 1;
        dp[1] = 9;
        int sum = dp[0] + dp[1];
        for (int i = 2; i <= min(n, 10);i++){
            dp[i] = dp[i - 1] * (10 - (i - 1));
            sum += dp[i];
        }

        return sum;

说明

本博客是为记录LeetCode的点点滴滴,有些方法借鉴于其他作者,方便以后查看,如有侵权,烦请告知。

题目来源:力扣(LeetCode)
题目链接:https://leetcode-cn.com/problems/count-numbers-with-unique-digits/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AILcy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值