2 reference approaches in C++, from brute force to the one to reach for. Compare them with yours.
The standard library has no replace-all for strings, so a small helper loops find and replace until the pattern is gone. Six calls rewrite the subtractive pairs additively (IX to VIIII, CM to DCCCC), and an unordered_map<char, int> sums what is left. s arrives by value, so rewriting it touches only our own copy.
#include <algorithm>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
using namespace std;
class Solution {
public:
int romanToInt(string s) {
static const unordered_map<char, int> values = {
{'I', 1}, {'V', 5}, {'X', 10}, {'L', 50}, {'C', 100}, {'D', 500}, {'M', 1000},
};
static const vector<pair<string, string>> spelled = {
{"IV", "IIII"}, {"IX", "VIIII"}, {"XL", "XXXX"}, {"XC", "LXXXX"}, {"CD", "CCCC"}, {"CM", "DCCCC"},
};
for (const auto& [from, to] : spelled) replaceAll(s, from, to);
int total = 0;
for (char ch : s) total += values.at(ch);
return total;
}
private:
static void replaceAll(string& s, const string& from, const string& to) {
for (size_t pos = s.find(from); pos != string::npos; pos = s.find(from, pos + to.size())) {
s.replace(pos, from.size(), to);
}
}
};
Walk from the last character to the first, keeping the value of the letter to the right in prev. A letter worth less than prev opens a subtractive pair and is subtracted; every other letter is added. A switch maps each char to its value, so there is no hashing and no allocation.
#include <algorithm>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
using namespace std;
class Solution {
public:
int romanToInt(string s) {
int total = 0;
int prev = 0; // value of the letter to the right
for (int i = (int)s.size() - 1; i >= 0; i--) {
int v = value(s[i]);
total += v < prev ? -v : v;
prev = v;
}
return total;
}
private:
static int value(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;
}
}
};