Day3 题解:数字字符串格式化| 豆包MarsCode AI刷题

105 阅读5分钟

数字字符串格式化

问题描述

小M需要处理输入的数字字符串,要求将不带千分位逗号的数字字符串转换为带千分位逗号的格式,并保留小数部分。同时,字符串可能包含无用的前导零,这些需要去除。我们需要帮助小M完成这项任务。

示例输入输出

  • 输入"1294512.12412"

    • 输出"1,294,512.12412"
  • 输入"0000123456789.99"

    • 输出"123,456,789.99"
  • 输入"987654321"

    • 输出"987,654,321"

解题思路

这个问题主要包括两个操作:

  1. 去除前导零:我们首先需要处理数字字符串的前导零,确保我们得到的数字是有效的。
  2. 插入千分位逗号:对整数部分插入千分位逗号,并且在处理后组合回小数部分。

为了解决这个问题,具体的步骤如下:

步骤1:去除前导零

  • 数字字符串可能以多个零开头(例如 "0000123456789")。我们只需要保留第一个非零字符后的所有字符。我们通过一个布尔变量 judge 来判断是否已经找到第一个非零字符,一旦找到,就开始保留后续字符。

步骤2:分离整数部分和小数部分

  • 如果输入的字符串包含小数点(即 "."),我们需要分离整数部分和小数部分。整数部分处理千分位逗号的插入,小数部分直接保留,不做改变。
  • 如果字符串中没有小数点(即纯整数),我们只处理整数部分。

步骤3:对整数部分插入千分位逗号

  • 对于整数部分,我们从右向左遍历字符串,每遇到三个字符就插入一个逗号。为了避免频繁的字符串拼接,我们使用 StringBuilder 来处理字符的插入操作。

步骤4:组合整数部分和小数部分

  • 在处理完整数部分并插入逗号后,将整数部分和小数部分(如果有)合并。如果没有小数部分,则只返回带逗号的整数部分。

代码实现与详解

下面是详细的代码实现过程:

java
复制代码
public class Main {
    public static String solution(String s) {
        // 去掉前导零
        String temp = "";
        boolean judge = false;
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '0' && !judge) {
                continue;  // 跳过前导零
            } else {
                judge = true;
                temp += s.charAt(i);  // 保留有效字符
            }
        }
        s = temp; // 去零后的字符串
        
        // 分离整数部分和小数部分
        String integerPart = "";
        String decimalPart = "";
        boolean hasDecimal = false;
        
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '.') {
                hasDecimal = true;  // 记录小数点的位置
            } else if (hasDecimal) {
                decimalPart += s.charAt(i);  // 小数部分
            } else {
                integerPart += s.charAt(i);  // 整数部分
            }
        }

        // 对整数部分插入千分位逗号
        StringBuilder newIntegerPart = new StringBuilder();
        int count = 0;
        for (int i = integerPart.length() - 1; i >= 0; i--) {
            if (count > 0 && count % 3 == 0) {
                newIntegerPart.insert(0, ',');  // 每三位插入逗号
            }
            newIntegerPart.insert(0, integerPart.charAt(i));  // 添加当前字符
            count++;
        }

        // 组合整数部分和小数部分
        if (decimalPart.isEmpty()) {
            return newIntegerPart.toString();  // 只有整数部分
        } else {
            return newIntegerPart + "." + decimalPart;  // 整数 + 小数部分
        }
    }

    public static void main(String[] args) {
        // 测试用例
        System.out.println(solution("1294512.12412").equals("1,294,512.12412"));
        System.out.println(solution("0000123456789.99").equals("123,456,789.99"));
        System.out.println(solution("987654321").equals("987,654,321"));
    }
}

代码详解

  1. 去除前导零

    • 通过 judge 变量来标记是否已经遇到非零字符。初始时,如果遇到 '0'judgefalse,则跳过该字符。直到遇到第一个非零字符才开始拼接有效字符。
    • 这一步操作确保我们最终得到的字符串是去除了前导零的有效数字。
  2. 分离整数部分和小数部分

    • 我们遍历去掉前导零后的字符串,遇到小数点时,开始将字符分到 decimalPart 中,之前的字符则归入 integerPart
    • 这样可以区分整数部分和小数部分,并分别处理。
  3. 插入千分位逗号

    • 在处理整数部分时,使用 StringBuilder 来构造新的字符串。我们从右往左遍历整数部分,并在每三位后插入逗号(注意:插入逗号的操作是从左到右插入,所以需要反向操作)。
    • 通过 count % 3 == 0 来判断每三个字符后是否插入逗号。
  4. 结果拼接

    • 最后,我们将格式化后的整数部分和小数部分拼接起来返回。如果没有小数部分,直接返回格式化后的整数部分。

时间复杂度分析

  1. 去除前导零

    • 我们遍历字符串一次,时间复杂度是 O(n),其中 n 是字符串的长度。
  2. 分离整数部分和小数部分

    • 这部分也需要遍历字符串一次,时间复杂度是 O(n)。
  3. 插入千分位逗号

    • 在整数部分插入逗号的操作是通过 StringBuilder 完成的,时间复杂度为 O(n),因为我们最多插入 n / 3 个逗号。
  4. 最终的时间复杂度

    • 由于每个步骤的时间复杂度都是 O(n),所以整个算法的时间复杂度为 O(n),其中 n 是输入字符串的长度。

空间复杂度分析

  1. 存储字符串

    • 我们使用 StringBuilder 来构造新的字符串,并且分离了整数部分和小数部分,所有这些操作的空间复杂度都是 O(n)。
  2. 空间复杂度

    • 由于我们只需要存储整数部分、小数部分以及最终的结果,空间复杂度是 O(n)。

总结

  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

这个解决方案通过一次遍历数字字符串,并用 StringBuilder 处理字符串拼接和千分位插入,保证了算法的高效性。通过去除前导零、分离整数小数部分、插入千分位逗号等步骤,最终得到符合要求的格式化字符串。