Skip to content

Instantly share code, notes, and snippets.

@hanjae-jea
Created October 12, 2025 14:54
Show Gist options
  • Save hanjae-jea/4da387cbff9a089d36ab7a2e5a9c6aea to your computer and use it in GitHub Desktop.
Save hanjae-jea/4da387cbff9a089d36ab7a2e5a9c6aea to your computer and use it in GitHub Desktop.
def test_extract():
res = extract('matt is the best school in korea')
assert res == 'MICLI', res
# 첫 번째 규칙: 보통 큰 숫자가 왼쪽 > 작은 숫자 오른쪽,
# 숫자의 값을 더한 값이 총합이다.
def test_passes_rule1():
r1, _ = rule1('MICLI')
assert r1 == False
r2, s2 = rule1('MCI')
assert r2 == True and s2 == 1101, s2
# 두 번째 규칙: 기호 V, L, D는 한 번만 사용할 수 있고, I,X,C는 **연속**해서 **세 번**까지만 쓸 수 있다.
# M은 몇 번이고 사용할 수 있다.
def test_passes_rule2():
t1, _ = rule2('MLLV')
assert t1 == False
t2, _ = rule2('VV')
assert t2 == False
t2_1, _ = rule2('DLLI')
assert t2_1 == False
t3, _ = rule2('LXIIII')
assert t3 == False
t4, s4 = rule2('LXIII')
assert t4 == True and s4 == 50 + 10 + 3, s4
# 세 번째 규칙
# IV = 4, IX = 9, XL = 40, XC = 90, CD = 400, CM = 900
# 각각 한 번씩 사용할 수 있다. 근데, (IV, IX) , (XL,XC), (CD, CM) 은 같이 나올 수 없다.
# 그리고 이들 외에는 작은 숫자가 큰 숫자 왼쪽 어디에도 나올 수 없다.
def test_rule3_convert():
t1_s = rule3_convert('XCXC')
assert t1_s == 'EE', t1_s
t2 = rule3_convert('CMCD')
assert t2 == 'QW', t2
t3 = rule3_convert('VX')
assert t3 == 'VX', t3
t4 = rule3_convert('IIX')
assert t4 == 'IT'
t5 = rule3_convert('IXIV')
assert t5 == 'TY'
t6 = rule3_convert('XLCM')
assert t6 == 'RQ'
t6_1 = rule3_convert('CMXL')
assert t6_1 == 'QR'
t6_2 = rule3_convert('CMLXIV')
assert t6_2 == 'QLXY'
t7 = rule3_convert('MCMXL')
assert t7 == 'MQR'
def test_passes_rule3():
# '아, rule1 재활용이 안되겠다.'
t1, _ = rule3('XCXC')
assert t1 == False
t2, _ = rule3('CMCD')
assert t2 == False, (t2, _)
t3, _ = rule3('VX')
assert t3 == False
t4, _ = rule3('IIX')
assert t4 == False
t5, _ = rule3('IXIV')
assert t5 == False
t6, _ = rule3('XLCM')
assert t6 == False
t6_1, s6_1 = rule3('CMXL')
assert t6_1 == True and s6_1 == 900 + 40, (t6_1, s6_1)
t6_2, s6_2 = rule3('CMLXIV')
assert t6_2 == True and s6_2 == 900 + 60 + 4
t7, s7 = rule3('MCMXL')
assert t7 == True and s7 == 1940
# 네 번째 규칙
# 가장 적은 개수의 로마 숫자로 표현 해야 한다
# 60 = LX , XLXX -> False, IVI -> False
def test_passes_rule4():
t1, s1 = rule4('LX')
assert t1 == True and s1 == 60
t2, s2 = rule4('XLXX')
assert t2 == False
t3, s3 = rule4('IVI')
assert t3 == False
# 여러 숫자도 표현할 수 있다고 볼 수 있으면 가장 큰 수를 출력해라
'''rome_dic = {
'M': 1000,
'Q': 900,
'D': 500,
'W': 400,
'C': 100,
'E': 90,
'R': 40,
'L': 50,
'X': 10,
'T': 9,
'V': 5,
'Y': 4,
'I': 1
}'''
# 첫 번째 처리: M은 그냥 많이 나오는게 좋다
# MM(!@*#&!@#)M(!@*@!#)M(!@#) -> MMMM(!@#)
# CM -> M
# 일단 M을 뽑아서 M사이에 거치적 거리는걸 지운다
def test_check_run1():
t1 = run1('MIVM')
assert t1 == 'MM', t1
t2 = run1('MIVMC')
assert t2 == 'MMC', t2
t3 = run1('MCM')
assert t3 == 'MM', t3
t4 = run1('MIVMCVII')
assert t4 == 'MMCVII', t4
# 두 번째 처리: D가 나오면,
# (p1)D(p2)D(p3)D(p4) ..
# Dp2 / Dp3 / Dp4 중에 가장 큰 수가 답이다
def test_check_run2():
t1 = run2('CIID')
assert t1 == 'D', t1
t2 = run2('CIIDXIIDCII')
assert t2 == 'DCII', t2
t3 = run2('MMMCIIDXIIDCII')
assert t3 == 'MMMDCII', t3
# 세 번째 처리: C에 대해서
# (p1)C(p2)C(p3)C(p4)C(p5)C(p6)C(p7)C(p8)C(p9)
# CC? -> 절대 불가능
# CD = 400? -> 절대 불가능 -> run2에서 CD는 안 보기로 했음
# CCC(p4/p5/p6)
# 약간 M이랑 비슷해지는 것 같기도...최대 제약이 3회이고 나머지 중에서 최대를 골라야 한다
# 3 번 뒤부터 나오는 것들 중에서 최대를 골라야 한다. 그 전이면 상관없이 C부터 골라야 한다
# 미구현 상태
def test_check_run3():
t1 = run3('MMMDXXCXXCXXCXXCXXCXXCXXCXX')
assert t1 == 'MMMDCCCXX'
t2 = run3('MMMD(XX)-(CXLX)`(CLXX)`(CXXV)(CXXI)(CXXVII)(CXXVI)(CXXVI)')
assert t2 == 'MMMDCCCXXVII'
# L 은 D랑 똑같다.
# X는 C랑 똑같다.
# V는 D랑 똑같다.
# I는 똑같지만 뭐 없다.
rome_chars = 'IVXLCDM'
def extract(s: str) -> str:
res = ''
for c in s.upper():
if c in rome_chars:
res += c
return res
rome_dic = {
'M': 1000,
'Q': 900,
'D': 500,
'W': 400,
'C': 100,
'E': 90,
'R': 40,
'L': 50,
'X': 10,
'T': 9,
'V': 5,
'Y': 4,
'I': 1
}
def rule1(s: str) -> tuple[bool, int]:
sumation = 0
for i in range(len(s)):
sumation += rome_dic[s[i]]
if i+1 < len(s) and rome_dic[s[i]] < rome_dic[s[i+1]]:
return False, 0
return True, sumation
only_once = 'VLDQWERTY'
three_in_a_row = 'IXC'
def rule2(s: str) -> tuple[bool, int]:
rule1_result, sumation = rule1(s)
if rule1_result == False:
return rule1_result, sumation
for c in only_once:
if s.count(c) > 1:
return False, 0
for c in three_in_a_row:
if s.count(c) > 3: # 최대 3번 까지
return False, 0
# 연속인지 아닌지 검증 -> rule1 을 통과하고 있다면, 안해도 되긴 해요
# 나중에 rule1에 예외가 존재할 수 있다는 걸 안다면
# 여기서 솔직히 **연속**도 점검을 해두는게 맞긴 하다.
if c * s.count(c) not in s: # X 가 두번 있다면 무조건 XX 형태로 존재해야 하니
# c * s.count(c) -> X * 2 -> 'XX' -> s 안에 있어야 한다
return False, 0
# 최대 연속으로 3번 등장
return rule1_result, sumation
rome_2char_dic = {
'CM': 'Q', # 900
'CD': 'W', # 400
'XC': 'E', # 90
'XL': 'R', # 40
'IX': 'T', # 9
'IV': 'Y' # 4
}
def rule3_convert(s: str) -> str:
for k, v in rome_2char_dic.items():
s = s.replace(k, v)
return s
def rule3(s: str) -> tuple[bool, int]:
# rule1을 그대로 쓰면 안된다.
# 1. 치환을 잘 했는지 체크 (rule3_convert)
# 2. 규칙을 지켰는지 체크
# (각각 한 번씩 사용할 수 있다.) 근데, (IV, IX) , (XL,XC), (CD, CM) 은 같이 나올 수 없다.
s = rule3_convert(s)
result, sumation = rule2(s)
if result == False:
return result, sumation
if s.count('Q') > 0 and s.count('W') > 0 or \
s.count('E') > 0 and s.count('R') > 0 or \
s.count('T') > 0 and s.count('Y') > 0:
return False, 0
return result, sumation
def rule4(s):
return rule3(s)
# extract 되어있는 s
def run1(s: str) -> str:
# M 갯수 구하고, 마지막 M 인덱스 뒤에 있는 것들을 붙인다
m_count = s.count('M')
if m_count > 0:
return ('M' * m_count) + s[s.rfind('M') + 1:]
else:
return s
# D 단위로 쪼개고, 물론 없으면 전체 return
# D로 시작하는 단위로 각각 쪼개고, 그 중에 최선을 선택
# CD는요? -> 안써요 -> CD 보다는 D 가 더 큰수라서요
def run2(s: str) -> str:
s = run1(s)
m_count = s.count('M')
s = s.replace('M', '')
idx = 0
largest_substr_and_sumation: tuple[str, int] = '', 0
while idx != -1:
pos = s.find('D', idx)
if pos == -1:
if idx == 0:
substr = s[idx:]
else:
substr = s[idx-1:]
idx = -1
else:
if idx == 0:
substr = s[idx:pos]
else:
substr = s[idx-1:pos]
idx = pos + 1
result, sumation = rule4(substr)
if result == True and largest_substr_and_sumation[1] < sumation:
largest_substr = substr, sumation
return f'{"M" * m_count}{largest_substr[0]}'
test_extract()
test_passes_rule1()
test_passes_rule2()
test_rule3_convert()
test_passes_rule3()
test_check_run1()
test_check_run2()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment