问题引入
你了解罗马数字吗?
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
举几个栗子:
LVIII = L + V +III = 50 + 5 + 3 = 58
MXLIV = M + XL + IV = 1000 + 40 + 4 = 1044
问题1:数字转罗马数字
解法一:贪心+哈希
对于数字num,使用贪心的思路,剥离下来从大到小的数字。同时我们还要借助一个哈希表。
class Solution {
public String intToRoman(int num) {
// 数字与罗马数字的哈希映射
Map<Integer, String> map = new HashMap<>();
map.put(1000, "M");
map.put(900, "CM");
map.put(500, "D");
map.put(400, "CD");
map.put(100, "C");
map.put(90, "XC");
map.put(50, "L");
map.put(40, "XL");
map.put(10, "X");
map.put(9, "IX");
map.put(5, "V");
map.put(4, "IV");
map.put(1, "I");
// HashMap是无序的,为了保证剥离下来的数字是从大到小的,还需要一个数组
int[] arr = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
// 贪心构建字符串
StringBuilder sb = new StringBuilder();
for (int n : arr) {
while (num / n > 0) {
sb.append(map.get(n));
num -= n;
}
}
return sb.toString();
}
}
解法二:贪心+数组
我们可以对解法一进行改进,不使用哈希表,而是使用数字数组与罗马数字数组,二者通过下标实现一一对应。同时,下标从左到右移动,即可保证数字从大到小。
class Solution {
public String intToRoman(int num) {
// 数字数组
int[] arr = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
// 罗马数字数组
String[] roman = {"M", "CM" , "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
// 贪心构建字符串
StringBuilder sb = new StringBuilder();
int index = 0;
while (num != 0) {
while (num / arr[index] > 0) {
sb.append(roman[index]);
num -= arr[index];
}
index++;
}
return sb.toString();
}
}
问题2:罗马数字转数字
解法一:字符串切割
思路很简单,不断切割下来罗马数字字符串,并将对应的数字加到结果上。切割的时候,仍旧是尽量使用“数值大”的字符串进行切割。
class Solution {
public int romanToInt(String s) {
int[] arr = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
String[] roman = {"M", "CM" , "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
int num = 0;
int index = 0;
while (s.length() > 0) {
while (s.startsWith(roman[index])) {
num += arr[index];
s = s.substring(roman[index].length());
}
index++;
}
return num;
}
}
解法二:加减法
以这道题为契机,下面讲一下罗马数字的本质。
罗马数字的单个字符从左到右是递减的,如果出现递增的反常情况,则左侧字符变负数。
看下图很容易理解:
class Solution {
public int romanToInt_2(String s) {
Map<Character, Integer> map = new HashMap<>();
map.put('M', 1000);
map.put('D', 500);
map.put('C', 100);
map.put('L', 50);
map.put('X', 10);
map.put('V', 5);
map.put('I', 1);
int num = 0;
for (int i = 0; i < s.length(); i++) {
// 出现递增反常,则用减法;否则用加法
if (i + 1 < s.length() && map.get(s.charAt(i)) < map.get(s.charAt(i + 1))) {
num -= map.get(s.charAt(i));
} else {
num += map.get(s.charAt(i));
}
}
return num;
}
}
E N D END END