문제 링크 |
---|
import Foundation
func solution(_ begin: String, _ target: String, _ words: [String]) -> Int {
guard words.contains(target) else { return 0 } // 변환할 수 없는 경우 0을 return
// graph 만들기
var graph: [String:[String]] = [:]
let allWords = [begin] + words
func isDifferenceOneLetter(_ word1: String, _ word2: String) -> Bool {
let array1 = Array(word1)
let array2 = Array(word2)
var diffCount = 0
for i in 0..<array1.count {
if array1[i] != array2[i] {
diffCount += 1
}
if diffCount > 1 { return false }
}
return diffCount == 1
}
for i in 0..<allWords.count {
let word1 = allWords[i]
for j in 0..<allWords.count {
let word2 = allWords[j]
if isDifferenceOneLetter(word1, word2) {
graph[word1, default: []].append(word2)
}
}
}
// BFS
func bfs(_ begin: String, _ target: String, _ graph: [String:[String]]) -> Int {
var visited: Set<String> = []
var queue: [(word: String, depth: Int)] = []
queue.append((begin, 0))
visited.insert(begin)
while !queue.isEmpty {
let current = queue.removeFirst()
let word = current.word
let depth = current.depth
if word == target {
return depth
}
for nextWord in graph[word, default: []] {
guard !visited.contains(nextWord) else { continue }
visited.insert(nextWord)
queue.append((nextWord, depth + 1))
}
}
return 0
}
return bfs(begin, target, graph)
}
개선 가능한 점:
Queue를 일반 Array로 구현하면,.removeFirst()
를 수행할 때 O(N)의 시간복잡도를 가지게 된다.
Array는 앞의 요소가 사라진 만큼 뒤의 요소를 모두 한 칸씩 이동시키기 때문이다.
이를 Queue를 직접 구현함으로써 해결할 수 있다.
// deque
struct Deque<T> {
private var array: Array<T?> = []
private var head: Int = 0
var isEmpty: Bool {
return count == 0
}
var count: Int {
return array.count - head
}
// Deque 앞에 추가
mutating func appendLeft(_ element: T) {
if head > 0 {
head -= 1
array[head] = element
} else {
array.insert(element, at: 0)
}
}
// Deque 뒤에 추가
mutating func append(_ element: T) {
array.append(element)
}
// Deque 앞에서 출력
mutating func popLeft() -> T? {
guard head < array.count, let element = array[head] else { return nil }
array[head] = nil // Array에서 원소를 제거하는 것이 아니라, nil로 놓음 (Array 크기 변화 X)
head += 1
optimizer() // Array 크기 조정
return element
}
// Deque 뒤에서 출력
mutating func pop() -> T? {
return array.popLast() ?? nil
}
// 필요 시, Array가 일정 크기를 넘지 않도록 하는 Helper
mutating func optimizer() {
if head > 50 && head > (array.count / 2) {
array.removeFirst(head)
head = 0
}
}
}
BFS (Breadth-First Search)는 그래프 탐색 알고리즘으로, 너비 우선으로 탐색하는 방식이다. 시작점에서 가까운 노드부터 탐색하고, 점차 멀리 있는 노드로 나아간다.
초기화
반복 탐색
종료 조건
import Foundation
func bfs(graph: [[Int]], start: Int) {
var visited = [Bool](repeating: false, count: graph.count)
var queue = [Int]()
queue.append(start)
visited[start] = true
while !queue.isEmpty {
let node = queue.removeFirst()
print(node, terminator: " ")
for neighbor in graph[node] {
if !visited[neighbor] {
queue.append(neighbor)
visited[neighbor] = true
}
}
}
}
// 예제 그래프 (인접 리스트)
let graph = [
[1, 3], // 0번 노드와 연결된 노드
[0, 2, 4], // 1번 노드
[1], // 2번 노드
[0, 4], // 3번 노드
[1, 3] // 4번 노드
]
// BFS 실행
bfs(graph: graph, start: 0)
0 1 3 2 4
0 - 1 - 2
| |
3 - 4
graph = [
[1, 3], # 0번 노드와 연결된 노드
[0, 2, 4], # 1번 노드
[1], # 2번 노드
[0, 4], # 3번 노드
[1, 3] # 4번 노드
]
시작점 0에서 BFS 실행 결과: 0 -> 1 -> 3 -> 2 -> 4