보이어 무어 알고리즘은 문자열 검색을 빠르게 처리하는 데에 사용되는 알고리즘 중 하나입니다. 이 알고리즘은 일치하지 않는 문자열을 다시 검색하지 않고, 패턴 내의 특정 문자들을 기준으로 문자열 검색을 처리하는 방식으로 작동합니다
텍스트 STRING STARTING CONSISTING에 대하여 패턴 STING을 탐색하는 수행과정을 본다면
먼저 STING이라는 패턴에 대한 skip 배열을 구하여야 합니다.
이제 보이어 무어 알고리즘을 파이썬으로 구현을 합니다
먼저 skip 배열을 만들어주는 initSkip() 함수를 구현합니다
def initSkip(p):
NUM = 27 # 알파벳 수
M = len(p) # 패턴의 길이
skip = [M for i in range(NUM)] #skip 함수를 모두 M값으로 초기화
for i in range(M):
skip[ord(p[i]) - ord('A')] = M - i - 1
return skip # skip 배열 반환
print(initSkip("ATION")) # 임시로 ATION 이란 패턴을 입력
저는 여기서 skip[ord(p[i]) - ord('A')] = M - i - 1을 잘 이해하지 못해서 천천히 살펴봤습니다.
먼저, ord 함수는 특정 문자를 아스키 값으로 변환하는 함수입니다.
p [] 배열에는 A T I O N (문자열)이 순서대로 들어오게 됩니다.
여기서 ord 함수를 이용하여 아스키 값으로 변환하지 않는다면 문자에 정수 값을 대입하는 결과가 발생합니다
또 ord('A') 를 빼주는 이유는 skip 배열의 번호가 0번부터 시작되기 때문에 맞춰주기 위함입니다.
실행 결과
def BM(p, t):
M = len(p)
N = len(t)
skip = initSkip(p)
i = M-1
j = M-1
while j >= 0:
while t[i] != p[j]:
k = skip[ord(t[i]) - ord('A')]
if M - j > k:
i = i + M - j
else:
i = i + k
if i >= N:
return N
j = M - 1
i = i-1
j = j-1
return i+1
print(BM("ATION","VISOINQUESTIONONIONCAPTIONGRADUATION"))
어제 공부했던 KMP처럼 보이어 무어도 이론만 공부를 하니 잘 이해가 안되는거같습니다
나중에 보이어 무어도 KMP와 함께 활용 문제를 풀어보며 더 공부를 해야겠다고 느꼈습니다
오늘 푼 알고리즘 문제도 그래프 탐색 문제입니다
바이러스
문제
신종 바이러스인 웜 바이러스는 네트워크를 통해 전파된다. 한 컴퓨터가 웜 바이러스에 걸리면 그 컴퓨터와 네트워크 상에서 연결되어 있는 모든 컴퓨터는 웜 바이러스에 걸리게 된다.
예를 들어 7대의 컴퓨터가 <그림 1>과 같이 네트워크 상에서 연결되어 있다고 하자. 1번 컴퓨터가 웜 바이러스에 걸리면 웜 바이러스는 2번과 5번 컴퓨터를 거쳐 3번과 6번 컴퓨터까지 전파되어 2, 3, 5, 6 네 대의 컴퓨터는 웜 바이러스에 걸리게 된다. 하지만 4번과 7번 컴퓨터는 1번 컴퓨터와 네트워크상에서 연결되어 있지 않기 때문에 영향을 받지 않는다.
어느 날 1번 컴퓨터가 웜 바이러스에 걸렸다. 컴퓨터의 수와 네트워크 상에서 서로 연결되어 있는 정보가 주어질 때, 1번 컴퓨터를 통해 웜 바이러스에 걸리게 되는 컴퓨터의 수를 출력하는 프로그램을 작성하시오.
입력
첫째 줄에는 컴퓨터의 수가 주어진다. 컴퓨터의 수는 100 이하이고 각 컴퓨터에는 1번 부터 차례대로 번호가 매겨진다. 둘째 줄에는 네트워크 상에서 직접 연결되어 있는 컴퓨터 쌍의 수가 주어진다. 이어서 그 수만큼 한 줄에 한 쌍씩 네트워크 상에서 직접 연결되어 있는 컴퓨터의 번호 쌍이 주어진다.
출력
1번 컴퓨터가 웜 바이러스에 걸렸을 때, 1번 컴퓨터를 통해 웜 바이러스에 걸리게 되는 컴퓨터의 수를 첫째 줄에 출력한다.
예제 입력 1
7
6
1 2
2 3
1 5
5 2
5 6
4 7
예제 출력 1
4
DFS는 재귀 호출을 통해 구현할 수 있습니다. DFS 함수의 매개변수로 바이러스가 있는 컴퓨터의 번호를 받습니다. 위에서 만든 그래프를 보고, 해당 컴퓨터와 연결되어 있는 컴퓨터에 방문하지 않았다면 컴퓨터의 번호를 매개변수로 전달하면서 재귀호출을 합니다. 함수가 호출되는 수가 감염된 컴퓨터의 수입니다.
import sys
input = sys.stdin.readline
# 깊이 우선 탐색 함수 dfs 정의
def dfs(graph, root):
# 현재 노드 방문 처리
visited[root] = True
# 현재 노드와 연결된 다른 노드들에 대해서 재귀적으로 DFS 호출
for i in graph[root]:
if visited[i] == False:
dfs(graph, i)
# 정점의 개수와 간선의 개수 입력 받기
n = int(input())
m = int(input())
# 각 노드에 대한 인접 리스트 만들기
graph = [[] for _ in range(n+1)]
for _ in range(m):
a, b = map(int, input().split())
# 양방향 그래프이므로 a와 b 사이에 간선 추가
graph[a].append(b)
graph[b].append(a)
# 방문 여부를 저장할 리스트 만들기
visited = [False] * (n + 1)
# 1번 정점을 시작으로 DFS 탐색 실행
dfs(graph, 1)
# 1번 정점을 제외한 방문한 정점의 개수 계산
ans = visited.count(True) - 1
# 결과 출력
print(ans)