Given a roman numeral, convert it to an integer.(给定一个罗马数字,将其转换成整数)
Input is guaranteed to be within the range from 1 to 3999.(输入范围在1-3999内)
1.个人分析
这道题本质上应该与将字符串转化为整型一样,可以将atoi中实现的方法应用到这里。
思路:
罗马数字的七个基本字符为:I(1)、V(5)、X(10)、L(50)、C(100)、D(500)、M(1000),它们的组合规则如下:
除I、X、C位于大数后作为加数,位于大数前作为减数外,一般把若干罗马基本数字写在一起,它表示的数字等于各个数字的和。
注意点:
- I、X、C在大数右边(即相加时)不能连续超过三个,在大数左边(即相减时)只能用一个。
- V、L、D不能用于大数左边(相减),只能用于大数右边(相加),且只使用一个。
- V、X左边小数只用I;L、C左边小数只用X;D、M左边小数只用C。
2.个人解法
int romanToInt(string s)
{
int len = s.length();
if(0 == len)
return 0;
map<char, int>roman;
roman['I'] = 1;
roman['V'] = 5;
roman['X'] = 10;
roman['L'] = 50;
roman['C'] = 100;
roman['D'] = 500;
roman['M'] = 1000;
int sum = 0;
int i;
for (i=1; i<len; ++i)
{
if('I' == s[i-1] && roman[s[i]] > roman[s[i-1]])
sum += (-roman[s[i-1]]);
else if('X' == s[i-1] && roman[s[i]] > roman[s[i-1]])
sum += (-roman[s[i-1]]);
else if('C' == s[i-1] && roman[s[i]] > roman[s[i-1]])
sum += (-roman[s[i-1]]);
else
sum += roman[s[i-1]];
}
sum += roman[s[i-1]];
return sum;
}
3.参考解法
int romanToInt(string s)
{
int len = s.length();
if(0 == len)
return 0;
unordered_map<char, int> roman = {
{ 'I', 1 },
{ 'V', 5 },
{ 'X', 10 },
{ 'L', 50 },
{ 'C', 100 },
{ 'D', 500 },
{ 'M', 1000 }
};
int sum = 0;
int pre = 0;
for (int i=len-1; i>=0; --i)
{
int cur = roman[s[i]];
if(cur < pre)
sum -= cur;
else
sum += cur;
pre = cur;
}
return sum;
}
4.总结
自己的解法与他人解法的思路是一致的,都是利用哈希表来保存罗马字母对应的值,然后扫描字符串进行累加,这里需要判断做减法的情形。这里有个细节值得推敲,第一种解法中是利用下标法进行初始化,第二种解法是在定义哈希表时就进行赋值;第一种初始化在VS2010中是正确的,第二种不能通过编译,但在leetcode可以通过编译和运行,所有这很可能是在C++11后的标准中才支持的;另外两种初始化方式的运行效率相差较大,第二种运行了60ms,第一种运行了80,提高了四分之一效率。
PS:
- 题目的中文翻译是本人所作,如有偏差敬请指正。
- “个人分析”和“个人解法”均是本人最初的想法和做法,不一定是对的,只是作为一个对照和记录。