数字字符串格式化问题解析 | 豆包MarsCode AI刷题

84 阅读6分钟

问题背景

小M在工作中遇到一个问题,用户输入的数字字符串通常不带千分位逗号,并且可能存在多余的前导零。为了提高数字的可读性,用户希望将输入的数字字符串转换成带有千分位逗号的格式,并且需要保留小数部分。如果输入的数字字符串前有多余的零,这些零也需要去除。该问题实际上是一个数字字符串格式化问题,要求精确处理整数部分和小数部分,并且考虑边界情况。

题目要求

给定一个数字字符串,要求:

  1. 去除字符串中无用的前导零。
  2. 将整数部分按照千分位格式化,即每三位添加一个逗号。
  3. 保留小数部分(如果有),并且不对其进行格式化。

输入与输出

  • 输入:

    • 一个数字字符串 s,包含整数部分和可选的小数部分,且可能包含无效的前导零。
  • 输出:

    • 格式化后的数字字符串,带有千分位逗号,且没有前导零。

例子分析

示例 1
  • 输入"1294512.12412"

  • 输出

     '1,294,512.12412'
    
    • 该数字字符串已经没有前导零,整数部分 1294512 可以被格式化为 1,294,512,小数部分保持不变。
示例 2
  • 输入"0000123456789.99"

  • 输出

     '123,456,789.99'
    
    • 输入的字符串包含前导零,去除后变为 123456789.99,然后整数部分被格式化为 123,456,789,小数部分 .99 保持不变。
示例 3
  • 输入"987654321"

  • 输出

     '987,654,321'
    
    • 该数字字符串没有前导零,整数部分 987654321 被格式化为 987,654,321

解决方案

为了实现这个数字字符串格式化的任务,我们需要以下几个步骤:

  1. 去除前导零

    • 字符串中的前导零不需要保留,因此可以使用 strip('0') 方法去除所有的前导零。需要注意的是,如果去除后字符串为空,表示原输入是一个非常小的数字,如 00000,此时应将其视作 0
  2. 分离整数部分和小数部分

    • 如果数字字符串中包含小数点,我们需要将整数部分和小数部分分开。可以使用 split('.') 方法,将小数部分与整数部分分开。
    • 如果没有小数点,则小数部分为空字符串。
  3. 格式化整数部分

    • 整数部分需要按照千分位格式化。具体方法是将整数部分反转,从右到左每三位插入一个逗号,然后再将结果反转回来。
  4. 合并整数部分和小数部分

    • 最后,将格式化后的整数部分和原始的小数部分(如果存在)重新组合成最终的格式化字符串。

实现细节

  • 去除前导零: 使用 Python 字符串的 strip('0') 方法去除所有前导零。如果去除后字符串为空,需要将其设置为 '0'

  • 分离整数和小数部分: 使用 Python 的 split('.') 方法,如果存在小数点,则可以获得整数部分和小数部分。对于没有小数点的情况,默认将小数部分设置为空字符串。

  • 千分位格式化: 通过反转整数部分,遍历每三位添加逗号,并在最后再反转回来。这是一种简单且有效的格式化方法。具体的步骤如下:

    1. 遍历整数部分,从右到左每三位插入一个逗号。
    2. 由于是从右到左添加逗号,因此最后需要将结果反转回来。
  • 返回结果: 如果存在小数部分,则返回格式化后的整数部分和小数部分合并后的结果;如果没有小数部分,则只返回格式化后的整数部分。


代码实现

 python复制代码def solution(s: str) -> str:
     # 去除前导零
     s = s.lstrip('0')
     # 如果去除前导零后字符串为空,说明数字为零
     if s == '':
         return '0'
     
     # 分离整数部分和小数部分
     if '.' in s:
         integer_part, decimal_part = s.split('.')
     else:
         integer_part, decimal_part = s, ''
     
     # 格式化整数部分
     formatted_integer_part = ''
     for i, char in enumerate(reversed(integer_part)):
         if i > 0 and i % 3 == 0:
             formatted_integer_part = ',' + formatted_integer_part
         formatted_integer_part = char + formatted_integer_part
 ​
     # 合并整数和小数部分
     if decimal_part:
         return f"{formatted_integer_part}.{decimal_part}"
     else:
         return formatted_integer_part

代码解析

  1. 去除前导零: 使用 s.lstrip('0') 方法去除字符串 s 中的前导零。这个方法返回去除前导零后的字符串。
  2. 处理空字符串情况: 如果 s 为空字符串(即输入的数字全是零),我们返回 '0'
  3. 分离整数和小数部分: 如果输入字符串中包含小数点(通过 '.' in s 判断),则使用 split('.') 方法将整数部分和小数部分分离。如果没有小数点,则小数部分为空字符串。
  4. 整数部分的千分位格式化: 遍历整数部分的字符(从右到左),每三位添加一个逗号。具体做法是将整数部分反转,并根据索引插入逗号,最后再将结果反转回来。
  5. 合并结果: 如果有小数部分,则将格式化后的整数部分和小数部分拼接在一起;如果没有小数部分,只返回格式化后的整数部分。

边界情况

  1. 输入为零: 如果输入为全零字符串(如 "0000"),经过去除前导零后应返回 '0'
  2. 没有小数部分的整数: 如果输入是一个整数,如 "1000000",则返回格式化后的整数部分 '1,000,000'
  3. 只有小数部分的数字: 如果输入只有小数部分(如 "0.999"),则结果应为 "0.999"
  4. 极小或极大的数字: 该方法同样适用于极小或极大的数字,如 "0.00000001""12345678901234567890",它们会按照预期格式化为 0.0000000112,345,678,901,234,567,890

复杂度分析

  • 时间复杂度

    • 去除前导零:O(n),其中 n 是字符串的长度。
    • 格式化整数部分:O(n),其中 n 是整数部分的长度。
    • 总体时间复杂度:O(n)
  • 空间复杂度

    • 空间复杂度:O(n),用于存储格式化后的字符串。