题目的主要信息:

  • 1、中文大写金额数字前应标明“人民币”字样。中文大写金额数字应用壹、贰、叁、肆、伍、陆、柒、捌、玖、拾、佰、仟、万、亿、元、角、分、零、整等字样填写。
  • 2、中文大写金额数字到“元”为止的,在“元”之后,应写“整字,如532.00应写成“人民币伍佰叁拾贰元整”。在”角“和”分“后面不写”整字。
  • 3、阿拉伯数字中间有“0”时,中文大写要写“零”字,阿拉伯数字中间连续有几个“0”时,中文大写金额中间只写一个“零”字,如6007.14,应写成“人民币陆仟零柒元壹角肆分“。
  • 4、10应写作“拾”,100应写作“壹佰”。例如,1010.00应写作“人民币壹仟零拾元整”,110.00应写作“人民币壹佰拾元整”
  • 5、十万以上的数字接千不用加“零”,例如,30105000.00应写作“人民币叁仟零拾万伍仟元整”

方法一:

用calPart1函数将整数部分转为中文,用calPart2函数将角分转为中文。calPart1的原理是,遍历一遍整数部分字符串,i表示当前字符在整数中的位数。如果当前字符不为'0',且当前位置不是10位,则转为中文;如果当前位置不是个位,则需要添加亿、万、仟等单位。当前位位数大于8位为亿位,大于4位为万位,第3位为千位,第2位为百位,第一位1为十位。转换过程中需要特别注意"零"的使用。

calPart2的原理是判断角位、分位是否位0,如果不为0转换为中文。需要注意的是如果整数部分为0,不需要加上"元"。 整个过程用res字符串暂存转换结果。 alt 具体做法:

#include <iostream>
using namespace std;
string gewei[10] = {"", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
string res;

void calPart1(string str){
    for(int i = str.size() - 1, j = 0; i >= 0; i--, j++){ //i表示这是数字的第几位,j表示字符串下标
        if(str[j] != '0'){//将当前位置的数字转为中文
            if(!(str[j] == '1' && i % 4 == 1)) //10应写作“拾”
                res += gewei[str[j] - '0'];
        }
        if(i != 0){//当前不是个位
            if(i % 8 == 0 && i >= 8){ //亿位
                res += "亿";
            }
            if(i % 4 == 0 && i % 8 != 0){ //万位
                res += "万";
                if(str[j + 1] == '0') //如果千位为0
                    res += "零";
            }
            if(i % 4 == 3 && str[j] != '0'){ //千
                res += "仟";
                if(str[j + 1] == '0' && str[j + 2] != '0') //百位为0
                    res += "零";
            }
            if(i % 4 == 2 && str[j] != '0'){ //百
                res += "佰";
                if(str[j + 1] == '0' && str[j + 2] != '0') //十位为0
                    res += "零";
            }
            if(i % 4 == 1 && str[j] != '0') //十位
                res += "拾";
        }
    }
}
//小数点之后的部分转换
void calPart2(string str){
    if(str == "00")
    {
        res += "整";
        return;
    }
    if (str[0] > '0')
    {
        res += gewei[str[0]-'0'] + "角";
    }
    if (str[1] > '0')
    {
        res += gewei[str[1]-'0'] + "分";
    }
    return;
}
//主函数 
int main()
{
    string str;
    while(getline(cin, str))
    {
        //获取小数点的位置
        int index = str.find('.');
        //获取小数点前的子字符串
        string str1 = str.substr(0, index);
        //获取小数点后的子字符串
        string str2 = str.substr(index + 1);
        //输出人民币
        cout << "人民币";
        //输出元钱
        calPart1(str1);
        //输出角分零钱
        if(str1!="0"){
            res += "元";
        }
        calPart2(str2);
        //换行
        cout << res << endl;
        res.clear();
    }
    return 0;
}

复杂度分析:

  • 时间复杂度:O(n)O(n),需要遍历一遍字符串。
  • 空间复杂度:O(1)O(1),只用了常数空间。

方法二:

将输入的数字转化int整数部分和小数点部分。首先对整数的大小进行判断,如果数字是0-9或者10-19、20-99可以直接逐位判断转换;如果数字大于100,我们判断先输出千位及以下的内容,然后对剩余的高位进行递归。

对于小数部分,是判断角位、分位是否位0,如果不为0转换为中文。需要注意的是如果小数部分为0,需要加上"整"。

具体做法:

#include<iostream>
#include<string>
#include<vector>
using namespace std;
const vector<string> helper1 = {"零","壹","贰","叁","肆","伍","陆","柒","捌","玖"};
const vector<string> helper2 = {"元", "万", "亿"};
const vector<string> helper3 = {"", "拾", "佰", "仟"};
string parts(int num)
{
    string str;
    if(num > 0 && num <= 9)
        str += helper1[num];
    else if(num >= 10 && num <= 19)
    {
        if(num % 10 == 0)
            str += helper3[1];
        else
            str += helper3[1] + helper1[num%10];
    }
    else if(num >= 20 && num <= 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] + parts(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] + parts(num % 1000);
        else
            str += helper1[num/1000] + helper3[3] + parts(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 += parts(vec[i]);
            res += helper2[i];
            if (i != 0 && i - 1 >= 0 && vec[i - 1] <= 999 && vec[i - 1] != 0)
                res += helper1[0];
        }
        // 第二步处理小数
        int deci = static_cast<int>((money - static_cast<int>(money)) * 100);
        if (deci == 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),递归需要遍历一遍字符串。
  • 空间复杂度:O(1)O(1),只用了常数空间。