給定一個羅馬數字(範圍 1~3999),將其轉換為阿拉伯數字;反之亦然。羅馬數字符號及對應值如下:
| 符號 | I | V | X | L | C | D | M |
|---|---|---|---|---|---|---|---|
| 值 | 1 | 5 | 10 | 50 | 100 | 500 | 1000 |
III = 3)。IV = 4, IX = 9)。核心邏輯:從左至右掃描,若當前字元值 大於等於 下一字元值,則 相加;若 小於 下一字元值,則 相減(實際上為:加上下一字元值,並扣除兩倍當前字元值)。
XVIII → 10, 5, 1, 1, 1 → 全遞減/相等 → 總和 = 18XIX → 10, 1, 10 → 1 < 10 觸發減法:10 + 1 + 10 - 2×1 = 19unsigned int roman2integer(const string& str) {
if (str.empty()) return 0;
static const unordered_map<char, int> m = {
{'I',1}, {'V',5}, {'X',10}, {'L',50},
{'C',100}, {'D',500}, {'M',1000}
};
int sum = m.at(str[0]);
for (size_t i = 0; i + 1 < str.size(); ++i) {
if (m.at(str[i]) >= m.at(str[i+1]))
sum += m.at(str[i+1]);
else
sum += m.at(str[i+1]) - 2 * m.at(str[i]);
}
return sum;
}
核心策略:將所有「減法組合」視為基本符號,建立 值-符號對應表,按值從大到小貪婪匹配。
值: 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1
符號: "M", "CM","D", "CD","C", "XC","L","XL","X","IX","V","IV","I"
string integer2roman(unsigned int n) {
if (n < 1 || n > 3999) return "";
static const unsigned int val[] = {1000,900,500,400,100,90,50,40,10,9,5,4,1};
static const string sym[] = {"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
string res;
for (size_t i = 0; i < sizeof(val)/sizeof(val[0]); ++i) {
while (n >= val[i]) {
res += sym[i];
n -= val[i];
}
}
return res;
}
雙向轉換測試:對 1~3999 每個整數 n,計算 r = integer2roman(n),再計算 m = roman2integer(r),斷言 n == m。若全通過,證明實作正確。
void test_case(int n) {
for (int i = 1; i <= n; ++i) {
string roman = integer2roman(i);
int integer = roman2integer(roman);
assert(i == integer);
}
}
程式包含兩個核心函式 roman2integer、integer2roman、測試函式 test_case 及 main 入口。編譯執行後無輸出即代表所有測試通過。