题意

题目直接就是题意

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;
}

复杂度分析

时间复杂度: 对于每一个位置,相关操作次数为常数次,所以总时间复杂度为O(n)O(n)

空间复杂度: 主要空间消耗在读入和生成的字符串,所以空间复杂度为O(n)O(n)

输出时合并零

对于上面的过程,还可以简化处理中的零处理,在过程中,只关心是不是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;
}

复杂度分析

时间复杂度: 对于每一个位置,相关操作次数为常数次,所以总时间复杂度为O(n)O(n)

空间复杂度: 主要空间消耗在读入和生成的字符串,所以空间复杂度为O(n)O(n)