LeetCode Number of Digit One(计算1的个数)

本文介绍了一种高效算法,用于计算从0到给定整数n范围内所有数字中数字1出现的总次数。该算法通过巧妙地划分数字区间,并利用数学规律简化计算过程。

题意:给出一个整数n,求从0到n之间的数中出现1的总个数

思路: 根据   high cur low(其中cur是1位),而number表示cur当前的位数(1,10,100,。。。)

当cur=0时,则有high * number

当cur =1时,则有high * number + (low + 1)

当cur>1时,则有(high+1) * number

代码如下:

public class Solution
{
    public int countDigitOne(int n)
    {
        int sum = 0;
        for (long m = 1; m <= n; m *= 10)
        {
            long a = n / m, b = n % m;
            sum += (a + 8) / 10 * m + (a % 10 == 1 ? 1 : 0) * (b + 1);
        }

        return sum;
    }
}


<think> 首先,用户要求使用C++实现一个程序:输入一个整数n,输出从1到n中字符'1'出现的次数。这里的"字符1"指的是数字字符'1',不是数字1。例如,在数字序列中,遇到像10、1112等数字时,统计这些数字字符串中字符'1'的出现次数。 用户引用了几个引用,但内容是关于其他C++程序的,比如字符串处理、数字字符提取等。我应该专注于用户当前的问题。 回顾系统级指令: - 所有行内数学表达式使用$...$。 - 独立公式使用$$...$$并单独成段。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识。 - 回答结构清晰,逐步解决问题。 用户的问题是:实现一个程序,输入整数n,输出1到n中字符'1'出现的总个数。 关键点: - 输入:一个整数n。 - 输出:从1到n(包括n)的所有数字中,字符'1'出现的总次数。 - 例如,如果n=11,数字包括1,2,3,...,11。字符'1'出现的位置:数字1有一个'1',数字10有一个'1',数字11有两个'1',总计4次。 算法思路: - 最简单的方法是枚举每个数字从1到n,转换成字符串,然后遍历字符串统计字符'1'的个数,最后累加。 - 但n可能很大,例如n=1000000,枚举每个数字可能会效率较低。需要优化。 - 一个优化的方法是使用数学公式来计算总次数,而不需要枚举每个数字。这涉及到数位DP或组合数学。 对于输出字符'1'出现的个数,一个高效的算法是考虑每个位上的贡献。 参考LeetCode上的类似问题:233. Number of Digit One。 标准方法是计算每个位(个位、十位、百位等)上1出现的次数。 公式推导: - 对于一个给定的位(比如第k位,从右向左,0-based),该位上的1出现的次数可以由n决定。 - 设当前位为10^k,数字n可以表示为abc...def,其中d是当前位。 - 当前位1出现的次数取决于当前位左边的数字(higher)和右边的数字(lower),以及当前位的值。 具体公式: - 设当前位为第k位(k从0开始,个位是k=0)。 - 令 factor = 10^k - 令 higher = n / (10^{k+1}) // 当前位左边的数字 - 令 lower = n % (10^k) // 当前位右边的数字 - 令 digit = (n / (10^k)) % 10 // 当前位的数字值 那么,第k位上1出现的次数为: - 如果 digit < 1: - higher * factor - 如果 digit == 1: - higher * factor + lower + 1 - 如果 digit > 1: - (higher + 1) * factor 然后,对每个位k求和,直到 factor <= n。 在代码实现中,可以迭代k从0开始,factor = 1, 10, 100, ... 直到 factor > n。 例如,n=12: - k=0 (个位): - factor = 1 - higher = 12 / 10 = 1 - digit = (12 / 1) % 10 = 2 - 由于 digit > 1, count = (1 + 1) * 1 = 2 - k=1 (十位): - factor = 10 - higher = 12 / 100 = 0 - digit = (12 / 10) % 10 = 1 - 由于 digit == 1, count = 0 * 10 + (12 % 10) + 1 = 0 + 2 + 1 = 3 - 总计数 = 2 + 3 = 5? 但实际数字112: 数字1:1个'1' 数字2-9:0个 数字10:1个'1' 数字11:2个'1' 数字12:1个'1' 总计:1+1+2+1=5? 11有两次'1',所以1:1,10:1,11:2,12:1,总计5次。是的,正确。n=12,从1开始,包括12。 另一个例子:n=11 - k=0: - factor=1 - higher=11/10=1 - digit=1 % 10? (11/1)%10=11%10=1? 等待:(n / factor) % 10 - n=11, factor=1, digit=(11/1)%10=11%10=1 - 由于 digit==1, count=higher*factor + lower + 1 - lower=n%factor=11%1=0? 实际上,factor=1时,lower=n%1=0 - higher=11/10=1 (整数除法) - count=1*1 + 0 + 1 = 2 - k=1: - factor=10 - higher=11/100=0 - digit=(11/10)%10=1%10=1? 11/10=1, 1%10=1 digit=1 lower=n%factor=11%10=1 count=0*10 +1 +1=2 - total=2+2=4, 正确:1:1,10:1,11:2,总计4。 代码实现: - 初始化count = 0 - k从0开始,factor=1; while factor <= n: - higher = n / (factor * 10) // integer division - lower = n % factor - digit = (n / factor) % 10 - if digit < 1: count += higher * factor - else if digit == 1: count += higher * factor + lower + 1 - else: count += (higher + 1) * factor - factor *= 10 在C++中实现。 用户要求输出程序代码。 结构回答: 1. 解释问题和算法思路。 2. 给出C++代码。 3. 添加相关问题。 使用中文回答。 生成相关问题。 引用:用户提供了引用,但它们似乎不直接相关: - 引用[1]:关于字符串中字符计数。 - 引用[2]:提取数字字符并转换。 - 引用[3]:打印图形。 我可以忽略这些,因为用户说“上述引用仅供参考”,并专注于当前问题。 回答结构: - 介绍问题。 - 解释高效算法(数学方法)。 - 给出C++代码实现。 - 测试示例。 - 生成相关问题。 代码使用标准C++,输入输出。 确保LaTeX正确: - 行内数学表达式用$...$,如$10^k$。 - 独立公式用$$...$$,如果需要。 独立公式: $$ \text{count} = \sum_{k=0}^{\lfloor \log_{10} n \rfloor} \text{digitCount}(k, n) $$ 其中digitCount如上所述。 在实际代码中直接用循环。 </think> ### 问题分析与解法说明 用户要求使用C++实现一个程序:输入一个整数$n$($n \geq 1$),输出从1到$n$的所有整数中,数字字符'1'出现的总次数。例如: - 当$n=11$时,数字序列为1,2,...,11:数字"1"有1个'1',数字"10"有1个'1',数字"11"有2个'1',总次数为4。 - 解决方法包括遍历每个数字并统计'1'的出现次数,但当$n$较大时(如$n=10^6$),直接遍历效率较低。推荐使用数学优化方法,基于每个数位(个位、十位等)的贡献计算,时间复杂度为$O(\log_{10} n)$。 #### 数学原理概述 设当前位为第$k$位($k$从0开始,个位为$k=0$): - 定义$factor = 10^k$(位权)。 - 计算高位部分$higher = n / (10^{k+1})$(整数除法)。 - 计算低位部分$lower = n \mod 10^k$。 - 计算当前位数字$digit = (n / 10^k) \mod 10$。 第$k$位上'1'出现的次数为: - 若 $digit < 1$: $count_k = higher \times factor$ - 若 $digit = 1$: $count_k = higher \times factor + lower + 1$ - 若 $digit > 1$: $count_k = (higher + 1) \times factor$ 总次数为所有$k$位的次数和:$\sum_{k=0}^{\lfloor \log_{10} n \rfloor} count_k$,直到 $factor > n$。这种方法避免了数字到字符串的转换,高效可靠[^1]。 ### C++代码实现 ```cpp #include <iostream> using namespace std; int main() { int n; cout << "请输入整数 n: "; cin >> n; // 输入整数n long long count = 0; // 初始化计数器,使用long long防止溢出 long long factor = 1; // 位权因子,初始为1 (10^0) while (factor <= n) { // 计算高位、低位和当前位 long long higher = n / (factor * 10); long long lower = n % factor; int digit = (n / factor) % 10; // 根据当前位值计算贡献 if (digit < 1) { count += higher * factor; } else if (digit == 1) { count += higher * factor + lower + 1; } else { count += (higher + 1) * factor; } factor *= 10; // 更新到下一位:个位 → 十位 → 百位... } cout << "1 到 " << n << " 中字符 '1' 出现的个数为: " << count << endl; return 0; } ``` #### 代码说明与测试用例 - **输入示例**:输入`n=11`,输出`4`(正确:数字110、11贡献1+1+2)。 - **输入示例**:输入`n=12`,输出`5`(正确:数字110、1112贡献1+1+2+1)。 - **特点**: - 时间复杂度 $O(\log_{10} n)$,高效处理大$n$(如 $n=10^6$)。 - 使用`long long`防止整数溢出。 - 直接数学计算,避免字符串转换开销。 #### 编译与运行 - 编译命令:`g++ -o count_ones count_ones.cpp`(假设文件名保存为`count_ones.cpp`)。 - 运行:`./count_ones`,按提示输入$n$。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

kgduu

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

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

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

打赏作者

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

抵扣说明:

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

余额充值