문제 소개
그리드(격자) 또는 2차원 행렬 형태로 배치된 문자들이 주어졌을 때, 특정 단어가 이 그리드 안에 존재하는지 확인하는 문제를 생각해 보겠습니다. 단어는 네 가지 방향, 즉 좌우 수평 방향과 상하 수직 방향으로만 읽을 수 있으며 대각선 이동은 허용되지 않습니다. 단어를 찾으면 True, 찾지 못하면 False를 반환하면 됩니다.
예를 들어 입력이 다음과 같다고 가정해 봅시다.
| p | g | h | s | f |
| y | k | d | g | h |
| t | k | g | h | i |
| h | n | s | j | s |
| o | j | f | g | h |
| n | r | t | y | u |
이때 찾을 단어가 'python'이라면 결과는 True입니다. 왼쪽 위 칸의 'p'에서 시작해 한 칸씩 아래로 내려가면 첫 번째 열을 따라 p → y → t → h → o → n 순서로 단어가 완성되기 때문입니다.
접근 방법: 깊이 우선 탐색(DFS)과 백트래킹
이 문제는 DFS(깊이 우선 탐색)와 백트래킹을 조합하면 자연스럽게 해결할 수 있습니다. 핵심 아이디어는 다음과 같습니다.
- 그리드의 모든 칸을 잠재적인 시작점으로 삼습니다.
- 현재 칸의 문자가 찾고자 하는 단어의 해당 위치 문자와 일치하면, 상하좌우 네 방향으로 재귀적으로 탐색을 이어갑니다.
- 이미 방문한 칸을 '#' 같은 임시 문자로 덮어 써 같은 칸을 두 번 사용하지 않도록 하고, 탐색이 끝나면 원래 문자로 되돌립니다(백트래킹).
- 단어의 모든 문자를 매칭하면 True를 반환하고, 어떤 경로로도 완성하지 못하면 False를 반환합니다.
find_grid() 함수의 동작 단계
- 종료 조건: degree(현재까지 매칭한 문자 수)가 단어 길이와 같으면 True를 반환합니다.
- 범위 검사: 현재 위치가 그리드를 벗어나면(음수 좌표 또는 행·열 개수 초과) False를 반환합니다.
- 문자 일치 검사: matrix[row_pos][col_pos]가 input_str[degree]와 같다면,
- 현재 값을 temp에 저장하고 해당 칸을 '#'로 바꿔 방문 표시를 합니다.
- 상·하·좌·우 네 방향으로 degree + 1을 넘겨 재귀 호출한 결과를 OR로 결합합니다.
- 탐색이 끝나면 칸을 temp로 복원하고 result를 반환합니다.
- 일치하지 않으면 False를 반환합니다.
메인 함수(solve)의 동작 단계
- 단어 길이가 행 개수 × 열 개수보다 크면 그리드에 존재할 수 없으므로 False를 반환합니다.
- 모든 행과 열을 순회하면서 matrix[row][col]이 단어의 첫 글자와 일치하는 칸을 찾습니다.
- 일치하는 칸마다 find_grid()를 호출해 True가 나오면 즉시 True를 반환합니다.
- 모든 시작점을 시도해도 실패하면 False를 반환합니다.
구현 예제
다음은 위 알고리즘을 파이썬으로 구현한 코드입니다.
def find_grid(matrix, input_str, row_pos, col_pos, row_count, col_count, degree):
if degree == len(input_str):
return True
if row_pos < 0 or col_pos < 0 or row_pos >= row_count or col_pos >= col_count:
return False
if matrix[row_pos][col_pos] == input_str[degree]:
temp = matrix[row_pos][col_pos]
matrix[row_pos][col_pos] = '#'
result = (find_grid(matrix, input_str, row_pos - 1, col_pos, row_count, col_count, degree + 1)
or find_grid(matrix, input_str, row_pos + 1, col_pos, row_count, col_count, degree + 1)
or find_grid(matrix, input_str, row_pos, col_pos - 1, row_count, col_count, degree + 1)
or find_grid(matrix, input_str, row_pos, col_pos + 1, row_count, col_count, degree + 1))
matrix[row_pos][col_pos] = temp
return result
else:
return False
def solve(matrix, input_str, row_count, col_count):
if len(input_str) > row_count * col_count:
return False
for row in range(row_count):
for col in range(col_count):
if matrix[row][col] == input_str[0]:
if find_grid(matrix, input_str, row, col, row_count, col_count, 0):
return True
return False
word_grid = ['pghsf', 'ykdgh', 'tkghi', 'hnsjs', 'ojfgh', 'nrtyu']
grid = [list(row) for row in word_grid]
print(solve(grid, 'python', 6, 5))
참고: 파이썬에서 문자열은 불변(immutable)이므로 문자열 행에 replace()를 호출해도 원본이 변경되지 않습니다. 따라서 위 코드처럼 각 행을 리스트(list)로 변환한 뒤 인덱스로 직접 값을 교체해야 방문 표시('#')와 복원이 실제로 동작합니다.
입력
['pghsf', 'ykdgh', 'tkghi', 'hnsjs', 'ojfgh', 'nrtyu'], 'python'
출력
True
시간 복잡도
각 시작점에서 최대 4방향으로 분기되며 단어 길이 L만큼 깊이 탐색하므로, 시간 복잡도는 O(R × C × 4^L)입니다. 여기서 R과 C는 각각 행과 열의 개수입니다. 공간 복잡도는 재귀 호출 스택을 포함해 O(L)입니다.