
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。
k 是完整千位段的数量,对应数字统一携带的逗号数量:
当 n = 10^15 时,浮点数 math.Log10 会存在精度丢失,无法正确算出位数,因此代码预设兜底 k=5;题目限制 n≤100000,不会触发该特判,仅为超大数兼容。
总逗号 = 两部分相减:
总逗号 = k × (n + 1) − 前k个完整千位区间全部数字产生的逗号总和
假设从1到n所有数字都有k个逗号,先算出理论最大值。 示例 n=1002,k=1:1 × (1002+1) = 1003 含义:假设1~1002每个数字都带1个逗号,合计1003个逗号。
这一步计算1 ~ (10^(3k)-1) 所有数字实际不含k个逗号的总差值,也就是需要扣除的无效逗号数量。
代入示例 n=1002: 总逗号 = 1003 − 1000 = 3,和题目输出完全匹配。
不暴力遍历1~n逐个统计(避免循环),利用十进制千位分段数学公式直接计算,按数字所在区间批量统计逗号:
整个计算仅执行常数次数学运算:log10、整数转换、幂运算、四则加减乘除,不存在循环、递归、遍历操作,运算次数不随n的大小变化,固定常数次计算,时间复杂度为常量级 O(1)。
函数内部仅定义固定数量局部变量(k、ans,无动态数组、切片、哈希、递归栈等动态内存),分配的内存空间大小与输入n无关,始终为固定常量空间,额外空间复杂度 O(1)。
.
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)
}

.
# -*-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) // 999
if __name__ == "__main__":
n = 1002
result = count_commas(n)
print(result) 
.
#include <iostream>
#include <cmath>
#include <cstdint>
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<int>(std::log10(static_cast<double>(n))) / 3;
}
int64_t pow10 = static_cast<int64_t>(std::pow(10.0, k * 3 + 3));
return static_cast<int64_t>(k) * (n + 1) - (pow10 - 1000) / 999;
}
int main() {
int64_t n = 1002;
int64_t result = countCommas(n);
std::cout << result << std::endl;
return0;
}

·