문제
1544번 사이클 단어
시간 제한 메모리 제한 제출 정답 맞힌 사람 정답 비율
2 초 128 MB 3685 2271 1888 64.547%
문제
사이클 단어는 어떤 단어를 원형 모양으로 차례대로 쓴 것이다. 따라서, 어떤 단어를 이렇게 쓴 후에 임의의 단어를 고른다. 그 후에 시계방향으로 차례대로 읽으면 그 것이 단어가 된다. 만약에 단어 A와 단어 B가 있을 때, 단어 B를 원형으로 써서, 단어 A와 같이 읽을 수 있으면, 두 단어는 같은 단어이다. 따라서, picture와 turepic은 같은 단어다.
N개의 단어가 주어졌을 때, 서로 다른 단어가 총 몇 개인지 구하는 프로그램을 작성하시오.
입력
첫째 줄에 단어의 개수 N이 주어진다. 둘째 줄부터 단어가 한 줄에 하나씩 주어진다. 단어는 영어 소문자로만 이루어져 있다. N은 50보다 작거나 같은 자연수이며, 단어의 길이는 최대 50이다.
출력
첫째 줄에 서로 다른 단어가 몇 개인지 출력한다.
예제 입력 1
5
picture
turepic
icturep
word
ordw
예제 출력 1
2
예제 입력 2
7
ast
ats
tas
tsa
sat
sta
ttt
예제 출력 2
3
예제 입력 3
5
aaaa
aaa
aa
aaaa
aaaaa
예제 출력 3
4
코드
아 XX 미래를 위해 문제 풀고 있었는데 백준 섭종해버려서 미치겠다
import sys
input = sys.stdin.readline
if __name__ == "__main__":
n = int(input())
char = [input().strip() for _ in range(n)]
words = []
for word in char:
stack = list(word)
is_same = False
for _ in range(len(word)):
rotated = ''.join(stack)
last = stack.pop()
stack.insert(0, last)
if rotated in words:
is_same = True
break
if not is_same:
words.append(word)
print(len(words))
해당 단어가 이미 등장한 단어가를 회전해서 만들 수 있는가?를 체크한다.
가능하다면 같은 단어이므로 버리고, 불가능하다면 새로운 단어이므로 저장한다.
words는 서로 다른 사이클 단어의 대표 집합이다.
이제 char에서 word를 하나씩 꺼내서 대표인지, 그리고 회전한 단어와 같은지 체크한다.
words = []
for word in char:
word의 단어를 하나씩 분리하여 stack에 저장한다.
stack = list(word)
그러면 다음과 같다.
"word" -> ['w', 'o', 'r', 'd']
이제 단어를 회전해야 하는데, len(word)만큼 돌아야 회전 경우 모두를 충족하게 된다.
회전은 stack의 마지막을 제거하여 맨 앞으로 삽입한다. (문제의 시계방향 충족)
last = stack.pop()
stack.insert(0, last)
예:
['w','o','r','d']
→ pop() → 'd'
→ insert(0,'d')
→ ['d','w','o','r']
그렇게 회전된 단어가 이미 저장된 단어와 같은지를 체크하고, 맞다면 종료한다.
if rotated in words:
is_same = True
break
word의 개수만큼 다 회전했는데도 못찾는 경우에는 새로운 단어이므로, 대표 단어 words 리스트에 추가한다.
if not is_same:
words.append(word)
이를 결과로 print하면 서로 다른 사이클 단어 개수를 알 수 있다.
print(len(words))
예시
입력:
picture
turepic
1. picture:
words = [] 이고 비교대상이 없으므로 picture가 words 안에 들어가 대표 단어가 된다.
2. turepic
회전하면 다음과 같다.
turepic
cturepi
icturep
picture ← 여기서 걸림
picture이라는 단어가 이미 있으므로 같은 단어임을 알 수 있으며, 따라서 추가하지 않는다.
정리
1. 단어 하나 선택
2. 가능한 모든 회전 생성
3. 기존 단어와 비교
4. 같으면 버림 / 다르면 추가
추가 코드
사실 '문자열 회전'이라고 하면 deque의 rotate 부터 생각이 난다.
따라서 deque로 풀어보았다.
from collections import deque
import sys
input = sys.stdin.readline
for __name__ == "__main__":
n = int(input())
words = []
for _ in range(n):
word = input().strip()
q = deque(word)
is_same = False
for _ in range(len(word)):
rotated = ''.join(q)
if rotated in words:
is_same = True
break
q.rotate(1) # 오른쪽으로 한 칸 회전
if not is_same:
words.append(word)
print(len(words))
그리고 사실 다른 분들 코드를 보고 배웠는데, 문자열 회전에서는 word + word 방식을 사용하는 방법도 있다.
어떤 단어를 두 번 붙이면 그 안에 모든 회전 형태가 들어있기 때문이다.
word + word = wordword
라는 형태에서는
word
ordw
rdwo
dwor
와 같은 형태가 전부 포함되어 있다.
따라서 아래와 같이 쉽고 빠르게 확인할 수 있다는 것이다. (황당~)
"turepic" in "picturepicture"
따라서 이렇게 쓸 수 있다.
import sys
input = sys.stdin.readline
if __name__ == "__main__":
n = int(input())
words = []
for _ in range(n):
word = input().strip()
is_same = False
for saved in words:
if len(word) == len(saved) and word in saved + saved:
is_same = True
break
if not is_same:
words.append(word)
print(len(words))
아래 코드로 길이가 같고, word가 saved를 두 번 붙인 문자열 안에 있으면 word는 saved의 회전이다를 확인할 수 있다.
if len(word) == len(saved) and word in saved+saved:
'CODE > Algorithm (Python)' 카테고리의 다른 글
| BOJ 10799 쇠막대기 (0) | 2026.04.28 |
|---|---|
| BOJ 3986 좋은 단어 (0) | 2026.04.28 |
| BOJ 4485 녹색 옷 입은 애가 젤다지? (0) | 2026.04.28 |
| BOJ 1504 특정한 최단 경로: 다익스트라 알고리즘 (0) | 2026.04.28 |
| 프로그래머스 level 1 명예의 전당(1) (0) | 2026.04.27 |