@[算法题解]
13 - Roman To Int
题目描述
罗马数字包含以下七种字符: 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 到 3999 的范围内。
- 示例 1:
- 输入: “III”
- 输出: 3
- 示例 2:
- 输入: “IV”
- 输出: 4
- 示例 3:
- 输入: “IX”
- 输出: 9
- 示例 4:
- 输入: “LVIII”
- 输出: 58
- 解释: L = 50, V= 5, III = 3.
- 示例 5:
- 输入: “MCMXCIV”
- 输出: 1994
- 解释: M = 1000, CM = 900, XC = 90, IV = 4.
- 提示:
- 1 <= s.length <= 15
- s 仅含字符 (‘I’, ‘V’, ‘X’, ‘L’, ‘C’, ‘D’, ‘M’)
- 题目数据保证 s 是一个有效的罗马数字,且表示整数在范围 [1, 3999] 内
- 题目所给测试用例皆符合罗马数字书写规则,不会出现跨位等情况。
- IL 和 IM 这样的例子并不符合题目要求,49 应该写作 XLIX,999 应该写作 CMXCIX 。
- 关于罗马数字的详尽书写规则,可以参考 罗马数字 - Mathematics 。
- 来源:力扣(LeetCode)
- 链接:https://leetcode-cn.com/problems/roman-to-integer
- 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
思路:
-
- 考察的应该是一个进制的转换问题,先列举一下观察规律
- 1 - 10: I, II, III, IV, V, VI, VII, VIII, IX, X
- => I, II, III, IV, V,
- VI, VII, VIII, IX, X
- 10-40-50: X, XV, XX, XXX, XL, L -> 10, 15, 20, 30, 40, 50
- ex: 384
- 384/1000 = 0, 384/500 = 0, 384/100 = 3 CCC
- 84/50 = 1 L
- 34/10 = 3 XXX
- 4 -> IV
- -> 应该是 CCCLXXXIV?
- 校验正确.
- 阿拉伯数字转罗马数字工具: https://www.luomashuzi.com/
- 按照进制来进行转换IVXL,但是4比较特殊.需要用下一位-上一位
- -> 5进制, 逢5进1,下一位就是2进制,所以3个digit为一组如IVX, LCD, M
- -> 判断当前是digit 是0~3 还是4.
执行结果及总结
- 结果: 通过.
- 执行用时:6 ms , 在所有 Java 提交中击败了57.93% 的用户
- 内存消耗:39.1 MB, 在所有 Java 提交中击败了10.43% 的用户
##Java 代码
/**
* 罗马数字转换方法
* @param s
* @return
*/
public static int romanToInt(String s) {
/**
* 字符 数值
* I 1
* V 5
* X 10
* L 50
* C 100
* D 500
* M 1000
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode-cn.com/problems/roman-to-integer
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
//1. 定义转换规则(规定在1-3999之间,所以不需要做合法性判断)
// 将特殊的定义出来?做减法
// IV = V - I => COUNT I, COUNT V if CONTAINS(IV) - 2I
// IX = X - I...
// XL = L - X..
// XC = C - X..
// CD = D - C..
// CM = M - C..
/* //正数计数
int countI = 0;
int countV = 0;
int countX = 0;
int countL = 0;
int countC = 0;
int countD = 0;
int countM = 0;
//负数计数
int countIV = 0;
int countIX = 0;
int countXL = 0;
int countXC = 0;
int countCD = 0;
int countCM = 0;
//然后就是一堆的switch和contains 好像太麻烦了.*/
//用数组定义规则,空间消耗大些,但是很直观,而且通用性好
Map<Character, Integer> digit = new HashMap<>();
digit.put('I', 1);
digit.put('V', 5);
digit.put('X', 10);
digit.put('L', 50);
digit.put('C', 100);
digit.put('D', 500);
digit.put('M', 1000);
//准备遍历字符串
int length = s.length();
//准备一个数组存每一位的值
int[] arr = new int[length];
//最后一位不用去比较,一定是个正数
for (int i = 0; i < length - 1; i++) {
char nextChar = s.charAt(i + 1);
char currentChar = s.charAt(i);
Integer integerNext = digit.get(nextChar);
Integer integerCurrent = digit.get(currentChar);
if (integerCurrent < integerNext) {
arr[i] = -integerCurrent;
} else {
arr[i] = integerCurrent;
}
}
//加入最后一位
char c = s.charAt(length - 1);
arr[length - 1] = digit.get(c);
//将arr做累加即可
int sum = 0;
for (int i = 0; i < length; i++) {
sum += arr[i];
}
return sum;
}