13. 罗马数字转整数:罗马数字包含以下七种字符: 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。
给定一个罗马数字,将其转换成整数。
思路:
- 一个字符对应一个数字 考虑使用哈希键值对比的形式,所以将所有值包括特殊
IV之类的,生成哈希表 - 特殊情况是存在2个字符串的解析,而且是前的为减,其他为正常键值对相加即可,所以考虑使用快慢指针的形式,而且是从后往前遍历(因为特殊情况是在前为减)
- 正常遍历,对比相应哈希表结果相加,为特殊
IV之类时,从当前索引值前2位开始新的循环
/**
* @param {string} s
* @return {number}
*/
var romanToInt = function (s) {
// 所有可能出现的罗马数字的组合哈希表
let obj = {
'IV': 4,
'IX': 9,
'XL': 40,
'XC': 90,
'CD': 400,
'CM': 900,
'I': 1,
'V': 5,
'X': 10,
'L': 50,
'C': 100,
'D': 500,
'M': 1000
}
let len = s.length
let result = 0
// 从后往前遍历
for (var a = len - 1; a > -1; a--) {
// 题目描述中有意义的罗马值最多为2个字符串组成
// 快慢指针 组合成新的字符串
let b = a - 1
let newValue = s[b] + s[a]
// 如果newValue组成的字符串在对象obj中有值 说明为特殊的4、9之类的值 下一次循环从a往前移两位索引开始
if (a > 0 && obj[newValue]) {
result = result + obj[newValue]
a--
} else {
result = result + obj[s[a]]
}
}
return result
};
12. 整数转罗马数字:七个不同的符号代表罗马数字,其值如下:
| 符号 | 值 |
|---|---|
| I | 1 |
| V | 5 |
| X | 10 |
| L | 50 |
| C | 100 |
| D | 500 |
| M | 1000 |
罗马数字是通过添加从最高到最低的小数位值的转换而形成的。将小数位值转换为罗马数字有以下规则:
- 如果该值不是以 4 或 9 开头,请选择可以从输入中减去的最大值的符号,将该符号附加到结果,减去其值,然后将其余部分转换为罗马数字。
- 如果该值以 4 或 9 开头,使用 减法形式,表示从以下符号中减去一个符号,例如 4 是 5 (
V) 减 1 (I):IV,9 是 10 (X) 减 1 (I):IX。仅使用以下减法形式:4 (IV),9 (IX),40 (XL),90 (XC),400 (CD) 和 900 (CM)。 - 只有 10 的次方(
I,X,C,M)最多可以连续附加 3 次以代表 10 的倍数。你不能多次附加 5 (V),50 (L) 或 500 (D)。如果需要将符号附加4次,请使用 减法形式。
给定一个整数,将其转换为罗马数字。
思路:
- 生成数字与罗马数字的哈希表
- 将数字拆分为各个单位(个、十、百、千)下的值
- 遍历将各个位置生成对应的罗马数字,其中的难点是
5是一个分界点,因为有各个单位下的5的对应罗马数字,所以要对5进行求余,求余后的整数、余数部分的罗马数字相加,则为对应的罗马数字的值 - 重新拼接罗马数字的数组
/**
* @param {number} num
* @return {string}
*/
var intToRoman = function(num) {
// 数字和罗马数字的键值对
let obj = {
4: 'IV',
9: 'IX',
40: 'XL',
90: 'XC',
400: 'CD',
900: 'CM',
1: 'I',
5: 'V',
10: 'X',
50: 'L',
100: 'C',
500: 'D',
1000: 'M'
}
// 数字拆分成字符串数组 方便后续生成相应的个、十、百、千
let newArr = num.toString().split('')
let len = newArr.length - 1
// 每一个数字遍历生成新的罗马数字数组
let numArr = newArr.map((item, index) => {
// 根据相应的索引对应幂生成对应的单位(个、十、百、千)
let unitValue = Math.pow(10, (len - index))
// 如果直接存在 则直接获取相应键值对值
if(obj[item*unitValue]) {
return obj[item*unitValue]
}
// 哈希表内不存在 说明是2、3、6、7、8内的数字
// 根据是否 > 5判断整数部分是否有值
// 取对应的5开头的整数的罗马数字
let integerStr = item > 5 ? obj[5*unitValue] : ''
// 除5求余
let remainder = item % 5
let remainderStr = ''
// 对应的1、10、100、1000的单位值
let unitStr = obj[unitValue]
// 根据余数循环相加 单位值
for(let i = 0; i < remainder; i++) {
remainderStr = remainderStr + unitStr
}
// 整数值 + 余数值 == 罗马数字值
return integerStr + remainderStr
})
let result = ''
// 将所有的罗马数字的数组拼接为字符串
numArr.forEach(item => result = result + item)
return result
};
方法二
这个方法是我看到其他人的题解的,我觉得比我自己的好就转载一下,点此跳转至题解具体位置
思路
- 第一步还是生成相应的值的集合
- 还是拆分,从最大值开始按相应单位值(1000、100、10、1)生成罗马数字,每生成一个减去相应的单位的值
- 并不担心
5的分界点因为5的时候,会匹配到相应的D、L、V字段,然后再通过num-=intArr[index]减去了相应的值
var intToRoman = function(num) {
let intArr=[1000,900,500,400,100,90,50,40,10,9,5,4,1];
let RomanArr=["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"];
let index=0;
let res="";
while(index<13){
while(num>=intArr[index]){
res+=RomanArr[index];
num-=intArr[index];
}
index++;
}
return res
};
作者:不吃辣