题解 | #人民币转换# 前后缀分治,递归处理
人民币转换
http://www.nowcoder.com/practice/00ffd656b9604d1998e966d555005a4b
思想
对于给定字符串,按照 亿、万、仟、佰、拾 依次根据字符串长度找到最高级别单位划分前后缀,递归处理。
举例
12031,0200,3002
我们先考虑没有小数的情况(小数很简单最后处理)。
len = 13 ,13 - 1对8整除商大于0,所以最高位是亿。那么答案必然是 xxx亿xxx.(减1是因为我们只判断最高位后面的字符串长度)
此时我们对原字符串划分前后缀,依次递归判断:
prefix = 12031
suffix = 02003002
前后缀最高级别单位是万.
细节处理
- 零的处理
当某一段全为零时,如50000,前缀5 + 单位万 + 后缀0000. 后缀全为0,我们直接全部略过。
当某一段的前半段为零,后半段存在非零的数时,如50050,前缀5 + 单位万 + 后缀0050. 此时从后缀第一个零开始到第一个非零数,只取一个零。
问题来了,因为我们是递归处理,会将后缀 0050划分成 零千零百五十。所以我们必须在进入后缀递归之前处理这一段零。即:
前缀5(递归处理) + 单位万 + 零(处理零)+ 后缀50(递归处理)。 - "壹拾"的处理
根据题意,需要将所得答案中的所有“壹拾”换成“拾”。 - 其余部分处理起来很简单,请直接看代码。
my solution
#include <bits/stdc++.h>
using namespace std;
const int N = 10;
string NUMS[N] = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
string res;
inline bool contains_only_zero(string &s)
{
bool res = true;
for (int i = 0; i < s.size(); i++) {
if (s[i] != '0') {
res = false;
break;
}
}
return res;
}
inline void handle_suffix_zero(string &suf)
{
if (res.size() > 1 && suf[0] == '0' && !contains_only_zero(suf)) res += "零";
int i = 0;
for (; i < suf.size() && suf[i] == '0'; i++);
suf = suf.substr(i, suf.size() - i);
}
void dfs(string &zz)
{
if (contains_only_zero(zz) || !zz.size()) { // if zz only 0
return;
}
int l = zz.size() - 1;
if (!l) {
//cout << NUMS[zz[0] - '0'];
res += NUMS[zz[0] - '0'];
return;
}
int y = (int) l / 8;
if (y > 0) {
string pre = zz.substr(0, zz.size() - 8);
dfs(pre);
//cout << "亿";
res += "亿";
string suf = zz.substr(pre.size(), 8);
handle_suffix_zero(suf);
//cout << suf << endl;
dfs(suf);
return;
}
int w = (int) l / 4;
if (w > 0) {
string pre = zz.substr(0, zz.size() - 4);
dfs(pre);
//cout << "万";
res += "万";
string suf = zz.substr(pre.size(), 4);
handle_suffix_zero(suf);
//cout << suf << endl;
dfs(suf);
return;
}
int q = (int) l / 3;
if (q > 0) {
string pre = zz.substr(0, zz.size() - 3);
dfs(pre);
//cout << "仟";
res += "仟";
string suf = zz.substr(pre.size(), 3);
handle_suffix_zero(suf);
//cout << suf << endl;
dfs(suf);
return;
}
int b = (int) l / 2;
if (b > 0) {
string pre = zz.substr(0, zz.size() - 2);
dfs(pre);
//cout << "佰";
res += "佰";
string suf = zz.substr(pre.size(), 2);
handle_suffix_zero(suf);
//cout << suf << endl;
dfs(suf);
return;
}
int s = (int) l / 1;
if (s > 0) {
string pre = zz.substr(0, zz.size() - 1);
dfs(pre);
//cout << "拾";
res += "拾";
string suf = zz.substr(pre.size(), 1);
handle_suffix_zero(suf);
//cout << suf << endl;
dfs(suf);
return;
}
}
inline void helper(string &zz, string &xx)
{
// 处理“壹拾“问题。当它出现在首部或者前面跟0时,仅用“拾”,其他情况用“壹拾”
for (size_t a = res.find("壹拾"); a != res.npos; a = res.find("壹拾"))
res.replace(res.find("壹拾"), strlen("壹拾"), "拾");
res = "人民币" + res;
if (res != "人民币")
res += "元";
if (xx == "" || contains_only_zero(xx)) {
res += "整";
}
else { // 处理小数部分
for (int i = 0; i < xx.size(); i++) {
if (xx[i] == '0') continue;
res += NUMS[xx[i] - '0'];
if (!i) res += "角";
else res += "分";
}
}
}
void solve(string s)
{
string zz = "", xx = "";
bool is_x = false;
for (int i = 0; i < s.size(); i++) {
if (s[i] == '.') {
is_x = true;
continue;
}
if (is_x) xx += s[i];
else zz += s[i];
}
dfs(zz);
helper(zz, xx);
cout << res << endl;
}
int main()
{
cin.tie(0)->sync_with_stdio(false);
string s;
for (; cin >> s; res = "")
solve(s);
return 0;
} 
查看9道真题和解析