欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

C语言中的罗马数字转换问题

最编程 2024-07-29 17:39:42
...

本文已参与[新人创作礼]活动,一起开启掘金创作之路

一.罗马数字

罗马 数字是最早的数字表示方式,比 阿拉伯数字 早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<stdio.h>
#include<string.h>
main()
{
    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.习题练习 :leetcode-cn.com/problems/ro…https://leetcode-cn.com/problems/roman-to-integer/

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

代码1:

int romanToInt(char * s){
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'];   //定义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……16<40  ,继续遍历,发现16>10,刚好对应symbols的X,故16-10=6;

2.6<9,继续遍历6>5,故6-5=1,

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

所以16=X+V+Ⅰ。

代码如下

#include<stdio.h>
#include<string.h>
#include<malloc.h>
#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 < 13; i++)
        {
            while (num >= 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. 习题练习 :leetcode-cn.com/problems/in…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<13;i++)
{
    while(num>=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;
}

推荐阅读