2026-04-02:统计移除零后不同整数的数目。用go语言,给定一个正整数 n。把 1 到 n 之间每个整数 x 的十进制写法拿出来,把其中所有数字“0”删掉

0 阅读5分钟

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的所有整数:

  1. 对每个数,删除所有数字0,剩余非零数字拼接成新整数;
  2. 统计所有新整数中不重复数值的总个数。

示例: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为例,拆分过程:

  1. 第一次循环:n=10 → 最后一位d=0,处理后n=1;
  2. 第二次循环:n=1 → 最后一位d=1,处理后n=0;
  3. 循环结束。

步骤3:逐位处理数字,分情况计算

情况1:当前位数字d = 0
  • 规则:只要某一位是0,当前位及后续的组合数直接清零
  • 原因:删除0后,包含0的数字不会产生新的有效组合,无法贡献不重复数值。
  • 示例:n=10的最后一位是0 → ans置为0。
情况2:当前位数字d ≠ 0

分两个子规则计算:

  1. 第一位特殊处理:如果是数字的最高位(pow9=1,代表9⁰),数字直接用原值; 如果不是最高位(pow9>1),数字需要减1(排除重复组合);
  2. 累加贡献值:用处理后的数字 × 当前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. 不暴力遍历1~n(n最大10¹⁵,遍历不可能完成);
  2. 把n按十进制位拆分,从低位到高位逐位分析;
  3. 利用9的幂次计算:删除0后,每一位只能选1-9,天然无重复;
  4. 分两部分求和:
    • 第一部分:位数和n相同的数字,删除0后的有效不重复数;
    • 第二部分:位数小于n的所有数字,删除0后的不重复数(固定公式计算);
  5. 两部分相加,就是最终答案。

四、时间复杂度 & 额外空间复杂度

1. 时间复杂度

  • 核心操作:逐位拆分数字n,循环次数 = n的十进制位数
  • n最大为10¹⁵,十进制最多16位,循环次数是常数级
  • 结论:时间复杂度 O(1)(常数时间复杂度)。

2. 额外空间复杂度

  • 函数中仅定义了anspow9d三个变量,没有使用数组、切片、哈希表等动态数据结构
  • 无论n多大,占用的额外内存空间固定不变;
  • 结论:额外空间复杂度 O(1)(常数空间复杂度)。

总结

  1. 代码通过数学规律+逐位处理,避免了暴力遍历,完美适配n≤10¹⁵的超大范围;
  2. 核心是利用「删除0后数字仅含1-9」的特性,用9的幂次计算不重复数;
  3. 时间和空间复杂度均为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;
}

在这里插入图片描述