📜  在(N!)N中查找位数(1)

📅  最后修改于: 2023-12-03 15:07:51.648000             🧑  作者: Mango

在(N!)N中查找位数

题目描述:

给定一个数字 N,求 N!(N 的阶乘)中某一位数字出现的次数。

例如: N = 11, 某一位数字为 1,则该数字在 N! 中出现的次数为 4。

具体解释如下:

N! = 11! = 39916800,其中数字 1 在个位、十位和百位上均各出现一次,所以该数字在 N! 中出现的次数为 4。

解题思路:

我们可以将该题目分成两个子问题:

1.求N!的值

2.求数字在N!中出现的次数

对于第一个子问题,可以使用递归的思想进行求解,即

N!=N*(N-1)!

其递归终止条件为 N = 1 或 N = 0,此时 N! 的值为 1。

对于第二个子问题,我们可以将 N! 中所有的数字拆分成个位、十位、百位等等的位置,然后再统计数字在各位出现的次数即可。

具体实现如下:

int countDigitOne(int n) {
    int res = 0;
    for (long long i = 1; i <= n; i *= 10) { // i表示位数上的值,个位为1,十位为10,百位为100...
        int divider = i * 10; // divider表示下一个位数的值
        res += (n / divider) * i + min(max(n % divider - i + 1, 0LL), i); // 核心代码,分三部分进行解析
    }
    return res;
}

代码解析:

1.首先我们定义变量 i,表示当前处理的位数值。从个位开始,依次处理到最高位。

2.然后我们定义变量 divider,表示下一个处理的位数值。

3.接下来就是核心代码部分,分为三部分进行解析:

3.1. (n / divider) * i:表示当前位数上数字在所有可能的数字当中一共出现的次数,例如对于个位数字 1 来说,其出现次数为 (n / 10) * 1。

3.2. n % divider - i + 1:表示当前位数上可能的第一个数字,例如对于个位数字 1 来说,其可能的第一个数字为 1,即 n % 10 - 1 + 1 = n % 10。

3.3. min(max(n % divider - i + 1, 0LL), i):表示当前位数上数字在可能的数字中实际出现的次数,我们需要将其限制在 [1, i] 的范围内,因为数字最多只能出现 i 次。

4.最后返回 res 即可。

代码时间复杂度:O(logn),空间复杂度:O(1)。

参考资料:

[1] 力扣(LeetCode)原题链接