Source: https://leetcode.com/problems/roman-to-integer/
13. Roman to Integer
Given a roman numeral,convert it to an integer.
Input is guaranteed to bewithin the range from 1 to 3999.
Solution:
为了解决这个问题,首先我们需要了解罗马数字(即题目中的Roman)计数规则。
1 罗马数字采用七个罗马字母作数字,这些字母及其对应的数字依次是I(1)、V(5)、X(10)、L(50)、C(100)、D(500)、M(1000);
2 同一字母连续出现最多3次;
3 右加左减:
(1) 在较大的罗马数字的右边记上较小或相等的罗马数字,表示大数字加小数字 (e.g. XI=11);
(2) 在较大的罗马数字的左边记上较小的罗马数字,表示大数字减小数字 (e.g. IX=9);
这里有以下限制:
① 左减数字只能有1位 (e.g. 8不可表示为IIX,而应是VIII);
② 左减数字只能是I、X、C之一 (e.g. 45不可表示为VL,而应是XLV);
③ 左减数字不能比其右一位低2位 (e.g. 99不可表示为IC,而应是XCIX)。
罗马数字还有一些其他的规则,但是本问题的数字范围在1到3999之间,以上规则已经适用,故不作补充。
(以上规则整理自https://www.douban.com/note/335254352/)
如果我们以ans作为一个罗马数字形式的字符串所对应的值的十进制表达,从以上规则可以总结,在计算ans的过程中,罗马数字的各位所对应的值或加到ans中,或从ans中减去,具体是加是减,取决于这一位的下一位是否大于该位。因此可以较为轻松得到本题的解法如下,算法复杂度为O(n),空间复杂度为O(1),n为字符串的长度。
class Solution {
public:
int romanToInt(string s) {
int i=0,j,k;
while (s[i]!='\0') //计算字符串长度
i++;
const int length=i;
char romanDigit[8]="IVXLCDM";
int weight[7]={1,5,10,50,100,500,1000};
int ans=0;
for (i=0;i<length-1;i++)
{
j=0;
k=0;
while (romanDigit[j]!=s[i]) //匹配该位
j++;
while (romanDigit[k]!=s[i+1]) //匹配下一位
k++;
if (j<k) //判断该位是否小于下一位
ans=ans-weight[j];
else
ans=ans+weight[j];
}
i=0;
while (s[length-1]!=romanDigit[i]) //加上最后一位
i++;
ans=ans+weight[i];
return ans;
}
};
这一方法通过所有样例所需时间为32ms。我采用的另一种复杂得多的写法占用多一些空间,通过所有样例时间为22ms,本质思路没有改变,只不过将含有“左减”情况的两位罗马数字看成一个单位考虑。这里只贴上代码:
class Solution {
public:
int romanToInt(string s) {
int i=0,j=6,k;
int ans=0;
int weight[7]={1,5,10,50,100,500,1000};
int count[7]={0};
char romanDigit[8]="IVXLCDM";
while (s[i]!='\0')
i++;
const int length=i;
for (i=0;i<length;i++)
{
switch (s[i])
{
case 'I':
count[0]++;
break;
case 'V':
count[1]++;
break;
case 'X':
count[2]++;
break;
case 'L':
count[3]++;
break;
case 'C':
count[4]++;
break;
case 'D':
count[5]++;
break;
case 'M':
count[6]++;
break;
}
}
for (i=0;i<length;i++)
{
while (count[j]==0)
j--;
if (s[i]!=romanDigit[j])
{
k=j-(2-(j%2));
ans=ans+weight[j]-weight[k];
count[j]--;
count[k]--;
i++;
}
else
{
ans=ans+weight[j];
count[j]--;
}
}
return ans;
}
};