目录
一、题目描述
二、初次解答
1. 思路:仅循环一次数组,判定当前元素以及后一个元素是否是特例,若是则加上特定的值且s+=2,若不是则按照标准的累加且s++。
2. 代码:
int romanToInt(char* s) { /* 健壮性考虑 */ if (!s) return -1; /* 循环遍历s数组 */ int ret = 0; while ((*s) != '\0') { // 考虑特殊规则 if ((*s == 'I') && (*(s+1) == 'V')){ ret += 4; s += 2; }else if ((*s == 'I') && (*(s+1) == 'X')){ ret += 9; s += 2; }else if ((*s == 'X') && (*(s+1) == 'L')){ ret += 40; s += 2; }else if ((*s == 'X') && (*(s+1) == 'C')){ ret += 90; s += 2; }else if ((*s == 'C') && (*(s+1) == 'D')){ ret += 400; s += 2; }else if ((*s == 'C') && (*(s+1) == 'M')){ ret += 900; s += 2; }else { //正常情况 switch (*s) { case 'I': ret += 1; break; case 'V': ret += 5; break; case 'X': ret += 10; break; case 'L': ret += 50; break; case 'C': ret += 100; break; case 'D': ret += 500; break; case 'M': ret += 1000; break; } s++; } } return ret; }
3. 优点:时间复杂度为O(n)且不占用额外的存储空间。
4. 缺点:当特殊规则较多时,if-else分支就更多,使可读性下降。
三、官方解法
1. 思路:首先,找到特例的规则,即当前值小于后一元素的值则ans-=value;否则不是特例,执行ans+=value。
2. 代码:
int romanToInt(char* s) { int symbolValues[26]; symbolValues['I' - 'A'] = 1; symbolValues['V' - 'A'] = 5; symbolValues['X' - 'A'] = 10; symbolValues['L' - 'A'] = 50; symbolValues['C' - 'A'] = 100; symbolValues['D' - 'A'] = 500; symbolValues['M' - 'A'] = 1000; int ans = 0; int n = strlen(s); for (int i = 0; i < n; ++i) { int value = symbolValues[s[i] - 'A']; if (i < n - 1 && value < symbolValues[s[i + 1] - 'A']) { ans -= value; } else { ans += value; } } return ans; }
3. 优点:代码冗余少。
4. 缺点:①需要找到特例的规律;②实测下来,执行速度不如本人“初次解答”的算法快;③尽管空间复杂度为O(1),但仍然需要额外的存储空间。
四、C++写法
class Solution {
public:
int romanToInt(string s) {
unordered_map<char, int> m{ {'I', 1}, {'V', 5}, {'X', 10},
{'L', 50}, {'C', 100}, {'D', 500}, {'M', 1000} };
int sum = 0;
int length = s.length();
for (int i = 0; i < length; ++i) {
if (i+1 < s.size() && m[s[i+1]] > m[s[i]]) {
sum -= m[s[i]];
} else {
sum += m[s[i]];
}
}
return sum;
}
};
五、总结
当特例规则较少时,可以直接if-else枚举;若规则较多时,可以寻找特例的规律,从而减少代码冗余。