此道题目,跟第12题,恰好相反,要求从罗马数字转到阿拉伯数字。这道题,我的算法依然比较复杂,主要是因为对于题目内在的规律和整体的结构缺乏了解,所以以后一定要好好理顺题目的内在结构和题目的规律。这道题,我的算法基本上算是直接枚举,因为缺乏对于题目内在规律的洞察,所以很麻烦。我的代码如下:
int romanToInt(string s) {
int index = 0, i = 0, len = (int)s.length(), result = 0, pos = 0, step = 0;
char one, five, ten;
for (index=0; index<len; index++) {
if (s.at(index) != 'M') {
break;
}
}
result = index * 1000;
while (index < len) {
step = 0;
if (s.at(index) == 'C' || s.at(index) == 'D') {
pos = 2;
one = 'C';
five = 'D';
ten = 'M';
} else if (s.at(index) == 'L' || s.at(index) == 'X') {
pos = 1;
one = 'X';
five = 'L';
ten = 'C';
} else if (s.at(index) == 'I' || s.at(index) == 'V') {
pos = 0;
one = 'I';
five = 'V';
ten = 'X';
}
if (s.at(index) == one) {
if (index+1 < len && s.at(index+1) == five) {
step = 2;
result += pow(10.0, pos) * 4;
} else if (index+1 < len && s.at(index+1) == ten) {
step = 2;
result += pow(10.0, pos) * 9;
} else {
step = 1;
for (i=index+1; i<len; i++) {
if (s.at(i) == one) {
step++;
} else {
break;
}
}
result += pow(10.0, pos) * step;
if (i == len) {
break;
}
}
} else if (s.at(index) == five) {
step = 1;
for (i=index+1; i<len; i++) {
if (s.at(i) == one) {
step++;
} else {
break;
}
}
result += pow(10.0, pos) * (step+4);
if (i == len) {
break;
}
}
index += step;
}
return result;
}
参考了别人的代码,发现简洁多了,调试和维护都很方便。代码的核心思想是从右至左进行遍历,并记录上次遍历的数值,如果当前数值比上次遍历的数值大,则直接相加就好了。如果小呢,则说明为IV和IX这样的情况,在此种情况,我们需要将当前的结果减去当前数值。代码如下:
int romanToInt(string s) {
int res=0;
int lastValue=0;
int digit;
for(int i=s.size()-1;i>=0;i--){ // 从右至左进行遍历
switch(s[i]){
case 'I': digit=1; break;
case 'V': digit=5; break;
case 'X': digit=10; break;
case 'L': digit=50; break;
case 'C': digit=100; break;
case 'D': digit=500; break;
case 'M': digit=1000; break;
}
if(digit>=lastValue){ // 为LV或者VI
res+=digit;
lastValue=digit;
}
else res-=digit; // 为CM,CD这样的形式
}
return res;
}