python https://www.algospot.com/judge/problem/read/DECUAL
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python https://www.algospot.com/judge/problem/read/DECUAL相关的知识,希望对你有一定的参考价值。
# -*- coding: utf-8 -*-
# 정수 문자열 찾아줌
# => (처음 non-digit가 나타난 index, 구한 정수값)
def find_digits(s):
for i in xrange(len(s)):
if s[i] < '0' or s[i] > '9':
return (i, int(s[:i]))
return (i+1, int(s))
# parser generator
# 파싱된 토큰을 순차적으로 반환하는 iterator 함수 반환
def generate_parser(s):
# 문자열 내 현재 위치
i = 0
l = len(s)
# 토큰 시작 위치, 토큰 끝 위치
p1 = p2 = 0
# 토큰 문자열
tok = ""
while(i<l):
# '(' 를 찾을 때까지 건너뜀
if s[i] != '(':
i += 1
continue
# '(' 이전의 문자열을 tok에 붙여줌
if p1 != i: tok += s[p1:i]
# '(mmm)^n' 패턴을 찾아서 토큰으로 만들어줌
p1 = i+1
p2 = s[p1:].index(')')
idx, cnt = find_digits(s[p1+p2+2:])
# 이 때 반복수가 1 이거나 확장된 길이가 100 이하이면 기존 토큰에 이어 붙임
if (cnt == 1) or (p2*cnt <= 100):
#if cnt <= 3:
tok += s[p1:p1+p2]*cnt
# 이제 토큰을 반환할 때가 되었다!
else:
# 우선 기존에 모으고 있던 토큰을 먼저 반환하고
if len(tok): yield (tok, 1)
tok = ""
# 반복수가 1보다 큰 다음 토큰도 이어서 반환함
yield (s[p1:p1+p2], cnt)
# 토큰 시작 위치 재조정
p1 = i = p1+p2+idx+2
# 문자열 파싱은 끝났지만 아직 반환 안 한 토큰이 남아 있다면 마지막으로 반환해줌
if p1 < i: tok += s[p1:i]
if len(tok): yield (tok, 1)
# 주어진 문자열을 파싱하여 (token, count) 원소를 가지는 배열과 최종 문자열 길이 반환
# 예제: ABC(ABC)^99999997(ABC)^1ABCAA
# => ([('ABC', 1), ('ABC', 99999997), ('ABCABCAA', 1)], 300000002)
def parse_str(s):
Q = []
tlen = 0
for g in generate_parser(s):
Q.append(g)
tlen += len(g[0])*g[1]
return (Q, tlen)
# 큐의 첫 번째 토큰이 l보다 짧은 경우 사용
# 주어진 길이의 토큰을 만들기 위해 반복수를 줄이고 그래도 안 되면 다음 토큰을 확장하게 됨
# 반환값: 길이 l의 토큰, 만약 큐에 남은 토큰이 더 이상 없으면 현재까지 구한 토큰 반환
def borrow_next_token(l, Q):
if len(Q) == 0: return ""
s, c = Q.pop(0)
sl = len(s)
# 결과 토큰, 채워야 할 길이, 빌려 쓰는 토큰의 남은 반복수
ts, tl, tc = s, l-sl, c-1
# 채워야 할 길이가 남아 있거나 빌려 쓰는 토큰의 반복수가 남아 있는 동안
while tl > 0 and tc > 0:
ts, tl, tc = ts+s, tl-sl, tc-1
# 길이 l인 토큰이 만들어졌다면
if tl == 0:
# 토큰의 반복수가 남아 있다면 큐에 다시 넣어줌
if tc > 0: Q.insert(0, (s, tc))
return ts
# 여전히 l보다 짧다면
if tl > 0:
# 다음 토큰에서 더 빌려오자! 빚쟁이가 되고 있다!
return ts + borrow_next_token(tl, Q)
# 결과 토큰이 l보다 길어졌다면
else:
# 결과 토큰의 남은 부분을 빌려 쓰는 토큰 앞에 결합하고 반복수를 재조정
# A(RUN)^50 에 l=2를 적용하면 => AR, (UNR)^49UN
ts1, ts2 = ts[:tl], ts[tl:]
if len(ts2): Q.insert(0, (ts2, 1))
if tc > 0: Q.insert(0, (ts2+s[:tl], tc))
return ts1
# 큐의 첫 번째 토큰의 길이가 l이 되도록 재조정
def resize_token(l, Q):
# 첫 번째 토큰 길이가 이미 l이면 더 볼 것 없음
if len(Q[0][0]) == l: return
s, c = Q.pop(0)
sl = len(s)
# 토큰의 길이가 l보다 크면
if sl > l and c == 1:
# 두 개의 토큰으로 쪼개어 큐에 다시 넣음
Q.insert(0, (s[l:], 1))
Q.insert(0, (s[:l], 1))
return
d, m = divmod(l, sl)
if m: d += 1
# 토큰의 반복수를 다 쓰고도 길이가 l보다 짧으면
if d > c:
s1 = s*c
# 다음 토큰에서 모자란 길이를 보충
s2 = borrow_next_token(l-len(s1), Q)
if len(s2) == 0: return
s1 += s2
Q.insert(0, (s1, 1))
# 토큰의 반복수를 적용해서 길이가 l보다 길어지면
else:
# 남은 반복수만큼 큐에 넣고
if c-d > 0: Q.insert(0, (s, c-d))
# 길이가 l 이상이 된 토큰을 큐에 넣음
Q.insert(0, (s*d, 1))
# 아직 첫 번째 토큰의 길이가 l이 되지 않았으므로 이 과정을 반복함
resize_token(l, Q)
def check_multiple(Q1, Q2):
# Q1에 들어 있는 첫 번째 토큰이 긴 것이 되도록 위치 교환
if len(Q1[0][0]) < len(Q2[0][0]):
Q1, Q2 = Q2, Q1
s1, c1 = Q1[0]
s2, c2 = Q2[0]
l1, l2 = len(s1), len(s2)
# 긴 토큰의 길이가 짧은 토큰 길이의 배수인지 확인
d, m = divmod(l1, l2)
if m: return False
# 짧은 토큰을 반복하여 긴 토큰과 같다면
if s1 == (s2*d):
# 긴 토큰을 큐에서 빼내고 짧은 토큰의 반복수를 d배 하여 큐 앞 쪽에 다시 넣음
Q1.pop(0)
Q1.insert(0, (s2, c1*d))
return True
return False
def compare_sub(Q1, Q2):
# 큐가 둘 다 비었으면 True, 하나만 비었으면 False
if len(Q1) == 0:
if len(Q2) == 0: return True
else: return False
s1, c1 = Q1[0]
s2, c2 = Q2[0]
l1, l2 = len(s1), len(s2)
# 각 큐의 첫 번째 토큰의 길이가 같으면
if l1 == l2:
# 두 토큰이 같다면, 토큰 반복 개수를 감하고, 남은 쪽은 다시 큐에 넣어줌
if s1 == s2:
Q1.pop(0)
Q2.pop(0)
if c1 > c2: Q1.insert(0, (s1, c1-c2))
elif c1 < c2: Q2.insert(0, (s2, (c2-c1)))
# 이번 토큰은 무사 통과
return True
# 토큰 길이가 같은데 문자열이 다르다면 더 볼 것 없음
else: return False
# 두 토큰의 길이가 다르면
else:
# 긴 토큰이 짧은 토큰의 반복 패턴인지 체크
if not check_multiple(Q1, Q2):
# 반복 패턴이 아니라면 짧은 토큰의 길이를 늘여줌
if l1 > l2: resize_token(l1, Q2)
else: resize_token(l2, Q1)
# 그리고 다시 비교
return compare_sub(Q1, Q2)
def compare(S1, S2):
# 문자열 그 자체를 비교
if S1 == S2: return True
# 문자열 파싱한 결과와 최종 길이 구함
# ABC(ABC)^99999997(ABC)^1ABCAA
# => 길이 : 300000002
# => 파싱 결과 큐: [('ABC', 1), ('ABC', 99999997), ('ABCABCAA', 1)]
Q1, L1 = parse_str(S1.strip())
Q2, L2 = parse_str(S2.strip())
# 길이가 다르면 더 볼 것 없음
if L1 != L2: return False
# 큐에 토큰이 남아 있는 동안 계속 비교
while(len(Q1) and len(Q2)):
if not compare_sub(Q1, Q2):
return False
# 두 큐 중 하나라도 토큰이 남아 있으면 두 문자열은 다른 거임
if len(Q1) or len(Q2):
return False
return True
if __name__=="__main__":
ANS = {True:"YES", False:"NO"}
T = input()
for _ in xrange(T):
print ANS[compare(raw_input(), raw_input())]
以上是关于python https://www.algospot.com/judge/problem/read/DECUAL的主要内容,如果未能解决你的问题,请参考以下文章