문제 개요
소문자(ASCII 문자)로만 이루어진 문자열이 주어졌을 때, 해당 문자열 안에서 회문(palindrome)이 되는 연속된 부분 문자열이 모두 몇 개 있는지 찾는 문제입니다.
예를 들어 입력 문자열이 "level"이라면 출력은 7이 됩니다. ['level', 'eve', 'l', 'e', 'v', 'e', 'l']과 같이 일곱 개의 회문 부분 문자열이 존재하기 때문입니다.
해결 알고리즘
이 문제는 다음 단계를 따라 해결할 수 있습니다.
- N := 26 (알파벳 개수)
- n := 문자열의 길이
- sum := 0 (결과를 저장할 변수)
- my_map := 크기가 N인 리스트를 생성하고 0으로 초기화
- i를 0부터 n-1까지 반복:
- my_map[(str[i]의 아스키 코드) - ('a'의 아스키 코드)] 값을 1씩 증가시켜 각 문자의 등장 횟수를 계산
- i를 0부터 N-1까지 반복:
- my_map[i]가 0이 아니라면, sum에 (my_map[i] × (my_map[i] + 1)) / 2를 더함
- 최종적으로 sum을 반환
여기서 핵심은 각 문자별 등장 횟수를 센 뒤, k번 등장한 문자에 대해 k × (k + 1) / 2 공식을 적용해 가능한 조합의 수를 더하는 것입니다.
구현 예제
아래 코드를 통해 실제 동작을 확인해 보겠습니다.
N = 26
def all_palindrome_substr_count(str):
n = len(str)
sum = 0
my_map = [0] * N
for i in range(n):
my_map[ord(str[i]) - ord('a')] += 1
for i in range(N):
if my_map[i]:
sum += (my_map[i] * (my_map[i] + 1) // 2)
return sum
str = "level"
print(all_palindrome_substr_count(str))
입력
"level"
출력
7
마무리
이 방법은 문자열을 한 번만 순회하면서 각 문자의 빈도를 기록하므로 시간 복잡도는 O(n)입니다. 추가적인 자료구조 없이 크기 26의 배열만 사용하기 때문에 메모리 효율성도 우수하며, 소문자 알파벳으로 구성된 문자열에서 회문 부분 문자열의 개수를 빠르게 계산할 수 있습니다.