-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
1,317 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
--- | ||
title: 12. 整数转罗马数字 | ||
date: 2023-01-15 20:03:06 | ||
tag: | ||
- 算法 | ||
categories: | ||
- 前端进击 | ||
--- | ||
# 12. 整数转罗马数字 | ||
## 解题过程 | ||
:::info | ||
[题目链接](https://leetcode.cn/problems/integer-to-roman/) | ||
<pre>罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。 | ||
字符 数值 | ||
I 1 | ||
V 5 | ||
X 10 | ||
L 50 | ||
C 100 | ||
D 500 | ||
M 1000</pre> | ||
例如, 罗马数字 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。 | ||
给你一个整数,将其转为罗马数字 | ||
::: | ||
```javascript | ||
/** | ||
* @link https://leetcode.cn/problems/integer-to-roman/ | ||
* @title 12. 整数转罗马数字 | ||
* @description 罗马数字包含以下七种字符: 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。 | ||
给你一个整数,将其转为罗马数字 | ||
* @param {number} num | ||
* @return {string} | ||
*/ | ||
// 解法一 | ||
// 思路:穷举法,罗列题目所有情况即可:通过对数字的拆分转换千百十个的位数,对应在罗马字符映射表上,然后对千百十个对应数字转换单独处理,然后拼接即可 | ||
// 缺点:执行效果比较差,很多重复的逻辑 | ||
var intToRoman = function (num) { | ||
const romanChar = { | ||
1: 'I', | ||
4: 'IV', | ||
5: 'V', | ||
9: 'IX', | ||
10: 'X', | ||
40: 'XL', | ||
50: 'L', | ||
90: 'XC', | ||
100: 'C', | ||
400: 'CD', | ||
500: 'D', | ||
900: 'CM', | ||
1000: 'M' | ||
} | ||
|
||
let res = '' | ||
const [thoNum, hudNum, tenNum, bitNum] = String(num).padStart(4, '0').split('') | ||
|
||
if (thoNum !== '0') { | ||
// 处理千位 | ||
res += parseInt(thoNum) > 1 ? romanChar[thoNum + '000'] || 'M'.repeat(parseInt(thoNum)) : 'M' | ||
} | ||
|
||
if (hudNum !== '0') { | ||
// 处理百位 | ||
const intNum = parseInt(hudNum) | ||
let count = 0 | ||
for (let i = intNum; i > 0; i--) { | ||
if (romanChar[i + '00'] && i <= intNum - count) { | ||
res += romanChar[i + '00'] | ||
count += i | ||
} | ||
} | ||
|
||
if (count !== intNum) { | ||
res += 'C'.repeat(intNum - count) | ||
} | ||
} | ||
|
||
if (tenNum !== '0') { | ||
// 处理十位 | ||
const intNum = parseInt(tenNum) | ||
let count = 0 | ||
for (let i = intNum; i > 0; i--) { | ||
if (romanChar[i + '0'] && i <= intNum - count) { | ||
res += romanChar[i + '0'] | ||
count += i | ||
} | ||
} | ||
|
||
if (count !== intNum) { | ||
res += 'X'.repeat(intNum - count) | ||
} | ||
} | ||
|
||
if (bitNum !== '0') { | ||
// 处理个位 | ||
const intNum = parseInt(bitNum) | ||
let count = 0 | ||
for (let i = intNum; i > 0; i--) { | ||
if (romanChar[i] && i <= intNum - count) { | ||
res += romanChar[i] | ||
count += i | ||
} | ||
} | ||
|
||
if (count !== intNum) { | ||
res += 'I'.repeat(intNum - count) | ||
} | ||
} | ||
|
||
return res | ||
}; | ||
|
||
// 解法二 | ||
// 思路:优化解法一思路代码,通过两个映射表和通过遍历数字在循环判断对应数字对应层级大小的累减计算 | ||
var intToRoman = function (num) { | ||
const romanNum = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1] | ||
const romanChar = { | ||
0: 'M', | ||
1: 'CM', | ||
2: 'D', | ||
3: 'CD', | ||
4: 'C', | ||
5: 'XC', | ||
6: 'L', | ||
7: 'XL', | ||
8: 'X', | ||
9: 'IX', | ||
10: 'V', | ||
11: 'IV', | ||
12: 'I', | ||
} | ||
|
||
let res = '' | ||
for (let i = 0; i < romanNum.length; i++) { | ||
for (let j = num; j >= romanNum[i];) { | ||
res += romanChar[i] | ||
num -= romanNum[i] | ||
j -= romanNum[i] | ||
} | ||
} | ||
|
||
return res | ||
} | ||
|
||
// 解法三 | ||
// 思路:来自评论区一个很不错的Java解题思路,跟解法二类似,然后自己做一遍:通过两个映射表解决:从数字表由大到小遍历数字对应的罗马字符表统计即可 | ||
// 优点:比解法一代码优雅和执行效果更好、解题思路更简单 | ||
var intToRoman = function (num) { | ||
const romanNum = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1] | ||
const romanChar = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I'] | ||
|
||
let res = '' | ||
for (let i = 0; i < romanNum.length; i++) { | ||
while (num >= romanNum[i]) { | ||
num -= romanNum[i] | ||
res += romanChar[i] | ||
} | ||
} | ||
|
||
return res | ||
} | ||
|
||
// const result = intToRoman(1994) // MCMXCIV | ||
const result = intToRoman(58) // LVIII | ||
// const result = intToRoman(3) // III | ||
// const result = intToRoman(4) // IV | ||
// const result = intToRoman(9) // IX | ||
// const result = intToRoman(20) // XX | ||
// const result = intToRoman(60) // LX | ||
console.log(result) | ||
``` | ||
## 解题感受 | ||
总的来说这题相对友好一点,虽然解法一有点累赘,通过优化之后,解法二执行效果大增;看到评论区一个 Java 解法比我写的解法二解题思路差不多,都用到了两个哈希表,但代码优雅很多;官方题解通过组合罗马数字和字符的哈希表更好、更优雅的解法。还有一种暴力匹配法,没有写跟解法一有点类似但好像写法代码更简洁,就是通过将数字除以对应的千百十的整数部分进行换算然后在 1-9、10-99、100-900、1000-3000、去配置哈希表然后在对应表里匹配,有点麻烦也就放弃,整理的问题会比解法一更多一些 | ||
## 优质题解 | ||
|
||
- [https://leetcode.cn/problems/integer-to-roman/solution/zheng-shu-zhuan-luo-ma-shu-zi-by-leetcod-75rs/](https://leetcode.cn/problems/integer-to-roman/solution/zheng-shu-zhuan-luo-ma-shu-zi-by-leetcod-75rs/) | ||
- [https://leetcode.cn/problems/integer-to-roman/solution/tan-xin-ha-xi-biao-tu-jie-by-ml-zimingmeng/](https://leetcode.cn/problems/integer-to-roman/solution/tan-xin-ha-xi-biao-tu-jie-by-ml-zimingmeng/) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
--- | ||
title: 13. 罗马数字转整数 | ||
date: 2023-01-12 20:03:06 | ||
tag: | ||
- 算法 | ||
categories: | ||
- 前端进击 | ||
--- | ||
# 13. 罗马数字转整数 | ||
## 解题过程 | ||
:::info | ||
[题目链接](https://leetcode.cn/problems/roman-to-integer/) | ||
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。 | ||
<pre> | ||
字符 数值 | ||
I 1 | ||
V 5 | ||
X 10 | ||
L 50 | ||
C 100 | ||
D 500 | ||
M 1000</pre> | ||
例如, 罗马数字 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。 | ||
给定一个罗马数字,将其转换成整数 | ||
::: | ||
```javascript | ||
/** | ||
* @link https://leetcode.cn/problems/roman-to-integer/ | ||
* @title 13. 罗马数字转整数 | ||
* @description 罗马数字包含以下七种字符: 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。 | ||
给定一个罗马数字,将其转换成整数 | ||
* @param {string} s | ||
* @return {number} | ||
*/ | ||
// 解法一 | ||
// 思路:将罗马数字映射出来,注意特殊规则的6种情况是两个字符的,然后遍历时候判断下一项是否在映射表能否找到截取对一个映射字符的数字累加即可 | ||
var romanToInt = function (s) { | ||
const romanNum = { | ||
I: 1, | ||
IV: 4, | ||
V: 5, | ||
IX: 9, | ||
X: 10, | ||
XL: 40, | ||
L: 50, | ||
XC: 90, | ||
C: 100, | ||
CD: 400, | ||
D: 500, | ||
CM: 900, | ||
M: 1000 | ||
} | ||
|
||
let res = 0 | ||
for (let i = 0; i < s.length; i++) { | ||
if (i + 1 < s.length && romanNum[s.substring(i, i + 2)]) { | ||
res += romanNum[s.substring(i, i + 2)] | ||
i++ | ||
} else { | ||
res += romanNum[s.substring(i, i + 1)] | ||
} | ||
} | ||
|
||
return res | ||
}; | ||
|
||
// const result = romanToInt('III') // 3 | ||
// const result = romanToInt('IV') // 4 | ||
// const result = romanToInt('IX') // 5 | ||
// const result = romanToInt('LVIII') // 58 | ||
const result = romanToInt('MCMXCIV') // 1994 | ||
console.log(result) | ||
``` | ||
## 解题感受 | ||
通过映射表获取对应的字符数字累加计算方法来做确实简单一点,因为时间关系没有做其他解法的尝试 | ||
## 优质题解 | ||
|
||
- [https://leetcode.cn/problems/roman-to-integer/solution/yong-shi-9993nei-cun-9873jian-dan-jie-fa-by-donesp/](https://leetcode.cn/problems/roman-to-integer/solution/yong-shi-9993nei-cun-9873jian-dan-jie-fa-by-donesp/) | ||
- [https://leetcode.cn/problems/roman-to-integer/solution/luo-ma-shu-zi-zhuan-zheng-shu-by-leetcod-w55p/](https://leetcode.cn/problems/roman-to-integer/solution/luo-ma-shu-zi-zhuan-zheng-shu-by-leetcod-w55p/) |
Oops, something went wrong.