一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情。
一、题目描述:
罗马数字包含以下七种字符: 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。
给你一个整数,将其转为罗马数字。
示例:
示例 1:
输入: num = 3
输出: "III"
示例 2:
输入: num = 4
输出: "IV"
示例 3:
输入: num = 9
输出: "IX"
示例 4:
输入: num = 58
输出: "LVIII"
解释: L = 50, V = 5, III = 3.
示例 5:
输入: num = 1994
输出: "MCMXCIV"
解释: M = 1000, CM = 900, XC = 90, IV = 4.
提示:
1 <= num <= 3999
二、题解:
这道题将数值转化为罗马数字字符串,意味着得从右至左或从左至右拼接数字。
这里找出千位,百位,十位,个位然后拼接起来就行
注意6种特殊情况
方法一 位数匹配法
- 原理。根据题解循环匹配位数即可。
- 思路。
- 先写出数字对应的罗马数字字符串
- 记录千百十个位
- 取第一位判断是否有千百十位
- 是否是特殊情况
- 整数位是否大于5*tenCount
- 循环叠加即可
代码:
var intToRoman = function(num) {
let map = {
'1': 'I',
'5': 'V',
'10': 'X',
'50': 'L',
'100': 'C',
'500': 'D',
'1000': 'M',
'4': 'IV',
'9': 'IX',
'40': 'XL',
'90': 'XC',
'400': 'CD',
'900': 'CM',
}
let res = ''
let count = 0
let cArr = [1000,100,10,1]
while(num>0){
let tenCount = cArr[count]
// 取第一位
let n = ~~(num / tenCount)
// 获得整数位
let allN = n*tenCount
let curStr = ''
// 为0则没有这一位
if(n===0){
count++
continue
}
// 是否是特殊情况
if(allN in map){
curStr = map[allN]
} else {
// 整数位是否大于5*tenCount
if(allN>=5*tenCount){
curStr += map[5*tenCount]
while(n-5>0){
curStr += map[1*tenCount]
n--
}
} else {
while(n>0){
curStr += map[1*tenCount]
n--
}
}
}
res += curStr
num = num % tenCount
count++
}
return res
};
如果替换成字符串呢,可以使用截取来获取整数位。
修改后的代码:
var intToRoman = function(num) {
let map = {
'1': 'I',
'5': 'V',
'10': 'X',
'50': 'L',
'100': 'C',
'500': 'D',
'1000': 'M',
'4': 'IV',
'9': 'IX',
'40': 'XL',
'90': 'XC',
'400': 'CD',
'900': 'CM',
}
let res =''
num = num +''
while(num.length>0){
let tenCount = Math.pow(10,num.length-1)
// 取第一位
let n = num[0]
// 获得整数位
let allN = n*tenCount
let curStr = ''
// 是否是特殊情况
if(allN in map){
curStr = map[allN]
} else {
// 整数位是否大于5*tenCount
if(allN>=5*tenCount){
curStr += map[5*tenCount]
while(n-5>0){
curStr += map[1*tenCount]
n--
}
} else {
while(n>0){
curStr += map[1*tenCount]
n--
}
}
}
res += curStr
num = num.substr(1)
}
return res
};
方法二 巧用遍历法
- 原理。根据题解利用大小关系遍历时记录后相减。
- 思路。
- 声明一个从大到小的map
- 循环map
- 当遍历到num大于map的key时,则开始记录
- 记录后减去改数值,则开始余数记录
- 不断相减记录则得出结果
代码:
var intToRoman = function(num) {
let map = new Map([
[1000, 'M'],
[900, 'CM'],
[500, 'D'],
[400, 'CD'],
[100, 'C'],
[90, 'XC'],
[50, 'L'],
[40, 'XL'],
[10, 'X'],
[9, 'IX'],
[5, 'V'],
[4, 'IV'],
[1, 'I'],
])
let res = ''
for(let [key,value] of map){
while(num>= key){
res+= value
num -= key
}
}
return res
};
三、总结
- 此题可以位数匹配法和巧用遍历法两种方案
- 位数匹配法主要是根据题解循环匹配位数即可。
- 巧用遍历法主要是根据题解利用大小关系遍历时记录后相减。
文中如有错误,欢迎在评论区指正