数字字符串格式化
问题描述
小M需要处理输入的数字字符串,要求将不带千分位逗号的数字字符串转换为带千分位逗号的格式,并保留小数部分。同时,字符串可能包含无用的前导零,这些需要去除。我们需要帮助小M完成这项任务。
示例输入输出
-
输入:
"1294512.12412"- 输出:
"1,294,512.12412"
- 输出:
-
输入:
"0000123456789.99"- 输出:
"123,456,789.99"
- 输出:
-
输入:
"987654321"- 输出:
"987,654,321"
- 输出:
解题思路
这个问题主要包括两个操作:
- 去除前导零:我们首先需要处理数字字符串的前导零,确保我们得到的数字是有效的。
- 插入千分位逗号:对整数部分插入千分位逗号,并且在处理后组合回小数部分。
为了解决这个问题,具体的步骤如下:
步骤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"));
}
}
代码详解
-
去除前导零:
- 通过
judge变量来标记是否已经遇到非零字符。初始时,如果遇到'0'且judge为false,则跳过该字符。直到遇到第一个非零字符才开始拼接有效字符。 - 这一步操作确保我们最终得到的字符串是去除了前导零的有效数字。
- 通过
-
分离整数部分和小数部分:
- 我们遍历去掉前导零后的字符串,遇到小数点时,开始将字符分到
decimalPart中,之前的字符则归入integerPart。 - 这样可以区分整数部分和小数部分,并分别处理。
- 我们遍历去掉前导零后的字符串,遇到小数点时,开始将字符分到
-
插入千分位逗号:
- 在处理整数部分时,使用
StringBuilder来构造新的字符串。我们从右往左遍历整数部分,并在每三位后插入逗号(注意:插入逗号的操作是从左到右插入,所以需要反向操作)。 - 通过
count % 3 == 0来判断每三个字符后是否插入逗号。
- 在处理整数部分时,使用
-
结果拼接:
- 最后,我们将格式化后的整数部分和小数部分拼接起来返回。如果没有小数部分,直接返回格式化后的整数部分。
时间复杂度分析
-
去除前导零:
- 我们遍历字符串一次,时间复杂度是 O(n),其中
n是字符串的长度。
- 我们遍历字符串一次,时间复杂度是 O(n),其中
-
分离整数部分和小数部分:
- 这部分也需要遍历字符串一次,时间复杂度是 O(n)。
-
插入千分位逗号:
- 在整数部分插入逗号的操作是通过
StringBuilder完成的,时间复杂度为 O(n),因为我们最多插入n / 3个逗号。
- 在整数部分插入逗号的操作是通过
-
最终的时间复杂度:
- 由于每个步骤的时间复杂度都是 O(n),所以整个算法的时间复杂度为 O(n),其中
n是输入字符串的长度。
- 由于每个步骤的时间复杂度都是 O(n),所以整个算法的时间复杂度为 O(n),其中
空间复杂度分析
-
存储字符串:
- 我们使用
StringBuilder来构造新的字符串,并且分离了整数部分和小数部分,所有这些操作的空间复杂度都是 O(n)。
- 我们使用
-
空间复杂度:
- 由于我们只需要存储整数部分、小数部分以及最终的结果,空间复杂度是 O(n)。
总结
- 时间复杂度:O(n)
- 空间复杂度:O(n)
这个解决方案通过一次遍历数字字符串,并用 StringBuilder 处理字符串拼接和千分位插入,保证了算法的高效性。通过去除前导零、分离整数小数部分、插入千分位逗号等步骤,最终得到符合要求的格式化字符串。