> 文档中心 > 《C语言》罗马数字问题

《C语言》罗马数字问题


一.罗马数字

罗马数字是最早的数字表示方式,比阿拉伯数字早2000多年,起源于罗马。

如今我们最常见的罗马数字就是钟表的表盘符号:Ⅰ, Ⅱ , Ⅲ ,Ⅳ(IIII),Ⅴ ,Ⅵ ,Ⅶ ,Ⅷ ,Ⅸ ,Ⅹ ,Ⅺ ,Ⅻ ……

对应阿拉伯数字(就是现在国际通用的数字),就是1,2,3,4,5,6,7,8,9,10,11,12。(注:阿拉伯数字其实是古代印度人发明的,后来由阿拉伯人传入欧洲,被欧洲人误称为阿拉伯数字。)

基本字符

I

V

X

L

C

D

M

相应的阿拉伯数字表示为

1

5

10

50

100

500

1000

  1. 相同的数字连写,所表示的数等于这些数字相加得到的数,如:Ⅲ = 3;

  2. 小的数字在大的数字的右边,所表示的数等于这些数字相加得到的数, 如:Ⅷ = 8;Ⅻ = 12;

  3. 小的数字,(限于Ⅰ、X 和C)在大的数字的左边,所表示的数等于大数减小数得到的数,如:Ⅳ= 4;Ⅸ= 9;

  4. 正常使用时,连写的数字重复不得超过三次。(表盘上的四点钟“IIII”例外)(注:现使用IV代表4)

  5. 在一个数的上面画一条横线,表示这个数扩大1000倍。

二. 罗马数字转整数(Roman to Integer

1.思路: 

一般来说,罗马数字中小的数字在大的数字的右边。那么只需要累加就可以。

例如:XVI  可视作 X+V+I=10+5+1=16;

若存在数字小的在大的数字左边的情况,我们需要根据规则减去小的数字。

例如:XIV 可视作 X-I+V=10-1+5=14. 

#include#includemain(){    char s[] = "XVI";  //定义了一个字符串    int symbolvalues[26];     //26为数组的长度,因为一共26个英文字母所以大小不超过26    symbolvalues['I' - 'A'] = 1;    symbolvalues['V' - 'A'] = 5;    symbolvalues['X' - 'A'] = 10;    symbolvalues['L' - 'A'] = 50;    symbolvalues['C' - 'A'] = 100;    symbolvalues['D' - 'A'] = 500;    symbolvalues['M' - 'A'] = 1000;    int sum = 0; int n = strlen(s);  //n为字符串s的长度    for (int i = 0; i < n; i++)    { int number = symbolvalues[s[i] - 'A'];     //先找一个数字作为后续判断的标准 if (i < n - 1 && number < symbolvalues[s[i + 1] - 'A']) {     sum -= number;    //如果数字小的在大的数字左边的情况则相减 } else  sum += number;    }    printf("%d", sum);}

2.习题练习 :https://leetcode-cn.com/problems/roman-to-integer/https://leetcode-cn.com/problems/roman-to-integer/

以下几种方法核心思路一样

代码1:

int romanToInt(char * s){int symbolvalues[26];     //共26个英文字母其大小不超过26,所以数组长度为26symbolvalues['I'-'A']=1;symbolvalues['V'-'A']=5;symbolvalues['X'-'A']=10;symbolvalues['L'-'A']=50;symbolvalues['C'-'A']=100;symbolvalues['D'-'A']=500;symbolvalues['M'-'A']=1000;int sum=0;int n=strlen(s);      //n为字符串s的长度for(int i=0;i<n;i++){    int number=symbolvalues[s[i]-'A'];   //定义number是为了与symbolvalues[s[i+1]-'A']作比较    if(i<n-1&&number<symbolvalues[s[i+1]-'A'])  {sum-=number;}  else  sum+=number;}return sum;}

代码2.

int romanToInt(char * s){int sum= 0;while (*s){ //当出现I、X、C三个字符时,如果右边是对应的特殊情况,就相应减法。if (*s == 'V')  sum += 5;//当不是特殊情况时,直接加法即可以else if (*s == 'L')    sum += 50;else if (*s == 'D')    sum += 500;else if (*s == 'M')    sum += 1000;else if (*s == 'I')sum = (*(s + 1) == 'V' || *(s + 1) == 'X') ? sum - 1 : sum + 1;else if (*s == 'X')sum = (*(s + 1) == 'L' || *(s + 1) == 'C') ? sum - 10 : sum + 10;else if(*s=='C')sum = (*(s + 1) == 'D' || *(s + 1) == 'M') ? sum - 100 : sum + 100;s++;}return sum;}

三.整数转罗马数字(Integer to Roman

1.思路:先举生活一个小栗子:在以前还使用现金购物的时候,找零钱的时候一般商家会尽量选择面值大的纸币(硬币)给顾客,这样才会使得给顾客的纸币(硬币)张数最少,让顾客点钱的时候更方便。

    为了表示给的的整数num,我们寻找不超过num的最大符号值,将num减去该符号值,并用该符号拼接(下面代码所用的strcpy,或者也可以用strcat)在上一个找到的符号之后,循环直到为0的时候结束过程。

建立一个数值-符号对的列表valueSymbols,(类似于哈希表按数值从大到小排列。遍历valueSymbols中的每个数值-符号对,若当前数值value不超过num,则从num中不断减去value,直至num小于value,然后遍历下一个数值-符号对。若遍历中num为0则跳出循环。

例如:16

1.16<1000  16<900……1610,刚好对应symbols的X,故16-10=6;

2.65,故6-5=1,

3.1<4,继续遍历1=1   1-1=0结果为0,跳出循环。

所以16=X+V+Ⅰ。

代码如下 

#include#include#include#pragma warning(disable:4996)main(){    int values[] = { 1000,900,500,400,100,90,50,40,10,9,5,4,1 }; //定义了一个整数数组    char* symbols[] = { "M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I" };  //罗马数字数组    int num = 16;      //假设num为16,当然可以定义为其他的数字 char* roman = malloc(sizeof(char) * 16);   //开辟了一个字符数组 roman[0] = '\0';      //字符数组初始化 for (int i = 0; i = values[i])     {  num -= values[i];  strcpy(roman + strlen(roman), symbols[i]);//strcpy表示将字符复制到另一个字符里     }     if (num == 0)     //如果num为0说明所有罗马数字已经都变换完成     {  break;     } } for (int i = 0; i<strlen(roman); i++) {     printf("%c", roman[i]); }}

2. 习题练习 :https://leetcode-cn.com/problems/integer-to-roman/https://leetcode-cn.com/problems/integer-to-roman/

代码1. 

char * intToRoman(int num){int values[]={1000,900,500,400,100,90,50,40,10,9,5,4,1};char *symbols[]={"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};char*Roman=(char*)malloc(sizeof(char)*25);Roman[0]='\0';for(int i=0;i=values[i])    { num-=values[i]; strcat(Roman,symbols[i]);//strcat为了字符的连接 //  strcpy(Roman+strlen(Roman),symbols[i]);  或者使用strcpy if(num==0)break;    }}return Roman;}

代码2.

比如输入是 2341,我们找到 2000300,40,1,而得到2000,300,40,1的方法就是利用取余

char * intToRoman(int num){ char* thousands[] = {"", "M", "MM", "MMM"}; char* hundreds[] = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"}; char* tens[] = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"}; char* ones[] = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};char*roman=(char*)malloc(sizeof(char)*16);roman[0]='\0';strcpy(roman+strlen(roman),thousands[num/1000]);strcpy(roman+strlen(roman),hundreds[num%1000/100]);strcpy(roman+strlen(roman),tens[num%1000%100/10]);strcpy(roman+strlen(roman),ones[num%1000%100%10]);return roman;}