問題:
https://leetcode.com/problems/roman-to-integer/
正解者さん:
https://leetcode.com/problems/roman-to-integer/discuss/965594/Python
class Solution(object):
def romanToInt(self, s):
rd = {
"I" : 1,
"V" : 5,
"X" : 10,
"L" : 50,
"C" : 100,
"D" : 500,
"M" : 1000
}
n = len(s)
rt = 0
for i in range(n):
if i==n-1 or rd[s[i]] >= rd[s[i+1]] :
rt += rd[s[i]]
else :
rt -= rd[s[i]]
return rt
まず、
Input: s = "III"
Output: 3
とする。
次に、
rd = {
"I" : 1,
"V" : 5,
"X" : 10,
"L" : 50,
"C" : 100,
"D" : 500,
"M" : 1000
}
と書いてアルファベットと数字を関連付けた辞書を作る。
次に、
n = len(s)
で、sの中の要素数を数える
(n=3)
次に、
for i in range(n):
で、0,1,2がiに入っていく間に下のコードを実行する。
次に、
if i==n-1 or rd[s[i]] >= rd[s[i+1]] :
rt += rd[s[i]]
で、もしi(0)がn-1(2)の数字と同じ、
または、"III"の0番目であるrdの辞書内の要素("I"(1))が、"III"の0+1番目("I"(1))よりも大きいか同じだったら、
rt = 0に、{rt(0) + "III"の0番目であるrdの辞書内の要素("I"(1))}の値を入れる。
(rt = 1)
次に、
else :
rt -= rd[s[i]]
で、それ以外だったら{rt(0) - "III"の0番目であるrdの辞書内の要素("I"(1))}の値をrt = 0に入れる。
(rt = -1)
次に、
if i==n-1 or rd[s[i]] >= rd[s[i+1]] :
rt += rd[s[i]]
を繰り返す。
もしも 1が2と同じか、"III"の1番目であるrdの辞書内の要素("I"(1))が、"III"の1+1番目("I"(1))よりも大きいか同じだったら、
rt = 1に、{rt(1) + "III"の1番目であるrdの辞書内の要素("I"(1))}の値を入れる。
(rt = 2)
また、
if i==n-1 or rd[s[i]] >= rd[s[i+1]] :
rt += rd[s[i]]
を繰り返す。
もしも 2が2と同じか、"III"の2番目であるrdの辞書内の要素("I"(1))が、"III"の2+1番目("I"(1))よりも大きいか同じだったら、
rt = 2に、{rt(2) + "III"の1番目であるrdの辞書内の要素("I"(1))}の値を入れる。
(rt = 3)
次に、
for i in range(n):
を確認してみると、この時点でn(0,1,2)が全てiに入ってしまっているため、forループ文は終了する。
最後に、
return rt(3)
となり、正解にたどり着く。
別の値を入れてみよう。
Input: s = "MCMXCIV"
Output: 1994
とする。
次に、
n = len(s)
で、sの中の要素数を数える
(n=7)
for i in range(n):
で、0,1,2,3,4,5,6がiに入っていく間に下のコードを実行する。
次に、
if i==n-1 or rd[s[i]] >= rd[s[i+1]] :
rt += rd[s[i]]
で、もしi(0)がn-1(6)の数字と同じ、
または、"MCMXCIV"の0番目であるrdの辞書内の要素("M"(1000))が、"MCMXCIV"の0+1番目("C"(100))よりも大きいか同じだったら、
rt = 0に、{rt(0) + "MCMXCIV"の0番目であるrdの辞書内の要素("M"(1000)}の値を入れる。
(rt = 1000)
次に、
if i==n-1 or rd[s[i]] >= rd[s[i+1]] :
rt += rd[s[i]]
を繰り返す。
今回は、1が6と同じか、"MCMXCIV"の1番目であるrdの辞書内の要素("C"(100))が、"MCMXCIV"の1+1番目("M"(1000))よりも大きいか同じではないので、
else :
rt -= rd[s[i]]
を使う。{rt(1000) - "MCMXCIV"の1番目であるrdの辞書内の要素("C"(100))}の値をrtに入れる。
(rt = 900)
次に、
if i==n-1 or rd[s[i]] >= rd[s[i+1]] :
rt += rd[s[i]]
で、もし2が6と同じ、
または、"MCMXCIV"の2番目であるrdの辞書内の要素("M"(1000))が、"MCMXCIV"の2+1番目("X"(10))よりも大きいか同じだったら、
rt = 900に、{rt(900) + "MCMXCIV"の2番目であるrdの辞書内の要素("M"(1000)}の値を入れる。
(rt = 1900)
と繰り返していく。(長いので省略)
今回の肝は、
・I can be placed before V (5) and X (10) to make 4 and 9.
・X can be placed before L (50) and C (100) to make 40 and 90.
・C can be placed before D (500) and M (1000) to make 400 and 900.
という縛りをいかに解決するかである。
この縛りが無ければ、
rt += rd[s[i]]
を何回も繰り返して足し算すればいい。
しかし、これだと、IVのときは、VからIが引かれて4になるという引き算ができなくなる。
そのため、もしもIがVよりも小さかった場合、Iの値を合計から引く、つまり、後で足されるVの値から先にIを引いておく必要がある。