2026-07-08:统计区间内奇妙数的数目。用go语言,给定一个正整数 n,我们要考虑从 1 到 n 之间(包括 1 和 n)的所有整数。对每个数,按
🤖 AI总结
主题
使用数学公式高效计算1到n间所有数字千位分隔符逗号的总数
摘要
本文通过数学公式推导,实现O(1)时间复杂度计算1到n所有数字千位分隔符逗号的总数,并提供多语言代码示例。
关键信息
- 1 利用千位分段数学公式直接计算逗号数量
- 2 时间复杂度O(1),避免暴力遍历
- 3 提供Go、Python、C++完整代码实现
2026-07-08:统计区间内奇妙数的数目。用go语言,给定一个正整数 n,我们要考虑从 1 到 n 之间(包括 1 和 n)的所有整数。对每个数,按照常见的千位分隔习惯写成字符串:从个位开始向左数,每三位插入一个逗号,但如果这个数不足四位(也就是小于 1000),则不加任何逗号。问题是:把 1 到 n 这 n 个数的这种书写形式连起来看,总共出现了多少个逗号?请计算出这个总数。
1 <= n <= 100000。
输入: n = 1002。
输出: 3。
解释:
数字 “1,000”、”1,001″ 和 “1,002” 每个都包含一个逗号,总计 3 个逗号。
题目来自力扣3870,3871。
一、函数 countCommas(n int64) 分步逻辑拆解 步骤1:定义变量k,k代表每个数字固定拥有的逗号个数档位
k 是完整千位段的数量,对应数字统一携带的逗号数量:
• 数字区间 [10^(3 m), 10^(3 m+3)-1] 内所有数,都固定有 m 个逗号
m=0:1 999,k=0,无逗号
m=1:1000 999999,k=1,1个逗号
m=2:1000000~999999999,k=2,2个逗号
以此类推
步骤2:计算k的核心逻辑 2.1 特殊边界说明
当 n = 10^15 时,浮点数 math.Log10 会存在精度丢失,无法正确算出位数,因此代码预设兜底 k=5;题目限制 n≤100000,不会触发该特判,仅为超大数兼容。
2.2 常规n<1e15时的k计算流程
1. 将整数n转为浮点数,调用 math.Log10 得到n的十进制位数减1:
例 n=1002,log10(1002)≈3.000867
2. 对结果取整数,得到数字总位数减1:int(3.000867)=3
3. 整除3,得到完整千位段数量k:3 / 3 = 1
含义:1002属于1000~999999区间,每个数字固定1个逗号,k=1
步骤3:拆分总逗号的数学公式推导
总逗号 = 两部分相减:总逗号 = k × (n + 1) − 前k个完整千位区间全部数字产生的逗号总和
第一部分:k × (n+1)
假设从1到n所有数字都有k个逗号,先算出理论最大值。
示例 n=1002,k=1:1 × (1002+1) = 1003
含义:假设1~1002每个数字都带1个逗号,合计1003个逗号。
第二部分:(10^(3k+3) − 1000) / 999
这一步计算1 ~ (10^(3k)-1) 所有数字实际不含k个逗号的总差值,也就是需要扣除的无效逗号数量。
1. 3k:完整千位段对应的位数偏移,k=1时 3k=3
2. 3k+3 = 6,10^6 = 1000000
3. 10^6 − 1000 = 999000
4. 除以999:999000 / 999 = 1000
含义:1~999 这1000个数字,本身没有1个逗号,前面理论计算时给它们全部算了1个逗号,多算了1000个,需要全部减去。
步骤4:合并公式计算最终答案
代入示例 n=1002:
总逗号 = 1003 − 1000 = 3,和题目输出完全匹配。
通用公式数学意义
1. k 代表当前数字档位的标准逗号数;
2. k*(n+1):给1~n全部数字强制分配k个逗号,得到高估总和;
3. 减数项:统计所有小于10^(3k)的数字总个数,这些数字本身不足k个逗号,全部是多算的部分,需要扣除;
4. 相减后得到真实总逗号数量。
步骤5:main函数执行流程
1. 定义输入n=1002,转为int64类型传入countCommas;
2. 执行上述数学计算得到结果;
3. 打印输出最终逗号总数。
二、整体算法核心思想总结
不暴力遍历1~n逐个统计(避免循环),利用十进制千位分段数学公式直接计算,按数字所在区间批量统计逗号:
1. 先确定当前数字所在千位分段,得到该分段标准逗号数k;
2. 用整体高估法,统一给所有数字分配k个逗号;
3. 减去低位区间(不足k个逗号)的数字总数,修正高估误差;
4. 一步算出总逗号,无循环、无逐一枚举。
三、时间复杂度 & 额外空间复杂度分析 1. 时间复杂度 O(1)
整个计算仅执行常数次数学运算:log10、整数转换、幂运算、四则加减乘除,不存在循环、递归、遍历操作,运算次数不随n的大小变化,固定常数次计算,时间复杂度为常量级 O(1)。
2. 额外空间复杂度 O(1)
函数内部仅定义固定数量局部变量(k、ans,无动态数组、切片、哈希、递归栈等动态内存),分配的内存空间大小与输入n无关,始终为固定常量空间,额外空间复杂度 O(1)。
Go完整代码如下:
package main
import (
"fmt"
"math"
)
func countCommas(n int64) (ans int64) {
k := 5// n == 1e15 时 Log10(n) 有误差,需要特判
if n < 1e15 {
k = int(math.Log10(float64(n))) / 3
}
returnint64(k)*(n+1) - (int64(math.Pow10(k*3+3))-1000)/999
}func main() {
n := 1002
result := countCommas(int64(n))
fmt.Println(result)
}
![]()
Python完整代码如下:
# -*-coding:utf-8-*-
def count_commas(n: int) -> int:
"""
返回从 1 到 n(含)所有整数的标准书写格式中逗号的总数
"""
if n < 1000:
return0
# k 表示最高位的逗号组数,例如 n=1000 时 k=1,n=1_000_000 时 k=2
k = (len(str(n)) - 1) // 3
# 使用公式:k*(n+1) - (10^(3k+3) - 1000) / 999
pow10 = 10 ** (3 * k + 3)
return k * (n + 1) - (pow10 - 1000) // 999if __name__ == "__main__":
n = 1002
result = count_commas(n)
print(result)
![]()
C++完整代码如下:
int64_t countCommas(int64_t n) {
int k = 5; // 当 n >= 1e15 时直接取 5,避免 log10 的精度误差
constexpr int64_t threshold = 1000000000000000LL; // 1e15
if (n < threshold) {
k = static_cast(std::log10(static_cast (n))) / 3;
}
int64_t pow10 = static_cast (std::pow( 10.0, k * 3 + 3));
return static_cast (k) * (n + 1) - (pow10 - 1000) / 999;
}int main() {
int64_t n = 1002;
int64_t result = countCommas(n);
std::cout << result << std::endl;
return0;
}
![]()
我们相信人工智能为普通人提供了一种“增强工具”,并致力于分享全方位的AI知识。在这里,您可以找到最新的AI科普文章、工具评测、提升效率的秘籍以及行业洞察。 欢迎关注“福大大架构师每日一题”,发消息可获得面试资料,让AI助力您的未来发展。