2026-04-02:统计移除零后不同整数的数目。用go语言,给定一个正整数 n。把 1 到 n 之间每个整数 x 的十进制写法拿出来,把其中所有数字“0”删掉(也就是只保留非零数字,并把剩下的部分视为一个新的十进制数)。把对每个 x 得到的结果都记录下来。
最后要你统计:这些记录到的结果里有多少个不同的数值。并返回这个不同结果的数量。
1 <= n <= 1000000000000000。
输入:n = 10。
输出:9。
解释:
我们记下的整数是 1, 2, 3, 4, 5, 6, 7, 8, 9, 1。有 9 个不同的整数 (1, 2, 3, 4, 5, 6, 7, 8, 9)。
题目来自力扣3747。
代码逻辑分步详细解析
一、先明确题目核心规则
给定正整数n,遍历1~n的所有整数:
- 对每个数,删除所有数字0,剩余非零数字拼接成新整数;
- 统计所有新整数中不重复数值的总个数。
示例:n=10时,1~10删除0后结果为1,2,3,4,5,6,7,8,9,1,去重后共9个,输出9。
二、函数countDistinct(n int64)分步执行过程
函数的核心目标:不遍历1~n(n极大,遍历会超时),直接通过数学规律计算去重后的总数。
我们以输入n=10为例,逐步骤拆解:
步骤1:初始化核心变量
- 定义结果变量
ans(初始值0):用于累加符合条件的数字组合数; - 定义变量
pow9(初始值1):用于计算9的幂次,代表每一位数字的可选组合数(因为删除0后,数字只能是1-9,共9种选择)。
步骤2:逐位拆分数字n(从低位到高位)
循环逻辑:不断取n的最后一位数字,处理完后去掉最后一位,直到n变为0。
以n=10为例,拆分过程:
- 第一次循环:n=10 → 最后一位
d=0,处理后n=1; - 第二次循环:n=1 → 最后一位
d=1,处理后n=0; - 循环结束。
步骤3:逐位处理数字,分情况计算
情况1:当前位数字d = 0
- 规则:只要某一位是0,当前位及后续的组合数直接清零;
- 原因:删除0后,包含0的数字不会产生新的有效组合,无法贡献不重复数值。
- 示例:n=10的最后一位是0 →
ans置为0。
情况2:当前位数字d ≠ 0
分两个子规则计算:
- 第一位特殊处理:如果是数字的最高位(
pow9=1,代表9⁰),数字直接用原值; 如果不是最高位(pow9>1),数字需要减1(排除重复组合); - 累加贡献值:用处理后的数字 × 当前9的幂次,结果加到
ans中。
- 示例:n=10的第二位是1(最高位)→ 直接用1,
ans += 1×1=1。
步骤4:更新9的幂次
每处理完一位数字,pow9乘以9(代表下一位的组合数:9¹=9、9²=81、9³=729...)。
- 示例:处理完个位(0)→ pow9=9;处理完十位(1)→ pow9=81。
步骤5:循环结束,计算最终总数
公式:最终结果 = ans + (pow9 - 9) / 8
这个公式的作用:计算所有位数小于n的数字,删除0后能产生的不重复数值总数。
- 公式拆解:
(pow9-9)/8是数学求和公式,计算9¹+9²+...+9ᵏ(k为n的位数-1); - 示例:
ans=1,(81-9)/8=9→ 最终结果=1+9=9,与题目输出一致。
三、总逻辑总结(通俗理解)
- 不暴力遍历1~n(n最大10¹⁵,遍历不可能完成);
- 把n按十进制位拆分,从低位到高位逐位分析;
- 利用9的幂次计算:删除0后,每一位只能选1-9,天然无重复;
- 分两部分求和:
- 第一部分:位数和n相同的数字,删除0后的有效不重复数;
- 第二部分:位数小于n的所有数字,删除0后的不重复数(固定公式计算);
- 两部分相加,就是最终答案。
四、时间复杂度 & 额外空间复杂度
1. 时间复杂度
- 核心操作:逐位拆分数字n,循环次数 = n的十进制位数;
- n最大为10¹⁵,十进制最多16位,循环次数是常数级;
- 结论:时间复杂度 O(1)(常数时间复杂度)。
2. 额外空间复杂度
- 函数中仅定义了
ans、pow9、d三个变量,没有使用数组、切片、哈希表等动态数据结构; - 无论n多大,占用的额外内存空间固定不变;
- 结论:额外空间复杂度 O(1)(常数空间复杂度)。
总结
- 代码通过数学规律+逐位处理,避免了暴力遍历,完美适配n≤10¹⁵的超大范围;
- 核心是利用「删除0后数字仅含1-9」的特性,用9的幂次计算不重复数;
- 时间和空间复杂度均为O(1),效率极高。
Go完整代码如下:
package main
import (
"fmt"
)
func countDistinct(n int64) (ans int64) {
pow9 := int64(1)
for ; n > 0; n /= 10 {
d := n % 10
if d == 0 {
ans = 0
} else {
if pow9 > 1 {
d--
}
ans += d * pow9
}
pow9 *= 9
}
return ans + (pow9-9)/8
}
func main() {
n := int64(10)
result := countDistinct(n)
fmt.Println(result)
}
Python完整代码如下:
# -*-coding:utf-8-*-
def countDistinct(n: int) -> int:
ans = 0
pow9 = 1
while n > 0:
d = n % 10
if d == 0:
ans = 0
else:
if pow9 > 1:
d -= 1
ans += d * pow9
pow9 *= 9
n //= 10
return ans + (pow9 - 9) // 8
def main():
n = 10
result = countDistinct(n)
print(result)
if __name__ == "__main__":
main()
C++完整代码如下:
#include <iostream>
using namespace std;
long long countDistinct(long long n) {
long long ans = 0;
long long pow9 = 1;
while (n > 0) {
long long d = n % 10;
if (d == 0) {
ans = 0;
} else {
if (pow9 > 1) {
d--;
}
ans += d * pow9;
}
pow9 *= 9;
n /= 10;
}
return ans + (pow9 - 9) / 8;
}
int main() {
long long n = 10;
long long result = countDistinct(n);
cout << result << endl;
return 0;
}