计算数字k在0到n中的出现的次数,k可能是0~9的一个值

本文详细解析了一个算法问题:如何计算数字k在从1到n的所有整数中出现的次数。通过具体示例123中数字2的出现次数,文章阐述了解决方案的思路,包括如何确定当前位、高位和低位,以及基于这些位置的判断条件来计算总次数。代码实现使用C语言,提供了清晰的步骤说明。

转载文章:https://blog.youkuaiyun.com/doujinlong1/article/details/81366217

例如n=12,k=1,在 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],我们发现1出现了5次 (1, 10, 11, 12)
int countDigitOne(int n, int k) {
    if (n<10 &&k==0) {
        return 1;
    }
    int sum =0;
    int level = 1;
    while(n / level != 0){
        if (k == 0 && n / (level * 10) == 0) {// 最高位不能为0
            break;
        }
        int cur = (n/level) %10;//计算当前位
        int bef = n/(10*level);//计算当前位高位
        int aft = n - n/level *level;//计算当前位的低位
        if (cur >k) {
            sum += (bef+1)*level;
        }else if (cur <k) {
            sum += (bef)*level;
        }else{
            sum += (bef)*level +aft+1;
        }
        level*= 10;
    }
    return sum;
}

思路:

首先看这道算法题,计算出现的次数,我们可以看一个例子来理解这道题。

如123中出现的2的次数。

首先123中出现了多少次2,我们可以这么想,个位有多少个2,十位有多少个2,百位有多少2。

1,个位有多少2呢?因为3是大于2的,所以2 12 22 32 42…122一共有12 +1 个,我们可以想象,如果个位的3小于2,那么就只有12个了,最后一个12X上不会有。如果等于呢 则也是12+1。

2,十位有多少2呢? 因为2 ==2 ,所以 21 22 23 24 25…29 120 121 122,这里可以看出来加入十位大于2的时候,则会有 20个,如果小于2,则10个,如果等于,则是10 + 个位+1 (因为个位是2,而计数从0开始 ,如这里加的这个1是120这个)

这里我们可以进行总结:

如果 当前位大于k,则 (高位+1)乘 当前的计数级别(个位为1,十位为10,百位为百)

如果当前位小于k, 则 为高位 乘 当前的计数级别。

如果等于,则为 高位数 乘 当前计数级别 + 低位数+1。

这里我们可以进行总结:

如果 当前位大于k,则 (高位+1)乘 当前的计数级别(个位为1,十位为10,百位为百)

如果当前位小于k, 则 为高位 乘 当前的计数级别。

如果等于,则为 高位数 乘 当前计数级别 + 低位数+1。

这里的难点就只剩下怎么计算这个当前位,怎么计算当前位的高位,怎么计算当前位的低位。

例如123 ,如果要计算十位的高位,低位,当前位。

当前位:123/10(计数级别) %10(固定10) = 12%10 = 2

高位: 123/(10(固定10) * 10(计数级别))

低位: 123 - 123/10(计数级别)*10(计数级别) 

整理一下就是: 

        int cur = (n/level) %10;//计算当前位
        int bef = n/(10*level);//计算当前位高位
        int aft = n - n/level *level;//计算当前位的低位

注:感谢博主的分享  https://blog.youkuaiyun.com/doujinlong1/article/details/81366217

<think>根据引用[1]和[2]的描述,用户最初的需求是:输入正整数n和09范围内的一个数m,判断m是否存在于n中,若不存在则输出提示;若存在则删除n中的m构成新数k,然后计算n除以k的倍数(保留两位小数),并输出k和倍数。 但用户当前的问题已经改变:用户现在想要获取一个计算给定正整数n中数字m(m取范围为[0,9])出现次数的解决方案。 因此,我们需要调整方向,不再做删除数字构成新数并计算倍数的操作,而是计算数字m在正整数n中出现的次数。 思路: 1. 将正整数n当作一个字符串来处理,遍历字符串的每一位,判断每一位是否等于字符m(注意:m是09数字,需要将整数m转换为字符形式)。 2. 或者,通过数学方法,不断取n的每一位数字(通过除以10取余),然后与m比较,统计次数。 这里我采用第二种方法(数学方法): 步骤: a. 初始化计数器count=0 b. 循环条件:当n>0 c. 取当前最低位:digit = n % 10 d. 判断digit是否等于m,如果相等则count++ e. 然后将n除以10(整数除法)以去掉最低位:n = n / 10 f. 循环直到n为0 注意:当m为0时,需要特殊考虑吗? 实际上,上述方法对于0也是有效的,因为当n的某一位为0时,digit为0,与m(0)相等,计数器会增加。但是,如果n本身就是0,那么我们需要单独处理,因为0%10=0,然后0/10还是0,会陷入死循环?或者一次也不执行循环?因此,如果n为0,那么我们需要判断m是否为0,如果是,则出现1次,否则0次。 但是,题目要求n是正整数,所以n至少为1,因此不用考虑0的情况。 然而,题目中m的取范围是09,所以m可以是0,而n是正整数(不可能有前导0),所以我们在循环中处理0是没问题的。例如:n=102,m=0,则取最低位:2(不等于0),然后除以1010;再取0,等于0,计数加1;再除以101;再取1不等于0,结束。所以计数为1。 但是,还有一种特殊情况:当n=0时?题目要求正整数n,所以我们假设n>=1。但为了程序健壮性,如果用户输入0,我们可以按0处理。不过题目要求是正整数,所以我们可以不考虑0。 因此,我们按照步骤写一个函数,函数名为count_digit,参数为整数n和整数m(0<=m<=9),返回为m在n中出现的次数。 示例: 输入:n=112233, m=1 -> 返回2 输入:n=100, m=0 -> 返回2 代码实现(C语言): 注意:由于题目要求是正整数,所以n>0,因此我们可以直接使用循环。 函数定义: int count_digit(int n, int m) { int count = 0; if (n == 0) { // 虽然题目要求正整数,但为了健壮性,考虑n=0的情况 return m == 0 ? 1 : 0; } while (n > 0) { int digit = n % 10; if (digit == m) { count++; } n /= 10; } return count; } 但是,题目要求是正整数,所以n>0,那么我们可以省略n=0判断。 然而,如果n是0,而题目要求正整数,所以我们可以不考虑。但如果用户输入0,那么我们可以按照要求(正整数)拒绝,但题目没有要求处理输入错误,所以我们假设输入是正整数。 因此,我们可以简化为: int count_digit(int n, int m) { int count = 0; while (n != 0) { int digit = n % 10; if (digit == m) { count++; } n = n / 10; } return count; } 但是注意:这样写的话,如果n是0,循环不会执行,返回0。而实际上,如果n=0,m=0,应该返回1,但题目要求正整数,所以n不会为0,所以这样写没问题。 但是,如果用户输入的n就是0(虽然题目要求正整数,但用户可能输入0),我们可以按照引用[1][2]中的描述,要求输入正整数。不过现在用户只是要求计算出现次数,我们可以先按上述函数实现。 然而,用户并没有要求写完整程序,而是要求一个解决方案。我们可以描述这个算法,并给出代码示例。 另外,引用[3]中给出了一个计算一个数能被另一个数整除的个数的方法,但这个问题和我们现在的问题不同,所以仅作参考。 引用[4]中的代码是关于猜数字和乘方计算的,与当前问题无关。 综上所述,我们按照第二种方法(数学方法)来给出解决方案。 但是,用户可能要求多种语言的实现?但问题中没有明确,这里按照最常见的C语言实现。 如果用户需要其他语言,可以后续补充。 因此,我们可以这样回答: 要计算正整数n中数字m(0~9)出现的次数,可以使用循环取出n的每一位数字,并与m进行比较,然后计数。具体步骤如下: 1. 初始化计数器count为0。 2. 当n不为0时循环: a. 取n的个位数字(用n % 10得到)。 b. 如果该数字等于m,则计数器count加1。 c. 将n整除10(即n = n / 10),以去掉个位数字。 3. 循环结束后,count即为m在n中出现的次数。 注意:由于n是正整数,循环会在n变为0时终止。 以下是一个C语言函数实现: ```c #include <stdio.h> int count_digit(int n, int m) { int count = 0; while (n != 0) { int digit = n % 10; if (digit == m) { count++; } n = n / 10; } return count; } int main() { int n, m; printf("请输入正整数n: "); scanf("%d", &n); printf("请输入0~9数字m: "); scanf("%d", &m); int count = count_digit(n, m); printf("数字%d在正整数%d中出现了%d次。\n", m, n, count); return 0; } ``` 但是,用户可能要求不能使用循环(比如递归),或者要求处理大整数(超出int范围)?但根据引用中的描述,输入是正整数,且没有特别说明范围,我们假设在int范围内。 如果n非常大(比如超出long long范围),那么我们可以用字符串处理(如思路1),但是题目没有要求,所以我们给出常规方法。 另外,如果用户要求使用递归,我们可以提供一个递归版本: 递归函数: int count_digit_recursive(int n, int m) { if (n == 0) { return 0; } int digit = n % 10; int count = (digit == m) ? 1 : 0; return count + count_digit_recursive(n / 10, m); } 但是,递归深度与n的位数有关,对于较大的n可能会导致栈溢出,所以循环更安全。 根据用户需求,我们提供循环版本。 最后,生成相关问题: 1. 如何计算一个正整数中所有数字0~9)各自出现的次数? 2. 如何计算一个正整数中某个数字出现的次数(不使用循环)? 3. 如何统计一个字符串中某个字符出现的次数? 4. 如何处理大整数(超过long long范围)中数字出现的次数? 注意:引用中的原始问题(删除数字构成新数并计算倍数)和当前问题不同,但用户已经转向了新的问题。 因此,回答完毕。 </think>### 计算数字出现次数的方法 要计算正整数 \(n\) 中数字 \(m\)(\(m \in [0,9]\))的出现次数,可采用以下两种常用方法: #### 方法一:数学取模法(推荐) 1. **初始化计数器**:`count = 0` 2. **循环处理**: - 取 \(n\) 的最低位:\(digit = n \% 10\) - 若 \(digit == m\),则计数器加 1 - 去掉最低位:\(n = n / 10\)(整数除法) 3. **终止条件**:当 \(n = 0\) 时结束 4. **时间复杂度**:\(O(\log_{10} n)\) ```c #include <stdio.h> int count_digit(int n, int m) { int count = 0; while (n > 0) { if (n % 10 == m) count++; // 比较最低位 n /= 10; // 移除最低位 } return count; } int main() { int n = 202405; int m = 0; printf("出现次数:%d\n", count_digit(n, m)); // 输出:2 return 0; } ``` #### 方法二:字符串转换法 1. 将整数 \(n\) 转换为字符串 2. 遍历字符串的每个字符 3. 若字符等于 \(m + &#39;0&#39;\)(ASCII 转换),则计数器加 1 ```c #include <stdio.h> #include <string.h> int count_digit_str(int n, int m) { char str[20]; sprintf(str, "%d", n); // 数字转字符串 int count = 0; for (int i = 0; i < strlen(str); i++) { if (str[i] == m + &#39;0&#39;) count++; // 比较字符 } return count; } ``` ### 关键说明 1. **特殊情况处理**: - 若 \(n = 0\) 且 \(m = 0\),直接返回 1 - \(m\) 必须在 [0,9] 范围内 2. **示例验证**: - \(n = 1050, m = 0\) → 出现 2 次(方法一输出) - \(n = 999, m = 9\) → 出现 3 次(方法二输出) ### 相关问题 1. 如何优化大整数(超过 `long long` 范围)的数字统计? 2. 递归实现数字统计的方法是什么? 3. 如何统计十进制数中所有数字0-9)的出现频率? 4. 若需排除前导零(如 00123),应如何修改算法? [^1]: 输入正整数和数字进行判断和操作的规范说明 [^2]: 数字存在性检查及后续处理流程 [^3]: 整数除法与计数机制的数学原理 [^4]: C语言基础操作参考
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值