问题描述
小R拿到了一个长度为n的数组,其中每个元素都是一个正整数。小R发现每次可以删除某个数组中某个数的一位数字,这样可以逐步将所有数字变为0。他想知道,要将数组中所有数字都变为0,最少需要多少步?
例如:对于数字 103,小R可以选择删除第1位数字,将其变为 3;或者删除第2位数字,变为 13,又或者删除第3位数字,将其变为 10。最终目标是将所有数字都删除为0。
解题思路
这是一道非常适合贪心思维的题目。在这道题中,每个数字的位数(长度)决定了至少需要多少步才能归零。然而,由于每次删除操作只针对非零位,因此最优解的关键在于:只需统计每个数字中的非零位数量。
-
单个数字归零的最少步数:
- 对于一个数字 ,将其归零的最小操作次数为其数字中非零数字的个数。例如:
- :有两个非零位 ,需要2步。
- :只有一个非零位 ,需要1步。
- 因此,每个数字的最优策略是逐步删除所有非零位,忽略零。
- 对于一个数字 ,将其归零的最小操作次数为其数字中非零数字的个数。例如:
-
数组整体归零的最少步数:
- 遍历数组中的每个数字,计算其归零所需的步数。
- 最后将所有步数累加,即为答案。
代码分解
核心函数:单个数字的归零步数
- 将数字转为字符串后逐位遍历,统计非零数字的数量即可得到所需步数。
- 特殊情况:对于数字
0,返回步数为 0。
def min_steps_for_number(num: int) -> int:
"""计算单个数字归零需要的最少步数"""
# 如果是0,不需要任何步数
if num == 0:
return 0
# 如果是个位数,只需要一步
if num < 10:
return 1
# 将数字转为字符串以便处理每一位
str_num = str(num)
# 统计非零数字的个数
non_zero_count = sum(1 for digit in str_num if digit != '0')
return non_zero_count
核心函数:数组的总步数
- 遍历数组中的每个数字,通过
min_steps_for_number计算单个数字的步数,并累加。 - 最终返回累加结果。
def solution(n: int, a: list) -> int:
"""计算数组中所有数字归零的最少步数总和"""
# 对数组中每个数字计算最少步数并求和
total_steps = 0
for num in a:
steps = min_steps_for_number(num)
total_steps += steps
return total_steps
运行结果
时间复杂度分析
-
单个数字的处理:
- 将数字转换为字符串的时间复杂度为 ,其中 是数字的位数。
- 遍历字符串统计非零位的复杂度为 。
-
数组整体的处理:
- 对于数组中的每个数字,执行上述操作。设数组中最大数字的位数为 ,数组长度为 。
- 总时间复杂度为 。
空间复杂度
- 只需要常量空间存储中间变量,空间复杂度为 。
思考与优化
- 效率优化:
- 当前算法的时间复杂度已经接近最优,但仍需注意输入的规模(数字长度和数组长度)。
- 特殊场景:
- 如果输入全为零,直接返回步数为零。
- 长度为1的数组直接处理单个数字,减少额外计算。