From 8cc2e1896504ba396d7292294775711bd60d39be Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 24 Oct 2023 15:48:15 -0400 Subject: [PATCH] Move roman bits --- leetcode/roman.py | 57 +++++++++++++++++++++++++++++++++++++ leetcode/stuff.py | 64 ------------------------------------------ leetcode/test_roman.py | 15 ++++++++++ leetcode/test_stuff.py | 12 -------- 4 files changed, 72 insertions(+), 76 deletions(-) create mode 100644 leetcode/roman.py create mode 100644 leetcode/test_roman.py diff --git a/leetcode/roman.py b/leetcode/roman.py new file mode 100644 index 0000000..88cdf91 --- /dev/null +++ b/leetcode/roman.py @@ -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 diff --git a/leetcode/stuff.py b/leetcode/stuff.py index 8c1f04d..361c704 100644 --- a/leetcode/stuff.py +++ b/leetcode/stuff.py @@ -79,70 +79,6 @@ def gen_matrix(width: int, height: int) -> list[list[int]]: 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: def __init__(self): self._v: list[int] = [] diff --git a/leetcode/test_roman.py b/leetcode/test_roman.py new file mode 100644 index 0000000..f480a51 --- /dev/null +++ b/leetcode/test_roman.py @@ -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 diff --git a/leetcode/test_stuff.py b/leetcode/test_stuff.py index 8d48ae7..2959a7d 100644 --- a/leetcode/test_stuff.py +++ b/leetcode/test_stuff.py @@ -19,18 +19,6 @@ def test_find_sqrt_ish(n: int, expected: int): 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( ("ops", "expected"), [