# 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/