题目描述
罗马数字包含以下七种字符:I
, V
, X
, L
, C
, D
和M
。
字符数值
I
:1
V
: 5
X
:10
L
:50
C
:100
D
:500
M
:1000
例如,罗马数字2
写作II
,即为两个并列的I
。12
写作XII
,即为X + II
。 27
写作XXVII
,即为XX + V + II
.
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如4
不写作IIII
, 而是IV
。数字1
在数字5
的左边,所表示的数等于大数5
减去小数1
得到的数值4
。同样地,数字9
表示为IX
。这个特殊的规则只适用于以下六种情况:
I
可以放在V
和X
的左边,来表示数字4, 9
;X
可以放在L
和C
的左边,用来表示数字40, 90
;C
可以放在D
和M
的左边,来表示数字400, 900
;
给定一个罗马数字,将其转换成整数。确保在1-3999
的范围内。
示例1:
输入: s = “III”
输出: 3
示例2:
输入: s = “IV”
输出: 4
示例3:
输入: s = “IX”
输出: 9
示例4:
输入: s = “LVIII”
输出: 58
解释: L = 50, V = 5, III = 3.
示例5:
输入: s = “MCMXCIV”
输出: 1994
解释: M = 1000, CM = 900, XC = 90, IV = 4.
思路分析
这道题难度为简单, 通过题意我们可以先将其看作简单的转换,接着是一个数值累加的过程,只不过这里存在着一些特殊情况为减去值,那么我们将规律尽量统一化:
- 大多数情况下,为累加;
- 特殊情况下,为减去当前值;
对于情况1 大多数情况下的累加,观察字符串,我们采用从右至左的角度,当val(rightNum) >= val(curr)
时,此时为加法;对于情况2 特殊情况下的减值,当val(currLeft) < val(curr)
时,此时为减法。
通过以上简单分析我们可知,我们首先需要一个转换的标准,这里我们借用HashMap<Character, Integer>
来存放题干中罗马数字字符与数字的转换原则;之后我们还需要存在一个记忆变量rightNum
,但是仅需存放最新的右边值即可,即rightNum
是随着遍历动态刷新的。我们直接给上代码:
解题代码
public static int solution(String s){
if(s == null || s == "") return 0;
// HashMap to storage rules exchanged.
Map<Character, Integer> map = new HashMap<>();
map.put('I', 1);
map.put('V', 5);
map.put('X', 10);
map.put('L', 50);
map.put('C', 100);
map.put('D', 500);
map.put('M', 1000);
int len = s.length();
int rightNum = map.get(s.charAt(len - 1));
int res = rightNum;
for(int i = len-2;i>=0;i--){
int cur = map.get(s.charAt(i));
if(cur < rightNum)
res -= cur;
else if(cur >= rightNum)
res += cur;
rightNum = cur;
}
return res;
}
复杂度分析
时间复杂度: 我们对字符串进行了一次遍历,故时间复杂度为O(N)
;
空间复杂度: 我们虽然对转换规则进行了HashMap
存储,但是其不随N
变化,所以空间复杂度为O(1)
.
Github源码
完整可运行文件请访问GitHub。