数字字符串格式化
1.问题描述
问题描述
小M在工作时遇到了一个问题,他需要将用户输入的不带千分位逗号的数字字符串转换为带千分位逗号的格式,并且保留小数部分。小M还发现,有时候输入的数字字符串前面会有无用的 0
,这些也需要精简掉。请你帮助小M编写程序,完成这个任务。
测试样例
样例1:
输入:
s = "1294512.12412"
输出:'1,294,512.12412'
样例2:
输入:
s = "0000123456789.99"
输出:'123,456,789.99'
样例3:
输入:
s = "987654321"
输出:'987,654,321'
2.思路与题解
问题理解
我们需要将一个不带千分位逗号的数字字符串转换为带千分位逗号的格式,并且保留小数部分。此外,输入的字符串可能会有前导的 0
,这些 0
需要被精简掉。
数据结构选择
由于我们处理的是字符串,并且需要对字符串进行插入操作(插入千分位逗号),因此我们可以选择使用字符串或字符串构建器(StringBuilder)来处理。
算法步骤
- 去除前导零:首先,我们需要去除字符串前面的无用
0
。 - 分离整数部分和小数部分:将字符串分为整数部分和小数部分。
- 处理整数部分:对整数部分进行千分位逗号的插入。
- 合并结果:将处理后的整数部分和小数部分重新合并。
具体步骤
去除前导零:
- 使用
String.replaceFirst("^0+(?!$)", "")
来去除前导零。
- 使用
分离整数部分和小数部分:
- 使用
String.split("\\.")
来分离整数部分和小数部分。
- 使用
处理整数部分:
- 从后往前遍历整数部分,每三位插入一个逗号。
合并结果:
- 将处理后的整数部分和小数部分重新合并,如果小数部分不存在,则只返回整数部分。
2.4代码框架
Java
public class Main {
public static String solution(String s) {
// write code here
s = s.replaceFirst("^0+(?!$)", "");
// 分离整数部分和小数部分
String[] parts = s.split("\\.");
String integerPart = parts[0];
String decimalPart = parts.length > 1 ? "." + parts[1] : "";
// 处理整数部分
StringBuilder formattedIntegerPart = new StringBuilder();
int count = 0;
for (int i = integerPart.length() - 1; i >= 0; i--) {
formattedIntegerPart.append(integerPart.charAt(i));
count++;
if (count % 3 == 0 && i != 0) {
formattedIntegerPart.append(",");
}
}
formattedIntegerPart.reverse();
// 合并结果
return formattedIntegerPart.toString() + 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"));
}
}
C++
#include <string>
#include <iostream>
std::string solution(const std::string& s) {
// 1. 去除前导零
size_t start = 0;
while (start < s.size() && s[start] == '0') {
start++;
}
std::string trimmed = s.substr(start);
// 2. 找到小数点的位置
size_t dotPos = trimmed.find('.');
if (dotPos == std::string::npos) {
dotPos = trimmed.size();
}
// 3. 插入千分位逗号
std::string result;
for (size_t i = 0; i < dotPos; ++i) {
if (i > 0 && (dotPos - i) % 3 == 0) {
result += ',';
}
result += trimmed[i];
}
// 4. 添加小数部分
if (dotPos < trimmed.size()) {
result += trimmed.substr(dotPos);
}
return result;
}
int main() {
std::cout << (solution("1294512.12412") == "1,294,512.12412") << std::endl;
std::cout << (solution("0000123456789.99") == "123,456,789.99") << std::endl;
std::cout << (solution("987654321") == "987,654,321") << std::endl;
}
Python
def solution(s: str) -> str:
# 去除前导零
s = s.lstrip('0')
# 分离整数和小数部分
if '.' in s:
integer_part, decimal_part = s.split('.')
else:
integer_part, decimal_part = s, ''
# 格式化整数部分
# 这里需要实现一个函数来添加千分位逗号
formatted_integer_part = add_commas_to_integer(integer_part)
# 合并整数和小数部分
if decimal_part:
return f"{formatted_integer_part}.{decimal_part}"
else:
return formatted_integer_part
def add_commas_to_integer(integer_part: str) -> str:
# 这里需要实现一个函数来添加千分位逗号
# 提示:可以使用 reversed 和 join 方法
pass
if __name__ == '__main__':
print(solution("1294512.12412") == '1,294,512.12412')
print(solution("0000123456789.99") == '123,456,789.99')
print(solution("987654321") == '987,654,321')
Golang
func solution(s string) string {
// 去除前导零
s = strings.TrimLeft(s, "0")
// 分离整数部分和小数部分
parts := strings.Split(s, ".")
integerPart := parts[0]
var decimalPart string
if len(parts) > 1 {
decimalPart = parts[1]
}
// 格式化整数部分
var formattedIntegerPart string
for i, char := range integerPart {
if i > 0 && (len(integerPart)-i)%3 == 0 {
formattedIntegerPart += ","
}
formattedIntegerPart += string(char)
}
// 合并整数部分和小数部分
if decimalPart != "" {
return formattedIntegerPart + "." + decimalPart
}
return formattedIntegerPart
}
2.5一些疑难的代码解释
去除前导零:
s.replaceFirst("^0+(?!$)", "")
分离整数部分和小数部分:
String[] parts = s.split("\\.");
处理整数部分:从后往前遍历整数部分,每三位插入一个逗号。
合并结果:将处理后的整数部分和小数部分重新合并。
其中这里为什么用StringBuilder不用StringBuffer(下面有讲解,拉下去)
在Java中,StringBuilder和StringBuffer都是用于处理可变字符串的类,但它们之间有一些关键的区别:
1、线程安全性:
- StringBuffer是线程安全的,它的所有公共方法都是同步的。这意味着在多线程环境中使用StringBuffer是安全的,但同步操作会带来一定的性能开销。
- StringBuilder不是线程安全的,它的方法没有同步。因此,在单线程环境中使用StringBuilder可以获得更好的性能。
2、性能:
- 由于StringBuilder不需要进行同步操作,因此在单线程环境中,StringBuilder的性能通常优于StringBuffer。
- 在代码中,StringBuilder被用于构建格式化后的整数部分。由于这个操作是在单线程环境中进行的,使用StringBuilder是合适的,因为它可以提供更好的性能。
3.欢迎大佬们关注或莅临本渣的一些个人website
gitee: https://gitee.com/xiao-chenago
github:https://github.com/cool-icu0
语雀:https://www.yuque.com/icu0
csdn:https://cool-icu.blog.csdn.net/