# 13. Roman to Integer
**練習日期:** 2026-02-08
**難度:** Easy
**類型:** Hash Table、Math、String
## 📘 題目敘述
給你一個羅馬數字字串 `s`,請把它轉換成整數並回傳。
羅馬數字使用下列七個不同的符號表示,並對應不同的數值:
* `I` = 1
* `V` = 5
* `X` = 10
* `L` = 50
* `C` = 100
* `D` = 500
* `M` = 1000
例如 `2` 寫成 `II`,也就是 2 個 1 相加。`12` 寫成 `XII`,也就是 `X + II`。
通常情況下,羅馬數字由左到右從大到小排列。但有六種特殊情況會用「減法表示」:
* `I` 可以放在 `V`(5)和 `X`(10)前面,形成 `IV`(4)和 `IX`(9)
* `X` 可以放在 `L`(50)和 `C`(100)前面,形成 `XL`(40)和 `XC`(90)
* `C` 可以放在 `D`(500)和 `M`(1000)前面,形成 `CD`(400)和 `CM`(900)
題目保證 `s` 是一個有效的羅馬數字,範圍在 `1` 到 `3999`。
### 條件限制
* `1 <= s.length <= 15`
* `s` 只包含字元 `('I', 'V', 'X', 'L', 'C', 'D', 'M')`
* 題目保證 `s` 是有效的羅馬數字,範圍在 `[1, 3999]`
## 🧠 解題思路
這題最重要的地方是「減法表示」:像 `IV` 其實不是 `1 + 5`,而是 `5 - 1`。
我用從左到右掃描的方式處理,並且只記住「上一個符號的值」就夠了。
我用 `before` 表示上一個羅馬符號的數值,`now` 表示目前這個符號的數值。每次讀到一個新符號後:
* 一般情況:`now <= before`
代表是正常的由大到小排列,我直接把 `now` 加到答案上。
* 減法情況:`now > before`
代表上一個符號其實應該要被減掉(例如 `IV` 讀到 `V` 時 `now=5`、`before=1`)。
但我前一步其實已經把 `before` 加進 `ans` 了,所以現在要把它修正回「減法」效果:
目標應該是:`ans` 這一段貢獻要變成 `now - before`
但目前 `ans` 早就變成 `... + before + now`
所以我要做的修正是:再加上 `-2 * before`,也就是:
`ans = ans + now - 2 * before`
這就是你程式裡那行的由來。
至於怎麼把字元轉成數值,我用兩個陣列 `sym` / `val` 做對照,每次遇到字元就去找它是哪個符號,拿到對應的值。
### 所有變數
* `now`:目前掃到的羅馬符號對應的數值
* `before`:上一個掃到的羅馬符號對應的數值
* `ans`:累加後的整數答案
* `val`:大小為 7 的陣列,依序存 `I,V,X,L,C,D,M` 的數值
* `sym`:大小為 7 的陣列,依序存羅馬符號 `I,V,X,L,C,D,M`
## 🪜 主要流程步驟
### 1. 先準備羅馬符號對照表,並初始化狀態
我先用 `sym` / `val` 建立符號到數值的對應。
然後把 `ans` 初始化為 0,並用 `before = 10000` 當作一個「比所有符號都大」的初始值,避免一開始就被判成減法。
---
### 2. 從左到右掃描字串,找出每個字元對應的數值 `now`
對每個字元 `c`,我用一個小迴圈去對照 `sym`,找到相同符號後就把 `now = val[i]` 設好,代表目前符號的數值。
---
### 3. 根據 `now` 和 `before` 判斷是正常加法還是減法修正
如果 `now > before`,代表出現像 `IV`、`IX` 這種減法情況。因為上一輪已經把 `before` 加進 `ans` 了,所以我要用:
`ans = ans + now - 2 * before`
把「+before」修正成「-before」。
如果 `now <= before`,代表正常排列,直接做:
`ans += now`
---
### 4. 更新 `before`,準備處理下一個字元
每處理完一個字元,我就把 `before = now`,讓下一輪可以用它來判斷是否出現減法。
### 5. 回傳 `ans`
掃描結束後回傳答案。
## 💻 程式碼實作
```cpp
class Solution {
public:
int romanToInt(string s) {
int now = 0, before = 10000;
int ans = 0;
int val[7] = {1, 5, 10, 50, 100, 500, 1000};
char sym[7] = {'I', 'V', 'X', 'L', 'C', 'D', 'M'};
for (char c : s) {
for (int i = 0; i < 7; i++) {
if (c == sym[i]) {
now = val[i];
if (now > before) {
ans = ans + now - 2 * before;
} else {
ans += now;
}
before = now;
break;
}
}
}
return ans;
}
};
```
## 🔗 題目連結
https://leetcode.com/problems/roman-to-integer/description/