MarsCode AI 刷题思路解析:45. (难) 最少步数归零问题 | 豆包MarsCode AI刷题

60 阅读3分钟

问题描述

小R拿到了一个长度为n的数组,其中每个元素都是一个正整数。小R发现每次可以删除某个数组中某个数的一位数字,这样可以逐步将所有数字变为0。他想知道,要将数组中所有数字都变为0,最少需要多少步?

例如:对于数字 103,小R可以选择删除第1位数字,将其变为 3;或者删除第2位数字,变为 13,又或者删除第3位数字,将其变为 10。最终目标是将所有数字都删除为0。

解题思路

这是一道非常适合贪心思维的题目。在这道题中,每个数字的位数(长度)决定了至少需要多少步才能归零。然而,由于每次删除操作只针对非零位,因此最优解的关键在于:只需统计每个数字中的非零位数量。

  1. 单个数字归零的最少步数

    • 对于一个数字 numnum,将其归零的最小操作次数为其数字中非零数字的个数。例如:
      • 105105:有两个非零位 {1,5}\{1, 5\},需要2步。
      • 100100:只有一个非零位 {1}\{1\},需要1步。
    • 因此,每个数字的最优策略是逐步删除所有非零位,忽略零。
  2. 数组整体归零的最少步数

    • 遍历数组中的每个数字,计算其归零所需的步数。
    • 最后将所有步数累加,即为答案。

代码分解

核心函数:单个数字的归零步数

  • 将数字转为字符串后逐位遍历,统计非零数字的数量即可得到所需步数。
  • 特殊情况:对于数字 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

运行结果

image.png

时间复杂度分析

  1. 单个数字的处理:

    • 将数字转换为字符串的时间复杂度为 O(d)O(d),其中 dd 是数字的位数。
    • 遍历字符串统计非零位的复杂度为 O(d)O(d)
  2. 数组整体的处理:

    • 对于数组中的每个数字,执行上述操作。设数组中最大数字的位数为 DD,数组长度为 nn
    • 总时间复杂度为 O(n×D)O(n \times D)

空间复杂度

  • 只需要常量空间存储中间变量,空间复杂度为 O(1)O(1)

思考与优化

  1. 效率优化:
    • 当前算法的时间复杂度已经接近最优,但仍需注意输入的规模(数字长度和数组长度)。
  2. 特殊场景:
    • 如果输入全为零,直接返回步数为零。
    • 长度为1的数组直接处理单个数字,减少额外计算。