题目大意:
按照中文发音规则输出一个绝对值在9位以内的整数。
算法思路:
此题考察的细节主要在ling
和Wan
的输出上,由于只有9位,那么最高位只会到达亿。那么首先使用units
数组存放每一位数字的单位(从个、十、百到亿),由于万,十万,百万,千万的单位每一个都有万字,但是在输出的时候只有该组数位中不为0的数字对应的最小单位才会带上万输出,所以,这里在units[4]
存储Wan,其他位只存储十,百,千。同时使用nums
数组存储所有的数字对应的中文拼音,下标(int
)和数字(string
)为一一对应关系。由于这里由于万位数字的特殊处理关系,将数字分为三个部分:
1、个、十、百、千,也就是从右往左第一个到第四个数字
2、万、十万、百万、千万,也就是从右往左第五个到第八个数字
3、亿,也就是从右往左第九个数字
那么我们首先将数字N转存到数组digits
中,其顺序恰好是逆序,这样我们从左往右按照每一个部分进行处理。对于万位数字的处理,我们使用is_first_wan
变量记录当前的万位数字是否是出现的第一个万位数字,如果是,那么得添加Wan。这里为了更加方便的处理ling
的输出,得先进行预处理,首先我们注意到,只要2个不为0的数字距离相差大于1的不管中间有几个0存在,最后都只会输出一个ling
,所以,我们使用数组non_zero
和non_zero_index
分别保存digits
数组中不为0的数字以及其在digits
中的下标位置,这里不采用hash
的方法来记录位置和对应的值是因为不同数位上的数字会出现重复。接着就是遍历non_zero
数组,处理所有的不为0的数字,使用vector<string> result
保存最后的结果
个、十、百、千位的处理:
1、如果不是第一位不为0的数字,并且与上一位数字的位置相差大于1,我们首先添加ling
(result.push_back(nums[0])
)
2、如果当前位是个位,只添加对应的数字result.push_back(nums[non_zero[j]])
,如果不是,得先添加单位result.push_back(units[non_zero_index[j]])
万、十万、百万、千万位的处理:
1、如果不是第一位不为0的数字,并且与上一位数字的位置相差大于1,我们首先添加ling
(result.push_back(nums[0])
)
2、如果是第一次出现万位数字,首先得添加一个Wan
,然后让is_first_wan
为false
;
3、如果当前位数字恰好为第五个(也就是万),那么一定是第一次出现的,所以只需要添加数字即可,否则就得添加上十,百,千补全单位,然后再添加数字
亿位的处理:
1、如果不是第一位不为0的数字,并且与上一位数字的位置相差大于1,我们首先添加ling
(result.push_back(nums[0])
)
2、先添加单位,然后添加数字。
从上面可以看到由于都需要处理0,于是可以将该步骤抽取出来作为公共代码部分。
核心处理逻辑代码如下:
for (int j = 0; j < non_zero_p; ++j) {
// 首选处理数字0
if(j!=0&&(non_zero_index[j]-non_zero_index[j-1])>1){
// 不是个位数字,并且与上一位数字的位置相差大于1
result.push_back(nums[0]);//添加一个0
}
if(non_zero_index[j]<4){
// 个、十、百、千位
if(non_zero_index[j]!=0){// 个位的单位不能添加,因为""也会输出一个空格,测试点0和4考察
result.push_back(units[non_zero_index[j]]);
}
result.push_back(nums[non_zero[j]]);
} else if(non_zero_index[j]<8) {
// 万、十万、百万、千万位
if(is_first_wan){
// 第一次出现万位及其以上的情况
result.push_back(units[4]);//添加一个Wan
is_first_wan = false;
}
if(non_zero_index[j]!=4){
// 十万、百万、千万位需要在万前面添加十、百、千
result.push_back(units[non_zero_index[j]]);
}
//最后添加数字
result.push_back(nums[non_zero[j]]);
} else {
// 亿位
result.push_back(units[non_zero_index[j]]);
result.push_back(nums[non_zero[j]]);
}
}
符号的处理:对于负数,在最后添加一个Fu即可
result的输出:逆序输出,对于i>0的情况,得输出空格。
注意点:
1、如果在个位添加了单位,也就是字符串数组中添加了"",会输出多余的空格,测试点0和测试点4就会出现格式错误
2、边界数据0,应当直接输出ling,测试点3考察
3、测试点1错误的可以考虑如下数据:808808808,ba Shi Wan后面不需要再输出ling,而是直接输出ba Qian
给出一组测试数据:
808080808 ba Yi ling ba Bai ling ba Wan ling ba Bai ling ba
-880808080 Fu ba Yi ba Qian ling ba Shi Wan ling ba Qian ling ba Shi
800000008 ba Yi ling ba
800000000 ba Yi
80000008 ba Qian Wan ling ba
80008000 ba Qian Wan ling ba Qian
80000000 ba Qian Wan
提交结果:
AC代码:
#include <cstdio>
#include <string>
#include <vector>
using namespace std;
int main()
{
string units[9] = {"","Shi","Bai","Qian","Wan","Shi","Bai","Qian","Yi"};
string nums[10] = {"ling","yi","er","san","si","wu","liu","qi","ba","jiu"};
int N;
int digits[10];
int index = 0;//digits的工作指针
scanf("%d",&N);
int n = N;
if(n<0){
n = -n;
}
if(n==0) {
// 0特判
printf("ling");
return 0;
}
//将n的每一位使用digits数组存储
while (n!=0){
digits[index++] = n%10;
n /= 10;
}
// 从左到右遍历digits数组(也即是从后往前遍历数字的每一位),记录所有不为0的数字及其位置
int non_zero[10];// 保存所有不为0的数字
int non_zero_index[10];// 保存所有不为0数字对应的下标
int non_zero_p = 0;//non_zero的工作指针
for (int i = 0; i < index; ++i) {
if(digits[i]!=0){
non_zero[non_zero_p] = digits[i];
non_zero_index[non_zero_p] = i;
++non_zero_p;
}
}
//遍历non_zero数组,处理所有的不为0的数字
vector<string> result;// 保存结果集合
bool is_first_wan = true;//判断是否已经添加了Wan
for (int j = 0; j < non_zero_p; ++j) {
// 首选处理数字0
if(j!=0&&(non_zero_index[j]-non_zero_index[j-1])>1){
// 不是个位数字,并且与上一位数字的位置相差大于1
result.push_back(nums[0]);//添加一个0
}
if(non_zero_index[j]<4){
// 个、十、百、千位
if(non_zero_index[j]!=0){// 个位的单位不能添加,因为""也会输出一个空格,测试点0和4考察
result.push_back(units[non_zero_index[j]]);
}
result.push_back(nums[non_zero[j]]);
} else if(non_zero_index[j]<8) {
// 万、十万、百万、千万位
if(is_first_wan){
// 第一次出现万位及其以上的情况
result.push_back(units[4]);//添加一个Wan
is_first_wan = false;
}
if(non_zero_index[j]!=4){
// 十万、百万、千万位需要在万前面添加十、百、千
result.push_back(units[non_zero_index[j]]);
}
//最后添加数字
result.push_back(nums[non_zero[j]]);
} else {
// 亿位
result.push_back(units[non_zero_index[j]]);
result.push_back(nums[non_zero[j]]);
}
}
if(N<0) {
result.emplace_back("Fu");
}
for (int i=result.size()-1;i>=0;--i) {
printf("%s",result[i].c_str());
if(i>0) printf(" ");
}
return 0;
}
在这里给出自己之前写的另外一种实现方式,现在回过头来看自己都觉得奇怪(☺️),使用一个字符串而不是字符串数组保存了最后的结果,这也就导致了该代码中的所有的字符串都是逆序显示的。
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
using namespace std;
/*
题目要求:给一个9位以内的数字,根据中文的发音规则进行输出对应的拼音
算法思路:首先想到的就是得从右往左进行处理,所以将数字判断完是正负后,取其正数转化为字符串然后逆置,其次就是获取从左往右的每一个不为0的数字的位置
使用数组notZero保存,然后遍历notZero,对于每一个不为0的数字需要特殊判断的只有一种情况
1)若当前数字的所在位置在4~7之间,也就是万位到千万位之间,并且是第一个不为0的数字就得添加“万”
1.如果当前位置为4,也就是万位本身,就只需再添加数字即可
2.若当前位置不是4,也就是十万、百万、千万,需要添加单位和数字
2)若当前数字所在位置不是4~7或者不是第一个4~7之间的数字,直接添加单位和数字即可
3)对于当前不为0的数字的位置和下一个不为0的数字的位置如果相差大与1的话说明有若干个0在其中,得添加一个ling
注意:
1.得先添加单位和数字然后再添加0,顺序不能颠倒
2.添加一律采取字符串的形式添加,先添加空格再添加单位和数字
3.最后在逆置结果字符串前得去除前导空格,然后再逆置
4.不要忘记添加符号
5.如果数据为0,直接输出ling即可
*/
//这里的每一个单位和数字都是倒过来写的,是因为在将结果用的是一个字符串从右往左添加,然后逆置后输出,只好将其倒过来写了
//也可以使用string数组,然后写个倒序的函数将其逆置
string unit[9] = {"","ihS","iaB","naiQ","naW","ihS","iaB","naiQ","iY"};//根据数字从右往左依次匹配单位,在4~7之间的数字最后的得加上"万"
string number[10] = {"gnil","iy","re","nas","is","uw","uil","iq","ab","uij"};
int notZero[10]={0};
int num = 0;//统计不为0的个数
int main(){
int a;
cin>>a;
bool flag = true;//表示该数为正数
if(a<0){
flag = false;
a = -a;
}
if(a==0){//0直接输出ling然后结束
cout<<"ling";
return 0 ;
}
string t = to_string(a);
reverse(t.begin(),t.end());//将t进行逆置,方便从个位进行依次添加单位个数字
bool isfirst = true;//表示第一次进入4~7之间,标识了添加"万"的时机
int len = t.size();
for(int i=0;i<len;++i){//找到数字所有不为0的位置
if(t[i]!='0'){
notZero[num++] = i;
}
}
string result = "";//保存最后结果
for(int i=0;i<num;++i){
if(notZero[i]>=4&¬Zero[i]<=7&&isfirst){//第一次进入到万到千万的位置得添加“万”
result += " "+unit[4];//添加万
if(notZero[i]==4){//当前为万位,只需添加数字即可
result += " "+number[t[notZero[i]]-'0'];
}else{
result += " "+unit[notZero[i]]+" "+number[t[notZero[i]]-'0'];//不是万位,为十万、百万或者千万位得添加单位和数字
}
isfirst = false;
}else{//不是4~7之间的数字或者不是第一次进入到万到千万的位置
result += " "+unit[notZero[i]]+" "+number[t[notZero[i]]-'0'];//添加单位和数字即可
}
if(i<num-1&¬Zero[i+1]-notZero[i]>1){//说明2个最近的不为0的数字的位置相差大于1,得添加0
result += " "+number[0];
}
}
if(!flag){
result += " uF";//添加负号
}
result.erase(0,result.find_first_not_of(" "));//取出前导空格,也就是最后结果末尾的空格,使用substr()好像不太管用
reverse(result.begin(),result.end());//逆置为最终结果
cout<<result<<endl;
return 0;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。