题目的主要信息:

  • 将输入的两位小数的数字人民币转换成中文表示的人民币
  • 中文大写金额数字前应标明“人民币”字样
  • 中文大写金额数字应用壹、贰、叁、肆、伍、陆、柒、捌、玖、拾、佰、仟、万、亿、元、角、分、零、整等字样填写
  • 中文大写金额数字到“元”为止的,在“元”之后,应写“整字,如果小数为0
  • 阿拉伯数字中间有“0”时,中文大写要写“零”字,阿拉伯数字中间连续有几个“0”时,中文大写金额中间只写一个“零”字
  • 10应写作“拾”,100应写作“壹佰”
  • 十万以上的数字接千不用加“零”

方法一:迭代

具体做法:

我们用字符串的形式来接收输入的数字(和将输入的double型数字转变成字符串一样),然后遍历字符串找到小数点的位置,根据小数点的位置截取字符串的整数部分和小数部分。

对于整数部分,我们用jj表示字符串每个字符的下标,从0开始,用ii表示该字符位于这个数字的哪一位,从s.length() - 1开始,下标jj不断向右递增,而位数ii则相应递减。处理的时候我们依次处理,优先判断该位字符是否为0,不为0再输出,同时如果位数位于十位且该位为1,则不需要输出,因为我们不要壹拾。然后通过ii依次判断属于哪一位,根据所属哪一位输出相应的字符,如可以根据对8取余为0决定亿位,对4取余为0决定万位,对4取余为3决定千位,对4取余为2决定百位,对4取余为1决定十位,同时注意万千百后一位如果为零,需要接一个零。最后如果整数部分第一个字符就是0,那么就不用输出元了,没有整数部分,否则需要输出元。

对于小数部分,如果小数部分是两个0,则无小数,输出整,否则要相应判断小数角与分是否为0,输出或者不输出相应的项。

alt

#include<iostream>
#include<string>
#include<vector>
using namespace std;

const vector<string> num = {"","壹","贰","叁","肆","伍","陆","柒","捌","玖"};
int main(){
    string money;
    while(cin >> money){
        int p = 0;
        while(money[p] != '.') //根据小数点划分
            p++;
        string s = money.substr(0, p); //处理小数点前的
        string res = "人民币";
        for(int i = s.length() - 1, j = 0; i >= 0; i--, j++){ //i表示这是数字的第几位,j表示字符串下标
            if(s[j] != '0'){  //不为0要输出
                if(!(s[j] == '1' && i % 4 == 1)) //输出跳过一拾前面的1
                    res += num[s[j] - '0'];
            }
            if(i != 0){
                if(i % 8 == 0 && i >= 8) //处理输出亿位
                    res += "亿";
                if(i % 4 == 0 && i % 8 != 0){ //处理输出万位
                    res += "万";
                    if(s[j + 1] == '0') //处理千位为0的情况
                        res += "零";
                }
                if(i % 4 == 3 && s[j] != '0'){ //处理千位
                    res += "仟"; 
                    if(s[j + 1] == '0' && s[j + 2] != '0') //百位为0
                        res += "零";
                }
                if(i % 4 == 2 && s[j] != '0'){ //处理百位
                    res += "佰";
                    if(s[j + 1] == '0' && s[j + 2] != '0') //十位为0
                        res += "零";
                }
                if(i % 4 == 1 && s[j] != '0') //输出十位
                    res += "拾";
            }
        }
        if(s[0] != '0') //整数部分有才输出元
            res += "元";
        s = money.substr(p + 1); //处理小数部分
        if(s == "00") //小数全0,元整
            res += "整";
        else{
            if(s[0] == '0'){ //角为0
                res += num[s[1] - '0'];
                res += "分";
            }
            else if(s[1] == '0'){ //分为0
                res += num[s[0] - '0'];
                res += "角";
            }
            else{ //角和分都有
                res += num[s[0] - '0'] + "角";
                res += num[s[1] - '0'] + "分";
            }
        }
        cout << res << endl;
    }
    return 0;
}

复杂度分析:

  • 时间复杂度:O(n)O(n),其中nn为输入的字符串长度,遍历整个字符串
  • 空间复杂度:O(n)O(n),保存截取后的字符串长度最多为n3n-3,res输出属于必要字符串

方法二:递归

具体做法:

可以将输入的数字转化成int就去掉了小数部分,用全部减去整数部分再乘上100就得到小数部分。

对于整数部分,可以对万连除取余,每四位为1组进行运算,每次运算完之后添加相应标识字符。计算的时候我们分情况讨论,数字到底是几位数,对于多位数把整百整千输出以后,剩余部分作为子问题可以递归地进入函数继续计算。

对于小数部分,我们乘100之后,得到的角与分其实两位数,如果是1位数说明没有角,如果整十说明没有分,否则都可以用除法和取余获取角和分。

#include<iostream>
#include<string>
#include<vector>
using namespace std;

const vector<string> helper1 = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
const vector<string> helper2 = {"元", "万", "亿", "万亿"};
const vector<string> helper3 = {"", "拾", "佰", "仟"};

string function(int num){
    string str;
    if(num > 0 && num <= 9) //只有个位
        str += helper1[num];
    else if(num >= 10 && num <= 19){ //10到19
        if(num % 10 == 0) //整十
            str += helper3[1];
        else
            str += helper3[1] + helper1[num%10];
    }else if(num >= 20 && num <= 99){ //20到99
        if(num % 10 == 0) //整十
            str += helper1[num/10] + helper3[1];
        else
            str += helper1[num/10] + helper3[1] + helper1[num%10];
    }else if(num >= 100 && num <= 999){ //三位数
        if(num % 100 == 0) //整百
            str += helper1[num/100] + helper3[2];
        else if(num % 100 <= 9) //整十
            str += helper1[num/100] + helper1[0] + helper1[num%100];
        else //后续进入递归
            str += helper1[num/100] + helper3[2] + function(num % 100);
    }else if(num >= 1000 && num <= 9999){ //四位数
        if(num % 1000 == 0) //整千
            str += helper1[num/1000] + helper3[3];
        else if(num % 1000 <= 99)  //后续进入递归
            str += helper1[num/1000] + helper3[3] + helper1[0] + function(num % 1000);
        else //后续进入递归
            str += helper1[num/1000] + helper3[3] + function(num % 1000);
    }
    return str;
}

int main(){
    double money;
    while (cin >> money){
        money += 0.0001; // 此处+0.0001防止double转换int产生误差
        int data = static_cast<int>(money); //处理整数
        vector<int> vec;
        string res = "人民币";
        while(data){
            vec.push_back(data % 10000); //四位一组
            data /= 10000;
        }
        for(int i = vec.size() - 1; i >= 0; i--){
            res += function(vec[i]); //从最高得4位得开始加
            res += helper2[i]; //添加亿万等字符
            if (i != 0 && i - 1 >= 0 && vec[i - 1] <= 999 && vec[i - 1] != 0)
                res += helper1[0]; //添加后一位为0的情况
        }
        int deci = static_cast<int>((money - static_cast<int>(money)) * 100);// 第二步处理小数
        if(deci == 0) //小数部分为0
            res += "整";
        else if(deci < 10) //没有角
            res += helper1[deci] + "分";
        else if(deci % 10 == 0) //没有分
            res += helper1[deci / 10] + "角";
        else //分角都有
            res += helper1[deci / 10] + "角" + helper1[deci % 10] + "分";
        cout << res << endl;
    }
    return 0;
}

复杂度分析:

  • 时间复杂度:O(n)O(n),其中nn为输入数字的位数,递归需要遍历所有位数
  • 空间复杂度:O(1)O(1),记录的临时数组都是常数空间