题目:
Given a roman numeral, convert it to an integer.
Input is guaranteed to be within the range from 1 to 3999.
思路:
原来一直在用罗马数字,但是真正的规则还是不太清楚,通过百科,查到了罗马数字的一些规律,如下:
- 罗马数字有下面七个基本符号:I(1)V(5)X(10)L(50)C(100)D(500)M(1000);
- 相同的数字连写,所表示的数等于这些数字相加得到的数,如:Ⅲ = 3;
- 小的数字在大的数字的右边,所表示的数等于这些数字相加得到的数, 如:Ⅷ = 8;Ⅻ = 12;
- 小的数字,(限于Ⅰ、X 和C)在大的数字的左边,所表示的数等于大数减小数得到的数,如:Ⅳ= 4;Ⅸ= 9;
- 正常使用时,连写的数字重复不得超过三次;
- 在一个数的上面画一条横线,表示这个数扩大1000倍;
- 基本数字Ⅰ、X 、C 中的任何一个,自身连用构成数目,或者放在大数的右边连用构成数目,都不能超过三个;放在大数的左边只能用一个;
- 不能把基本数字V 、L 、D 中的任何一个作为小数放在大数的左边采用相减的方法构成数目;放在大数的右边采用相加的方式构成数目,只能使用一个;
- V 和X 左边的小数字只能用Ⅰ;
- L 和C 左边的小数字只能用 X;
- D 和M 左边的小数字只能用 C。
所以基于上述规则,我们可以发现,将输入字符串s的所有字符转换为数字之后,可以看到是不同大小的数字序列。
我们设有一个表示该数字序列每位数字的加减符号数组flags(true为加,false为减),那么最后的输出值为所有数字的加减和。
默认每个数字标志位为true,当一个数字比前一个数字大时,前一个数字的标志位变为false;
所以算法如下所示:
public class Solution {
public int conversion(char c) {
switch(c){
case 'I': return 1;
case 'V': return 5;
case 'X': return 10;
case 'L': return 50;
case 'C': return 100;
case 'D': return 500;
case 'M': return 1000;
default: return 0;
}
}
public int romanToInt(String s) {
//check the string
if(s.length() == 0) {
return 0;
}
int sum = 0;
//generate add or minus flags
boolean[] flags = new boolean[s.length()];
flags[0] = true;
for(int i = 1;i<s.length();i++) {
if(conversion(s.charAt(i)) > conversion(s.charAt(i-1))) {
flags[i-1] = false;
flags[i] = true;
}else{
flags[i] = true;
}
}
//generate the sum
for(int i = 0;i<s.length();i++) {
sum += (flags[i]?1:-1) * conversion(s.charAt(i));
}
return sum;
}
}