题解 | #人民币转换#
人民币转换
http://www.nowcoder.com/practice/00ffd656b9604d1998e966d555005a4b
题意
题目直接就是题意
1、中文大写金额数字前应标明“人民币”字样。中文大写金额数字应用壹、贰、叁、肆、伍、陆、柒、捌、玖、拾、佰、仟、万、亿、元、角、分、零、整等字样填写。
2、中文大写金额数字到“元”为止的,在“元”之后,应写“整字,如532.00应写成“人民币伍佰叁拾贰元整”。在”角“和”分“后面不写”整字。
3、阿拉伯数字中间有“0”时,中文大写要写“零”字,阿拉伯数字中间连续有几个“0”时,中文大写金额中间只写一个“零”字,如6007.14,应写成“人民币陆仟零柒元壹角肆分“。
4、10应写作“拾”,100应写作“壹佰”。例如,1010.00应写作“人民币壹仟零拾元整”,110.00应写作“人民币壹佰拾元整”
5、十万以上的数字接千不用加“零”,例如,30105000.00应写作“人民币叁仟零拾万伍仟元整”
方法
实现
先拆解类别
1~9: 壹、贰、叁、肆、伍、陆、柒、捌、玖
10/100/100/10000/100000000: 拾、佰、仟、万、亿
小数:角、分
单位:元
特殊:零、整
把文字变为逻辑
整:当角和分都是零的时候出现
零:4个一组,连续的合并,且和末尾不连接
万:万的4个数字非全0
拾:单位是1时不输出1
把上述逻辑转换成代码
以样例数据151121.15
为例
操作 | 字符 | 剩余处理部分 |
---|---|---|
初始化 | - | 151121.15 |
处理'整'/'角'/'分' | 壹角伍分 | 151121 |
处理后4位 | - | 1121 |
处理1 | 壹 | 1121 |
处理2 | 贰拾壹 | 1121 |
处理1 | 壹佰贰拾壹 | 1121 |
处理1 | 壹仟壹佰贰拾壹 | 1121 |
拼接到结果 | 壹仟壹佰贰拾壹元壹角伍分 | 15 |
处理高4位 | - | 15 |
处理5 | 伍 | 15 |
处理1 | 拾伍 | 15 |
拼接到结果 | 拾伍万壹仟壹佰贰拾壹元壹角伍分 | - |
代码
#include<bits/stdc++.h>
using namespace std;
string ch[] = {
"零",
"壹",
"贰",
"叁",
"肆",
"伍",
"陆",
"柒",
"捌",
"玖"
};
string chstr(string s){
string str = "";
int n = s.length();
if(s[n-1] != '0'){ // 全为零不输出
str += ch[s[n-1]-'0'];
}
if(n-2 >= 0){
if( s[n-2] != '0'){
if(s[n-2] != '1'){
str = ch[s[n-2]-'0'] + "拾" + str;
}else{
str = "拾" + str;
}
}else if(str.length() != 0 && str.rfind("零",0) != 0){ // 不要连续零
str = "零" + str;
}
}
if(n-3 >= 0){
if(s[n-3] != '0'){
str = ch[s[n-3]-'0'] + "佰" + str;
}else if(str.length() != 0 && str.rfind("零",0) != 0){ // 不要连续零
str = "零" + str;
}
}
if(n-4 >= 0){
if(s[n-4] != '0'){
str = ch[s[n-4]-'0'] + "仟" + str;
}else if(str.length() != 0 && str.rfind("零",0) != 0){ // 不要连续零
str = "零" + str;
}
}
return str;
}
int main(){
char s[20];
while(~scanf("%s",s)){
int n = strlen(s);
// 是否 整数 和 角 分
bool zheng = s[n-1] == '0' && s[n-2] == '0';
string res = zheng ? "整" : "";
if(s[n-1] != '0'){
res = ch[s[n-1]-'0'] + "分" + res;
}
if(s[n-2] != '0'){
res = ch[s[n-2]-'0'] + "角" + res;
}
// 整数部分
string ywy[] = {"元","万","亿"}; // 四个一组的单位
int itr = 0;
for(int i = n - 4;i >= 0;i-=4){
string s4 = ""; // 4个数一组
for(int j = 0;j < 4 && i-j>=0;j++){
s4 = s[i-j] + s4;
}
string cs = chstr(s4); // 转换成 字符
if(cs.length() > 0){ // 为空不输出单位
res = cs + ywy[itr++] + res;
}
}
cout<<"人民币"<<res<<endl;
}
return 0;
}
复杂度分析
时间复杂度: 对于每一个位置,相关操作次数为常数次,所以总时间复杂度为
空间复杂度: 主要空间消耗在读入和生成的字符串,所以空间复杂度为
输出时合并零
对于上面的过程,还可以简化处理中的零处理,在过程中,只关心是不是4个连续中的末尾0链接。对于中间的零,均记为零
最后输出时再忽略掉连续的零。
因为string中的中文十分难取,所以这里改用 deque 来记录字符串,方便比较相邻的中文。
代码
#include<bits/stdc++.h>
using namespace std;
string ch[] = {
"零",
"壹",
"贰",
"叁",
"肆",
"伍",
"陆",
"柒",
"捌",
"玖"
};
deque<string> chstr(string s){
deque<string> res;
int n = s.length();
if(s[n-1] != '0'){
res.push_front(ch[s[n-1]-'0']);
}
if(n-2 >= 0){
if( s[n-2] != '0'){
res.push_front("拾");
if(s[n-2] != '1'){
res.push_front(ch[s[n-2]-'0']);
}
}else if(res.size()){ // 只考虑 是否和末尾的零连续
res.push_front("零");
}
}
if(n-3 >= 0){
if(s[n-3] != '0'){
res.push_front("佰");
res.push_front(ch[s[n-3]-'0']);
}else if(res.size()){ // 只考虑 是否和末尾的零连续
res.push_front("零");
}
}
if(n-4 >= 0){
if(s[n-4] != '0'){
res.push_front("仟");
res.push_front(ch[s[n-4]-'0']);
}else if(res.size()){ // 只考虑 是否和末尾的零连续
res.push_front("零");
}
}
return res;
}
int main(){
char s[20];
while(~scanf("%s",s)){
int n = strlen(s);
// 是否 整数 和 角 分
deque<string> res;
if(s[n-1] == '0' && s[n-2] == '0'){
res.push_back("整");
}
if(s[n-1] != '0'){
res.push_front("分");
res.push_front(ch[s[n-1]-'0']);
}
if(s[n-2] != '0'){
res.push_front("角");
res.push_front(ch[s[n-2]-'0']);
}
// 整数部分
string ywy[] = {"元","万","亿"};
int itr = 0;
for(int i = n - 4;i >= 0;i-=4){
string s4 = ""; // 4个数一组
for(int j = 0;j < 4 && i-j>=0;j++){
s4 = s[i-j] + s4;
}
auto cs = chstr(s4);
if(cs.size() > 0){
res.push_front(ywy[itr++]);
for(int i = cs.size()-1;i>=0;i--){
res.push_front(cs[i]);
};
}
}
cout<<"人民币";
for(int i = 0;i<res.size();i++){
if(i > 1 && res[i] == res[i-1] && res[i] == "零"){ // 去掉连续的零
continue;
}
cout<<res[i];
}
cout<<endl;
}
return 0;
}
复杂度分析
时间复杂度: 对于每一个位置,相关操作次数为常数次,所以总时间复杂度为
空间复杂度: 主要空间消耗在读入和生成的字符串,所以空间复杂度为