Move roman bits
This commit is contained in:
parent
ffb16efcdc
commit
8cc2e18965
57
leetcode/roman.py
Normal file
57
leetcode/roman.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
SIMPLE = {
|
||||||
|
"I": 1,
|
||||||
|
"V": 5,
|
||||||
|
"X": 10,
|
||||||
|
"L": 50,
|
||||||
|
"C": 100,
|
||||||
|
"D": 500,
|
||||||
|
"M": 1000,
|
||||||
|
}
|
||||||
|
SIMPLE_REVERSE = {v: k for k, v in SIMPLE.items()}
|
||||||
|
COMPOUND = {
|
||||||
|
"IV": 4,
|
||||||
|
"IX": 9,
|
||||||
|
"XL": 40,
|
||||||
|
"XC": 90,
|
||||||
|
"CD": 400,
|
||||||
|
"CM": 900,
|
||||||
|
}
|
||||||
|
PREFIXES = {k[0] for k in COMPOUND.keys()}
|
||||||
|
COMPOUND_REVERSE = {v: k for k, v in COMPOUND.items()}
|
||||||
|
ALL = SIMPLE | COMPOUND
|
||||||
|
ALL_REVERSE = {v: k for k, v in ALL.items()}
|
||||||
|
|
||||||
|
|
||||||
|
def i2r(i: int) -> str:
|
||||||
|
if i > 100_000:
|
||||||
|
raise ValueError(f"{i} is too silly")
|
||||||
|
|
||||||
|
r: list[str] = []
|
||||||
|
|
||||||
|
for int_val, roman_val in sorted(ALL_REVERSE.items(), reverse=True):
|
||||||
|
remainder = i % int_val
|
||||||
|
|
||||||
|
r += [roman_val] * int((i - remainder) / int_val)
|
||||||
|
|
||||||
|
i = remainder
|
||||||
|
|
||||||
|
return "".join(r)
|
||||||
|
|
||||||
|
|
||||||
|
def r2i(r: str) -> int:
|
||||||
|
total = 0
|
||||||
|
offset = 0
|
||||||
|
|
||||||
|
for i in range(len(r)):
|
||||||
|
if i + offset > len(r) - 1:
|
||||||
|
break
|
||||||
|
|
||||||
|
c = r[i + offset]
|
||||||
|
if c in PREFIXES and (i + offset + 1) < len(r) and c + r[i + offset + 1] in ALL:
|
||||||
|
total += ALL[c + r[i + offset + 1]]
|
||||||
|
offset += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
total += ALL[c]
|
||||||
|
|
||||||
|
return total
|
@ -79,70 +79,6 @@ def gen_matrix(width: int, height: int) -> list[list[int]]:
|
|||||||
return [list(range(width)) for _ in range(height)]
|
return [list(range(width)) for _ in range(height)]
|
||||||
|
|
||||||
|
|
||||||
class Roman:
|
|
||||||
SIMPLE = {
|
|
||||||
"I": 1,
|
|
||||||
"V": 5,
|
|
||||||
"X": 10,
|
|
||||||
"L": 50,
|
|
||||||
"C": 100,
|
|
||||||
"D": 500,
|
|
||||||
"M": 1000,
|
|
||||||
}
|
|
||||||
SIMPLE_REVERSE = {v: k for k, v in SIMPLE.items()}
|
|
||||||
COMPOUND = {
|
|
||||||
"IV": 4,
|
|
||||||
"IX": 9,
|
|
||||||
"XL": 40,
|
|
||||||
"XC": 90,
|
|
||||||
"CD": 400,
|
|
||||||
"CM": 900,
|
|
||||||
}
|
|
||||||
PREFIXES = {k[0] for k in COMPOUND.keys()}
|
|
||||||
COMPOUND_REVERSE = {v: k for k, v in COMPOUND.items()}
|
|
||||||
ALL = SIMPLE | COMPOUND
|
|
||||||
ALL_REVERSE = {v: k for k, v in ALL.items()}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def i2r(cls, i: int) -> str:
|
|
||||||
if i > 100_000:
|
|
||||||
raise ValueError(f"{i} is too silly")
|
|
||||||
|
|
||||||
r: list[str] = []
|
|
||||||
|
|
||||||
for int_val, roman_val in sorted(cls.ALL_REVERSE.items(), reverse=True):
|
|
||||||
remainder = i % int_val
|
|
||||||
|
|
||||||
r += [roman_val] * int((i - remainder) / int_val)
|
|
||||||
|
|
||||||
i = remainder
|
|
||||||
|
|
||||||
return "".join(r)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def r2i(cls, r: str) -> int:
|
|
||||||
total = 0
|
|
||||||
offset = 0
|
|
||||||
|
|
||||||
for i in range(len(r)):
|
|
||||||
if i + offset > len(r) - 1:
|
|
||||||
break
|
|
||||||
|
|
||||||
c = r[i + offset]
|
|
||||||
if (
|
|
||||||
c in cls.PREFIXES
|
|
||||||
and (i + offset + 1) < len(r)
|
|
||||||
and c + r[i + offset + 1] in cls.ALL
|
|
||||||
):
|
|
||||||
total += cls.ALL[c + r[i + offset + 1]]
|
|
||||||
offset += 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
total += cls.ALL[c]
|
|
||||||
|
|
||||||
return total
|
|
||||||
|
|
||||||
|
|
||||||
class MinStack:
|
class MinStack:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._v: list[int] = []
|
self._v: list[int] = []
|
||||||
|
15
leetcode/test_roman.py
Normal file
15
leetcode/test_roman.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
import roman
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("n", "expected"),
|
||||||
|
[
|
||||||
|
(3, "III"),
|
||||||
|
(58, "LVIII"),
|
||||||
|
(1994, "MCMXCIV"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_int_to_roman(n: int, expected: str):
|
||||||
|
assert roman.i2r(n) == expected
|
@ -19,18 +19,6 @@ def test_find_sqrt_ish(n: int, expected: int):
|
|||||||
assert stuff.find_sqrt_ish(n) == expected
|
assert stuff.find_sqrt_ish(n) == expected
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
("n", "expected"),
|
|
||||||
[
|
|
||||||
(3, "III"),
|
|
||||||
(58, "LVIII"),
|
|
||||||
(1994, "MCMXCIV"),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def test_int_to_roman(n: int, expected: str):
|
|
||||||
assert stuff.Roman.i2r(n) == expected
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("ops", "expected"),
|
("ops", "expected"),
|
||||||
[
|
[
|
||||||
|
Loading…
Reference in New Issue
Block a user