一、题目描述
1.题目内容
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给你一个整数,将其转为罗马数字。
原题链接:https://leetcode.cn/problems/integer-to-roman/
对应相反的题为LeetCode13:罗马数字转整数,可参考https://blog.csdn.net/qq_43665602/article/details/127307596
2.样例
二、解决方案
举几个例子先:
例1: 输入整数为num=3999,分析其计算过程: 3999=3000+900+90+9
其中3000=1000+1000+1000,而1000=M,900=CM,90=XC,9=IX
所以3000=MMM,3999=MMMCMXCIX例2:输入整数为num=738,分析其计算过程:738=700+30+8
其中700=500+200=500+100+100,30=10+10+10,而8=5+3=5+1+1+1
所以700=DCCXXXVIII
观察分析:
(1)在题目中给定基础罗马字符共7个,即I、V、X、L、C、D、M;特殊情况共6种,为IV、IX、XL、XC、CD、CM,并说明了这13种情况各自对应的数值为多少。因此我们在进行代码实现时一定要注意遇到这13种情况必须严格按照其映射关系来处理,比如500=D而不是CCCCC。
(2)此外,将题目要求的整数区间划分为[1,10],[10,100],[100,1000]三个区间。可以看到在每个区间之内,以5或者50、500作为一个临界点,比如[1,10]区间中,5作为临界点。当某个数大于对应临界点时则需要进行分解,比如num=600,500<num<1000,那么此时我们需要将num拆分为500+100,即600=500+100=MC,而不是600=CCCCCC。
所以可推出:
代码实现时情况分为两种:
- 属于事先说明的13种情况之一;
- 其他情况:在其他情况中,又分为两种子情况,通过此数值在对应区间是否超出临界点;
由此得到我们代码实现的算法流程:
- 构建事先说明的13种情况之间的映射关系(比如Python中用字典结构存储);
- 获取输入整数千百十个位,各自对应的数值,比如1338百位为3;
- 分别对该数的各位置进行处理,进行罗马字符转换:(1)对于千位数值,直接累计1000所对应的罗马字符即可;(2)对于百十个位数值,在他们对应区间需要考虑两种情况:1)对应整数是否为13种情况之一;2)此数值在对应区间是否超出临界点;比如字符串为s,整数num=1338百位为second_num=3,说明需要在s中添加300对应的罗马字符串CCC,而个位forth_num=8>5,则说明需要分别添加5和3对应的字符,即V和III,依次类推得到1338=MCCCXXXVIII。
1.Python代码
'''
LeetCode12:整数转罗马数字
'''
class Solution:
# 处理百十个位对应数字
def process_num(self,map_relation,num,level)->str:
s=''
if num==9 or num==4 or num==1 or num==5: # 13种情况之一
s+=map_relation[num*level]
else:
if num>5: # 超出临界点
s+=map_relation[5*level]
for i in range(0,num-5):
s+=map_relation[level]
else:
for i in range(0,num):
s+=map_relation[level]
return s
def intToRoman(self, num: int) -> str:
# 构造数值与对应罗马字符串之间的映射关系,使用字典存储
intKey = [1, 5, 10, 50, 100, 500, 1000,4,9,40,90,400,900]
romanValue = ["I", "V", "X", "L", "C", "D", "M","IV","IX","XL","XC","CD","CM"]
intToRoman ={}
for k in range(0,len(intKey)):
intToRoman[intKey[k]]=romanValue[k]
# 分别得到输入数字的千百十个位对应数字
first_num=int(num/1000)
second_num=int(num/100%10)
third_num=int(num/10%10)
forth_num=int(num%10)
# 分别处理千百十个位对应数值:
s=''
for i in range(0,first_num): # 处理千位数字
s+=intToRoman[1000]
s+=self.process_num(intToRoman,second_num,100)
s+=self.process_num(intToRoman,third_num,10)
s+=self.process_num(intToRoman,forth_num,1)
return s
if __name__=='__main__':
num=1994
# num=3
# num=500
# num=700
# num=250
# # num=5000
# # num=4
# num=3999
print(Solution().intToRoman(num))
2.Java代码
import java.util.HashMap;
import java.util.Map;
public class IntToRoman {
public static void main(String[] args) {
int num=1994;
Solution solution=new Solution();
System.out.println(solution.intToRoman(num));
}
}
class Solution{
// 处理百十个位对应数字
/*
level表示处理百/十/个位,不同位置;
level=1、level=10、level=100分别表示个十百位置
* */
public String processNum(Map<Integer,String> mapRelation,int num,int level) {
StringBuilder s = new StringBuilder();
if (num == 9 || num == 4 || num == 1 || num == 5) { // 13种情况之一
s.append(mapRelation.get(num * level));
} else {
if (num > 5){ // 超出临界点
s.append(mapRelation.get(5 * level));
for (int i=0;i<num-5;i++) {
s.append(mapRelation.get(level));
}
}else {
for (int i=0;i<num;i++) {
s.append(mapRelation.get(level));
}
}
}
return s.toString();
}
public String intToRoman(int num) {
// 构造数值与对应罗马字符串之间的映射关系,使用字典存储
int[] intKey = new int[]{1, 5, 10, 50, 100, 500, 1000, 4, 9, 40, 90, 400, 900};
String[] romanValue = new String[]{"I", "V", "X", "L", "C", "D", "M", "IV", "IX", "XL", "XC", "CD", "CM"};
Map<Integer, String> intToRoman_ = new HashMap<Integer, String>();
for (int k = 0; k < intKey.length; k++) {
intToRoman_.put(intKey[k], romanValue[k]);
}
// System.out.println(intToRoman_);
//分别得到输入数字的千百十个位对应数字
int first_num=num/1000;
int second_num=num/100%10;
int third_num=num/10%10;
int forth_num=num%10;
// 分别处理千百十个位对应数值:
StringBuilder s=new StringBuilder();
for (int i=0;i<first_num;i++) // 处理千位数字
s.append(intToRoman_.get(1000));
s.append(processNum(intToRoman_,second_num,100));
s.append(processNum(intToRoman_,third_num,10));
s.append(processNum(intToRoman_,forth_num,1));
return s.toString();
}
}