이 튜토리얼에서는 리스트에 있는 모든 아나그램(Anagram)을 그룹으로 묶는 파이썬 프로그램을 작성해 보겠습니다. 본격적인 구현에 앞서, 먼저 아나그램이 무엇인지 살펴보겠습니다.
아나그램이란 두 문자열이 서로 다른 순서로 배열되어 있지만, 동일한 문자들로 구성되어 있는 경우를 말합니다.
문제 이해하기
해결 방법을 알아보기 전에 예시를 통해 문제를 이해해 보겠습니다.
입력
['cat', 'dog', 'fired', 'god', 'pat', 'tap', 'fried', 'tac']
출력
[['cat', 'tac'], ['dog', 'god'], ['fried', 'fired'], ['pat', 'tap']]
위 예시에서 'cat'과 'tac'은 같은 문자(c, a, t)로 이루어져 있으므로 아나그램 관계입니다. 마찬가지로 'dog'과 'god', 'fried'와 'fired', 'pat'과 'tap'도 서로 아나그램입니다.
1단계: 두 문자열이 아나그램인지 확인하는 함수 만들기
문제를 두 부분으로 나누어 해결하겠습니다. 먼저, 두 문자열이 아나그램인지 판별하는 함수를 작성합니다.
- 두 문자열을 초기화합니다.
- 두 문자열을 각각 정렬합니다.
- 정렬된 문자열이 서로 같다면 True를, 다르다면 False를 반환합니다.
예제 코드
# 두 문자열이 아나그램인지 확인하는 간단한 람다 함수
are_anagrams = lambda x, y: str(sorted(x.lower())) == str(sorted(y.lower()))
# 함수 호출
print(are_anagrams('cat', 'tac'))
print(are_anagrams('cat', 'Tac'))
print(are_anagrams('cat', 'dog'))실행 결과
위 코드를 실행하면 다음과 같은 결과가 출력됩니다.
True True False
'cat'과 'Tac'도 소문자로 변환 후 비교했기 때문에 True가 반환된 점에 주목하세요. 대소문자를 무시하고 비교하고 싶다면 .lower() 메서드를 활용하면 됩니다.
2단계: 딕셔너리를 활용해 아나그램 그룹화하기
아나그램 판별 방법을 알았지만, 이것만으로는 문제가 완전히 해결되지 않습니다. 리스트에서 모든 아나그램을 찾아 하위 리스트(그룹)로 묶어 저장해야 합니다.
그렇다면 어떻게 해결할 수 있을까요?
요소들을 그룹화할 때는 딕셔너리(Dictionary)를 사용하는 것이 가장 좋은 방법입니다. 서로 아나그램 관계인 문자열들은 하나의 키(key)로 묶어 관리할 수 있습니다. 파이썬 초보자에게는 다소 생소할 수 있으니, 단계별로 살펴보겠습니다.
- 문자열 리스트를 초기화합니다.
- 빈 딕셔너리를 초기화합니다.
- 리스트를 순회하며 다음 작업을 수행합니다.
- 현재 문자열을 정렬합니다.
- 정렬된 문자열이 딕셔너리의 키로 존재하는지 확인합니다.
- 키가 존재한다면, 해당 키의 리스트에 현재 문자열을 추가(append)합니다.
- 키가 존재하지 않는다면, 현재 문자열을 포함하는 새로운 리스트로 키를 초기화합니다.
- 딕셔너리의 모든 값(values)을 리스트로 출력합니다.
예제 코드
# 문자열 리스트 초기화
anagrams = ['cat', 'dog', 'fired', 'god', 'pat', 'tap', 'fried', 'tac']
# 빈 딕셔너리 초기화
grouped_anagrams = {}
# 리스트를 순회하며 아나그램 그룹화
for string in anagrams:
# 문자열 정렬
sorted_string = str(sorted(string))
# 딕셔너리에 키가 존재하는지 확인
if sorted_string in grouped_anagrams:
# 기존 그룹에 문자열 추가
grouped_anagrams[sorted_string].append(string)
else:
# 현재 문자열로 새로운 리스트 생성
grouped_anagrams[sorted_string] = [string]
# 딕셔너리의 값들(아나그램 그룹) 출력
print(list(grouped_anagrams.values()))실행 결과
위 코드를 실행하면 다음과 같은 결과가 출력됩니다.
[['dog', 'god'], ['pat', 'tap'], ['cat', 'tac'], ['fired', 'fried']]
핵심 원리: 정렬된 문자열을 키로 사용하는 이유
이 방법이 작동하는 핵심은 아나그램끼리는 정렬했을 때 반드시 동일한 결과가 나온다는 점입니다. 예를 들어 'fired'와 'fried'를 모두 정렬하면 'deifr'가 되므로, 같은 키 아래에 자연스럽게 그룹화됩니다. 이러한 기법은 시간 복잡도 측면에서도 효율적이며, 코딩 인터뷰에서 자주 등장하는 패턴이기도 합니다.
마무리 및 추가 학습 방향
물론 위 방법 외에도 다양한 접근 방식으로 이 문제를 해결할 수 있습니다. 특히 파이썬의 collections.defaultdict를 활용하면 키 존재 여부를 매번 확인하지 않아도 되어 코드를 더욱 간결하게 만들 수 있습니다. 직접 defaultdict를 학습하고 위 코드를 리팩토링해 보는 것도 좋은 연습이 될 것입니다.
튜토리얼에 대해 궁금한 점이 있다면 댓글로 남겨주세요!