问题描述
小C对“好数”非常感兴趣,她定义一个不含前导零的正整数为“好数”,如果它的所有数位最多包含两种不同的数字。例如,数字 23,2323,9,111,和 101 都是好数。现在小C想知道,从1到nn之间有多少个好数。
例如:当n=110n=110时,所有的1位数、2位数,以及一些3位数(如 100, 101)都是好数,一共有102个。
测试样例
样例1:
输入:
n = 110
输出:102
样例2:
输入:
n = 1000
输出:352
样例3:
输入:
n = 1
输出:1下面是一个解决方案的思路:
-
直接枚举法:
- 遍历1到n的所有数字,检查每个数字是否符合“好数”的条件。
- 具体地,可以将数字转换为字符串,使用集合来检查其中不同数字的数量。
-
实现步骤:
-
对于每一个数字i,从1到n:
- 将i转换为字符串。
- 使用一个集合存储其中的字符。
- 如果集合的大小不超过2,则计入“好数”。
-
-
复杂度:
- 这个方法的时间复杂度是O(n * d),其中d是数字的位数,通常对于n ≤ 1000,d是比较小的,因此该方法是可行的。
下面是Python实现的代码:
python
def count_good_numbers(n):
count = 0
for i in range(1, n + 1):
# 将数字转换为字符串
num_str = str(i)
# 使用集合存储不同的字符
unique_digits = set(num_str)
# 检查集合的大小
if len(unique_digits) <= 2:
count += 1
return count
# 测试样例
print(count_good_numbers(110)) # 输出: 102
print(count_good_numbers(1000)) # 输出: 352
print(count_good_numbers(1)) # 输出: 1
```好的,让我们深入分析上述代码,分解其工作机制、性能以及可能的优化方向。
### 代码分析
python def count_good_numbers(n): count = 0 for i in range(1, n + 1): num_str = str(i) unique_digits = set(num_str) if len(unique_digits) <= 2: count += 1 return count
#### 1. 函数定义
python def count_good_numbers(n):
- 定义了一个名为`count_good_numbers`的函数,接受一个整数参数`n`,表示我们要查找的范围。
#### 2. 初始化计数器
python count = 0
- 初始化一个计数器`count`,用于记录符合条件的“好数”的数量。
#### 3. 遍历数字
python for i in range(1, n + 1):
- 使用`for`循环遍历从1到n的所有整数,`range(1, n + 1)`确保包括n本身。
#### 4. 转换为字符串
python num_str = str(i)
- 将当前数字`i`转换为字符串,以便后续操作可以逐位处理。
#### 5. 提取唯一数字
python unique_digits = set(num_str)
- 使用`set`创建一个集合,自动去除字符串中重复的字符。这将保留数字的唯一性。
#### 6. 检查数字种类数量
python if len(unique_digits) <= 2:
- 检查集合的长度。如果不同数字的数量不超过2,则认为这是一个“好数”。
#### 7. 更新计数器
python count += 1
- 如果当前数字是“好数”,则将计数器`count`加一。
#### 8. 返回结果
python return count
- 最后返回计数器的值,表示在1到n之间的“好数”总数。
### 性能分析
#### 时间复杂度
- 外层循环执行n次(从1到n),内层的字符串转换和集合操作时间复杂度为O(d),其中d是数字的位数。
- 最终时间复杂度为O(n * d)。对于n ≤ 1000,d通常为3,因此该方法在这个范围内是可行的。
#### 空间复杂度
- 主要使用的额外空间是存储唯一数字的集合,最坏情况下的空间复杂度为O(d),最多为10(数字0-9)。所以空间使用量也相对有限。
### 代码解释:
- 我们定义了一个函数`count_good_numbers`,接受参数n。
- 通过一个for循环遍历从1到n的每个数字。
- 将每个数字转换为字符串,并通过集合存储其数字,最后检查集合的大小是否小于等于2。
- 如果满足条件,计数器加一,最后返回计数器的值。
### 优化建议:
对于更大的n,可以考虑使用动态规划或其他更高效的方法来避免逐一检查每个数字,但对于范围较小的n,这种直接的方法是简单且有效的。