数学LeeCode13. 罗马数字转整数
Posted chenry777
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数学LeeCode13. 罗马数字转整数相关的知识,希望对你有一定的参考价值。
罗马数字包含以下七种字符: 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 的范围内。
题解一:遍历字符串,分别转换
常规思想遍历循环整个输入的字符串,对应每种情况的判断,最后输出结果
class Solution {
// 题解一:遍历字符串,分别转换
// 获取单个罗马字符的整数值
public int getInt(char r) {
int ans = 0;
switch (r) {
case 'I':
ans = 1;
break;
case 'V':
ans = 5;
break;
case 'X':
ans = 10;
break;
case 'L':
ans = 50;
break;
case 'C':
ans = 100;
break;
case 'D':
ans = 500;
break;
case 'M':
ans = 1000;
break;
default:
}
return ans;
}
// 获取前后相连的特殊罗马字符对的整数值
public int getInt(char r, char r_after) {
int ans = 0;
switch (r) {
case 'I':
ans = 1;
break;
case 'V':
ans = 5;
break;
case 'X':
ans = 10;
break;
case 'L':
ans = 50;
break;
case 'C':
ans = 100;
break;
case 'D':
ans = 500;
break;
case 'M':
ans = 1000;
break;
default:
}
if (r == 'I') {
switch (r_after) {
case 'V':
ans = 4;
break;
case 'X':
ans = 9;
break;
default:
}
}
if (r == 'X') {
switch (r_after) {
case 'L':
ans = 40;
break;
case 'C':
ans = 90;
break;
default:
}
}
if (r == 'C') {
switch (r_after) {
case 'D':
ans = 400;
break;
case 'M':
ans = 900;
break;
default:
}
}
return ans;
}
// 判断2个输入字符是否构成特殊罗马字符
public boolean isGetTwoInt(char r, char r_after) {
if (r == 'I') {
switch (r_after) {
case 'V':
case 'X':
return true;
default:
}
}
if (r == 'X') {
switch (r_after) {
case 'L':
case 'C':
return true;
default:
}
}
if (r == 'C') {
switch (r_after) {
case 'D':
case 'M':
return true;
default:
}
}
return false;
}
// 功能函数
public int romanToInt(String s) {
int ans = 0;
// 循环length - 1次,例如s.length() = 20,遍历次数 = 19次,Max(i) = 18
// , s.charAt(18)为倒数第二个数。
// 该循环遍历了当s.length() >= 2时的所有情况
for (int i = 0; i < s.length() - 1; i++) {
ans += getInt(s.charAt(i), s.charAt(i + 1));
//判断是否是两个字符的特殊情况
if (isGetTwoInt(s.charAt(i), s.charAt(i + 1))) {
i++;
}
}
//将单字符情况和最后一个字符单独判断,如果放到上边的循环会越界
// !s.length() >= 2 筛选单字符情况
// s.length() - 2 ==> 倒数第二个字符
// s.length() - 1 ==> 最后一个字符
if (!(s.length() >= 2 && isGetTwoInt(s.charAt(s.length() - 2), s.charAt(s.length() - 1)))) {
ans += getInt(s.charAt(s.length() - 1));
}
return ans;
}
}
输入的字符串的length直接决定了循环的次数,所以时间复杂度是O(n),n为字符串长度
空间复杂度:O(1)。
题解二、提前去除特殊情况
class Solution {
// 题解二、提前去除特殊情况
public int romanToInt(String s) {
int sum = 0;
// 每次遇到特殊情况,就从sum中减去
if (s.indexOf("IV") != -1) sum -= 2;
if (s.indexOf("IX") != -1) sum -= 2;
if (s.indexOf("XL") != -1) sum -= 20;
if (s.indexOf("XC") != -1) sum -= 20;
if (s.indexOf("CD") != -1) sum -= 200;
if (s.indexOf("CM") != -1) sum -= 200;
char c[] = s.toCharArray();
// 遍历整个字符数组,
for (int count = 0 ; count <= s.length() - 1; count++) {
if (c[count] == 'M') sum += 1000;
if (c[count] == 'D') sum += 500;
if (c[count] == 'C') sum += 100;
if (c[count] == 'L') sum += 50;
if (c[count] == 'X') sum += 10;
if (c[count] == 'V') sum += 5;
if (c[count] == 'I') sum += 1;
}
return sum;
}
}
时间复杂度还是O(n)
空间复杂度因为用到了一个char[],变成了O (n) ,也可以使用String.charAt()函数来代替String.toCharArray(),空间复杂度依然为O (1)
题解三、利用罗马数字的规则判定
利用到罗马数字的规则,一般情况是表示数字大的字母在前,数字小的字母在后,如果不是这样,就说明出现了特殊情况,此时应该做减法。
class Solution {
// 题解三、利用罗马数字的规则判定
private int getVal(char c) {
switch (c) {
case 'M':
return 1000;
case 'D':
return 500;
case 'C':
return 100;
case 'L':
return 50;
case 'X':
return 10;
case 'V':
return 5;
case 'I':
return 1;
default:
}
// 表示没有对应字符
return 0;
}
public int romanToInt(String s) {
int res = 0;
// 空字符串判定
if (s.length() == 0) {
return res;
}
// 循环遍历:判断当前字符和next字符之间的大小关系
for (int i = 0; i < s.length() - 1; i++) {
int cur = getVal(s.charAt(i));
int nex = getVal(s.charAt(i + 1));
// 如果当前字符小于next字符,则res - 当前字符
if (cur < nex) {
res -= cur;
} else {
// 否则 + 当前字符
res += cur;
}
}
// 因为前面的循环只涉及到前后2个字符的比较,没有算上最后一个值
// 最后一个值不存在next,所以肯定符合要求,直接加上
return res + getVal(s.charAt(s.length() - 1));
}
}
时间复杂度:O (1)
空间复杂度:O (1)
总结
这题的特殊情况相对较少,感觉用第二种方法来提前去除掉特殊值,会简单一点。
以上是关于数学LeeCode13. 罗马数字转整数的主要内容,如果未能解决你的问题,请参考以下文章