0Pricing
Coding Interview Prep · 강의

어려운 문제 풀이: 단어 사다리 II와 외계인 사전

BFS와 백트래킹을 사용하는 단어 사다리 II, 위상 정렬을 사용하는 외계인 사전, 두 가지 어려운 문제를 처음부터 끝까지 자세히 설명하며 해결합니다.

어려운 문제 풀이: 단어 사다리 II와 외계인 사전은(는) CoddyKit의 무료 Coding Interview Prep 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Coding Interview Prep 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Coding Interview Prep 강의에는 총 4개의 강의가 포함되어 있습니다.

어려운 문제가 다른 이유

어려운 LeetCode 문제는 중간 난이도 문제와 두 가지 핵심적인 차이가 있습니다. (1) 두 가지 이상의 알고리즘 기법을 결합해야 하고, (2) 문제 설명만으로는 최적의 풀이가 분명하지 않은 경우가 많습니다. 표면적인 설명을 넘어 그 아래에 있는 그래프 또는 DP 구조를 파악해야 합니다. 단어 사다리 II와 외계인 사전은 FAANG 면접에 반복해서 등장하는 대표적인 어려운 문제입니다.

어려운 문제에 접근할 때는 처음부터 완성된 풀이를 보려고 하지 마십시오. 대신 문제를 하위 문제로 나누고, 각 하위 문제의 구조를 파악한 다음, 각각을 독립적으로 해결하고 서로 연결하십시오. 이러한 모듈식 사고가 압박 속에서 어려운 문제를 해결하는 핵심입니다.

# Hard problem meta-strategy
strategy = [
    '1. Read the problem 2x — hard problems often have subtle constraints',
    '2. Model it as a known structure: graph? DP table? sorted order?',
    '3. Break into sub-problems: separate the graph-building from the traversal',
    '4. Solve sub-problems in order, verifying each before connecting',
    '5. Handle the edge case where no solution exists (empty result, -1, [])',
    '6. Optimise only after the correct but slow solution works',
]
print('Hard problem meta-strategy:')
for step in strategy:
    print(f'  {step}')

단어 사다리 II: 문제 설명

단어 사다리 II (LeetCode 126)는 시작 단어, 종료 단어, 단어 목록이 주어졌을 때 시작 단어에서 종료 단어까지의 모든 최단 변환 순서를 찾는 문제입니다. 각 단계에서는 정확히 한 문자를 바꾸며, 중간 단어는 모두 단어 목록에 포함되어 있어야 합니다. 모든 최적 경로를 열거해야 하므로, 최단 경로 하나만 찾는 단어 사다리 I보다 훨씬 어렵습니다.

예시: beginWord='hit', endWord='cog', wordList=['hot','dot','dog','lot','log','cog'] → [['hit','hot','dot','dog','cog'],['hit','hot','lot','log','cog']]. 두 경로 모두 길이는 5입니다.

# Word Ladder II problem breakdown
begin_word = 'hit'
end_word = 'cog'
word_list = ['hot','dot','dog','lot','log','cog']

# What we need:
# 1. Build a graph: word -> set of words that differ by one character
# 2. BFS to find the MINIMUM number of steps (shortest path distance)
# 3. DFS/backtracking to enumerate ALL paths of that minimum length

# Key insight: BFS finds shortest distance; DFS reconstructs all shortest paths
# Two-phase approach:
print('Phase 1: BFS from begin_word to find min distance to each word')
print('Phase 2: DFS/backtrack from end_word using only edges that decrease distance')
print()
print(f'Input: {begin_word} -> {end_word}')
print(f'Word list: {word_list}')
print('Expected: [[hit,hot,dot,dog,cog],[hit,hot,lot,log,cog]]')

단어 사다리 II: BFS 단계

1단계에서는 시작 단어에서 출발해 BFS로 단계별 탐색을 수행합니다. 각 단계에서 문자 하나가 다른 모든 이웃 단어를 찾습니다. 각 단어에 처음 도달한 단계, 즉 시작 단어로부터의 거리를 기록합니다. 종료 단어에 도달했다고 해서 NOT 중단합니다. 최단 경로를 모두 탐색할 수 있도록 종료 단어를 찾은 단계가 끝날 때까지 계속합니다.

핵심은 각 단어를 어떤 최단 경로에서든 바로 앞에 올 수 있는 단어들의 집합과 연결하는 parents 사전을 만든다는 점입니다. 이 그래프를 2단계에서 백트래킹에 사용합니다.

from collections import defaultdict, deque

def find_parents(begin, end, word_set):
    parents = defaultdict(set)
    layer = {begin}
    found = False

    while layer and not found:
        next_layer = set()
        for word in layer:
            for i in range(len(word)):
                for c in 'abcdefghijklmnopqrstuvwxyz':
                    new_word = word[:i] + c + word[i+1:]
                    if new_word in word_set and new_word not in parents:
                        next_layer.add(new_word)
                        parents[new_word].add(word)
                        if new_word == end:
                            found = True
        layer = next_layer
    return parents if found else {}

words = {'hot','dot','dog','lot','log','cog'}
parents = find_parents('hit', 'cog', words)
print('Parents map (which words can precede each word):')
for word, preds in sorted(parents.items()):
    print(f'  {word}: {preds}')

단어 사다리 II: DFS 백트래킹 단계

2단계에서는 종료 단어에서 시작해 DFS 백트래킹을 수행하고, parents 맵을 역방향으로 따라갑니다. 종료 단어에서 시작 단어를 향해 경로를 만든 다음 경로를 뒤집습니다. 시작 단어에 도달하면 완전한 최단 경로를 찾은 것입니다. parents 맵은 발견되는 모든 경로가 최소 길이임을 보장하므로, 더 긴 경로로 ‘벗어날’ 수 없습니다.

이 2단계 접근 방식(BFS로 단계 계산, DFS로 경로 복원)은 표준적인 풀이이며, BFS는 n = 단어 목록의 크기, L = 단어 길이일 때 O(n × L × 26)에 실행됩니다. 여기에 K = 최단 경로의 개수일 때 DFS의 O(K × L)이 더해집니다.

def find_ladders(beginWord, endWord, wordList):
    word_set = set(wordList)
    if endWord not in word_set:
        return []

    # Phase 1: BFS to build parents map
    parents = defaultdict(set)
    layer = {beginWord}
    found = False
    visited = {beginWord}

    while layer and not found:
        next_layer = set()
        for word in layer:
            for i in range(len(word)):
                for c in 'abcdefghijklmnopqrstuvwxyz':
                    nw = word[:i] + c + word[i+1:]
                    if nw in word_set and nw not in visited:
                        next_layer.add(nw)
                        parents[nw].add(word)
                        if nw == endWord: found = True
        visited |= next_layer
        layer = next_layer

    # Phase 2: DFS backtrack from endWord to beginWord
    result = []
    def dfs(word, path):
        if word == beginWord:
            result.append(path[::-1])
            return
        for parent in parents[word]:
            dfs(parent, path + [parent])
    dfs(endWord, [endWord])
    return result

print(find_ladders('hit','cog',['hot','dot','dog','lot','log','cog']))

외계인 사전: 문제 설명

외계인 사전 (LeetCode 269)은 외계 언어에서 사전순으로 정렬된 단어 목록이 주어졌을 때 해당 언어의 문자 순서를 알아내는 문제입니다. 문자 순서를 문자열로 반환하십시오. 유효한 순서가 존재하지 않으면(모순되는 경우) 빈 문자열을 반환합니다.

예시: ['wrt','wrf','er','ett','rftt'] → 'wertf'. 인접한 단어를 비교하면 다음과 같습니다. wrt와 wrf에서 ‘t’ < ‘f’, wrt와 er에서 ‘w’ < ‘e’, er와 ett에서 ‘r’ < ‘t’, ett와 rftt에서 ‘e’ < ‘r’입니다. 이는 이러한 문자 순서 제약 조건에 대한 위상 정렬입니다.

words = ['wrt', 'wrf', 'er', 'ett', 'rftt']
# Compare adjacent pairs to extract ordering:
# wrt vs wrf: first diff at index 2: t < f  (t comes before f)
# wrf vs er:  first diff at index 0: w < e  (w comes before e)
# er  vs ett: first diff at index 1: r < t  (r comes before t)
# ett vs rftt:first diff at index 0: e < r  (e comes before r)

ordering_constraints = [
    ('t', 'f', 'from wrt vs wrf'),
    ('w', 'e', 'from wrf vs er'),
    ('r', 't', 'from er vs ett'),
    ('e', 'r', 'from ett vs rftt'),
]
print('Ordering constraints extracted from adjacent word pairs:')
for a, b, source in ordering_constraints:
    print(f'  {a} -> {b}  ({source})')
print('\nThis is a directed graph: find topological order = alien alphabet order')

외계인 사전: 그래프 구축

첫 단계는 제약 조건 추출입니다. 인접한 각 단어 쌍을 비교하고, 처음으로 다른 문자를 찾은 다음, 더 작은 문자에서 더 큰 문자로 향하는 방향성 간선을 add합니다. 한 단어가 다음 단어의 접두사인데 더 긴 경우(예: ‘abc’가 ‘ab’보다 앞에 있는 경우) 입력은 유효하지 않으므로 즉시 빈 문자열을 반환합니다.

단어 목록에 나타나는 모든 문자는 순서 제약 조건이 없더라도 그래프의 노드입니다. 이러한 고립된 노드는 최종 순서의 어느 위치에나 나타날 수 있습니다.

from collections import defaultdict

def build_alien_graph(words):
    adj = defaultdict(set)    # char -> set of chars that come after it
    in_degree = {c: 0 for word in words for c in word}

    for i in range(len(words) - 1):
        w1, w2 = words[i], words[i+1]
        min_len = min(len(w1), len(w2))
        found_diff = False
        for j in range(min_len):
            if w1[j] != w2[j]:
                if w2[j] not in adj[w1[j]]:   # avoid duplicate edges
                    adj[w1[j]].add(w2[j])
                    in_degree[w2[j]] += 1
                found_diff = True
                break
        if not found_diff and len(w1) > len(w2):
            return {}, {}   # invalid: 'abc' before 'ab'
    return adj, in_degree

words = ['wrt', 'wrf', 'er', 'ett', 'rftt']
adj, in_degree = build_alien_graph(words)
print('Adjacency list (directed):', {k: list(v) for k, v in adj.items()})
print('In-degrees:', in_degree)

외계인 사전: 위상 정렬

그래프를 만든 후에는 칸의 BFS 위상 정렬을 적용합니다. 진입 차수가 0인 모든 문자(선행 조건이 없는 문자)로 큐를 초기화합니다. 각 문자를 처리하면서 그 후속 문자의 진입 차수를 줄입니다. 후속 문자의 진입 차수가 0이 되면 큐에 넣습니다. 처리 순서대로 문자를 모으면 이것이 외계 언어의 알파벳 순서가 됩니다.

결과에 모든 문자가 포함되어 있으면 유효한 순서입니다. 예상한 수보다 문자가 적으면 순환이 존재하는 것입니다. 즉, 제약 조건이 서로 모순되므로 빈 문자열을 반환합니다.

from collections import deque, defaultdict

def alien_order(words):
    adj = defaultdict(set)
    in_degree = {c: 0 for word in words for c in word}

    for i in range(len(words) - 1):
        w1, w2 = words[i], words[i + 1]
        min_len = min(len(w1), len(w2))
        found = False
        for j in range(min_len):
            if w1[j] != w2[j]:
                if w2[j] not in adj[w1[j]]:
                    adj[w1[j]].add(w2[j])
                    in_degree[w2[j]] += 1
                found = True; break
        if not found and len(w1) > len(w2):
            return ''    # invalid: 'abc' before 'ab'

    # Kahn's BFS topological sort
    queue = deque([c for c in in_degree if in_degree[c] == 0])
    result = []
    while queue:
        c = queue.popleft()
        result.append(c)
        for neighbor in sorted(adj[c]):   # sort for determinism
            in_degree[neighbor] -= 1
            if in_degree[neighbor] == 0:
                queue.append(neighbor)

    return ''.join(result) if len(result) == len(in_degree) else ''

print(alien_order(['wrt','wrf','er','ett','rftt']))  # e.g., 'wertf'
print(alien_order(['z','x']))                         # 'zx'
print(alien_order(['z','x','z']))                     # '' (cycle z->x->z)

경계 사례 처리: 두 문제

단어 사다리 II와 외계인 사전에는 제대로 처리하지 않으면 오답을 일으키는 미묘한 경계 사례가 있습니다.

  • 단어 사다리 II: beginWord와 endWord가 같으면 [[beginWord]] 또는 길이 1을 반환합니다. endWord가 wordList에 없으면 빈 결과를 반환합니다. 경로가 존재하지 않아도 빈 결과를 반환합니다.
  • 외계인 사전: duplicate 단어에서는 제약 조건을 추출하지 않습니다. 단어가 하나뿐이면 모든 고유 문자를 반환합니다. 제약 조건에 순환이 있으면 빈 문자열을 반환합니다. 한 단어가 다음 단어의 더 긴 접두사이면 입력이 유효하지 않으므로 빈 문자열을 반환합니다. 모든 문자가 고립되어 있으면 어떤 순서든 반환할 수 있습니다.
# Edge case tests for Word Ladder II
def test_word_ladder_edge_cases():
    from collections import defaultdict
    def find_ladders(begin, end, word_list):
        # [abbreviated implementation for testing]
        if end not in word_list: return []
        if begin == end: return [[begin]]
        return []  # placeholder

    tests = [
        ('hit', 'cog', ['hot','dot','dog','lot','log'], []),  # no path (cog missing)
        ('hit', 'hit', ['hit'], [['hit']]),                   # begin==end
        ('a',   'c',  ['a','b','c'], [['a','c']]),            # short words
    ]
    for begin, end, wl, expected in tests:
        result = find_ladders(begin, end, wl)
        print(f'{begin}->{end}: result={result}')

# Edge case tests for Alien Dictionary
def test_alien_edge_cases():
    from collections import defaultdict, deque
    # (using alien_order from previous scene)
    tests = [
        (['abc', 'ab'], ''),          # 'abc' before 'ab' = invalid
        (['a'],         'a'),          # single word
        (['z','z'],     'z'),          # duplicate: no constraint
    ]
    print('Alien dictionary edge cases:')
    for words, expected in tests:
        print(f'  {words} -> expected: "{expected}"')

test_word_ladder_edge_cases()
test_alien_edge_cases()

복잡도 분석: 두 문제

단어 사다리 II의 복잡도: BFS 단계는 n = 목록의 단어 수, L = 단어 길이일 때 O(n × L × 26)에 실행됩니다. 각 BFS 단계에서 각 단어에 대해 26L개의 후보 단어를 만들고, 단어 집합에 포함되는지 확인합니다. 각 확인은 O(1)입니다. DFS 단계는 K = 최단 경로의 개수일 때 O(K × L)이며, 이론적으로 K는 지수적으로 증가할 수 있습니다.

외계인 사전의 복잡도: 그래프 구축은 C = 모든 단어에 포함된 전체 문자 수일 때 O(C)입니다. 위상 정렬은 V = 고유 문자의 수, E = 순서 제약 조건의 수일 때 O(V + E)입니다. 전체 복잡도는 O(C), 즉 입력에 포함된 전체 문자 수에 대한 O(C)입니다.

# Complexity analysis for both problems
complexities = [
    {
        'problem': 'Word Ladder II',
        'time': 'O(n * L * 26) BFS + O(K * L) DFS backtracking',
        'space': 'O(n * L) for word set + parents map',
        'notes': 'K (number of shortest paths) can be exponential in pathological cases',
    },
    {
        'problem': 'Alien Dictionary',
        'time': 'O(C) where C = total characters in all words',
        'space': 'O(V + E) for adjacency list',
        'notes': 'V <= 26 (alphabet), E <= V^2 = 676; often treated as O(C) total',
    },
]
for c in complexities:
    print(f'{c["problem"]}:')
    print(f'  Time:  {c["time"]}')
    print(f'  Space: {c["space"]}')
    print(f'  Notes: {c["notes"]}')
    print()

패턴 요약: 재사용 가능한 두 가지 템플릿

두 문제는 재사용 가능한 패턴을 가르쳐 줍니다. 단어 사다리 II = 거리 계산을 위한 BFS + 경로 복원을 위한 DFS: 이 패턴은 가중치가 없는 그래프에서 모든 최단 경로가 필요할 때 나타납니다. BFS 중에 부모 맵을 만들고, 도착점에서 출발점까지 백트래킹하십시오.

외계인 사전 = 간선 추출 + 위상 정렬: 이 패턴은 정렬된 순서가 주어지고 그 아래에 있는 순서 규칙을 추론해야 할 때 나타납니다. 인접한 쌍에서 방향성 제약 조건을 추출한 다음 칸 알고리즘을 적용하십시오. 순환이 감지되면(순서를 만들 수 없으므로) ''을 반환합니다.

# Pattern templates
print('Template 1: All Shortest Paths in Unweighted Graph')
template_1 = '''
1. BFS from source, recording parents[node] = set of nodes that lead to node
2. Continue each BFS level fully (do not stop at first endNode reach)
3. DFS backtrack from endNode, following parents map
4. Reverse each path found (built end->start, need start->end)
'''
print(template_1)

print('Template 2: Infer Ordering from Sorted Sequence')
template_2 = '''
1. Compare adjacent pairs, extract first differing element as directed constraint
2. Build adjacency list + in-degree map
3. Check for invalid input (prefix longer than successor)
4. Kahn's BFS topological sort
5. If result length < number of nodes => cycle => return invalid
'''
print(template_2)

어려운 문제에 대한 자신감 키우기

어려운 문제는 처음에는 불가능해 보이지만, 올바른 사고 모델을 사용하면 접근할 수 있게 됩니다. 핵심 통찰은 다음과 같습니다.

  • 관심사를 분리하십시오: 서로 연결하기 전에 각 하위 문제를 독립적으로 해결하십시오
  • 기본 구성 요소를 파악하십시오: BFS/DFS, 위상 정렬, 다익스트라, DP 표 등 어려운 문제는 이러한 요소를 예상하기 어려운 방식으로 결합합니다
  • 예시에서 시작하십시오: 작은 예시로 문제를 직접 따라가며 그 아래에 있는 구조를 발견하십시오
  • 하위 문제를 검증하십시오: 1단계(그래프 구축)를 구현한 후 그래프를 출력하고 직접 확인한 다음 2단계로 진행하십시오
# Hard problem confidence-building practice plan
practice_plan = [
    ('Week 1', 'BFS/DFS fundamentals', ['Number of Islands', 'Clone Graph', 'Word Ladder I']),
    ('Week 2', 'Topological sort', ['Course Schedule I & II', 'Alien Dictionary (easy)']),
    ('Week 3', 'All-paths problems', ['All Paths to Target', 'Word Ladder II (hard)']),
    ('Week 4', 'Hard combos', ['Minimum Window Substring', 'Serialize/Deserialize Tree']),
]
print('4-week hard problem practice plan:')
for week, theme, problems in practice_plan:
    print(f'\n{week} — {theme}:')
    for p in problems:
        print(f'  - {p}')

print('\nAfter each problem, write:')
print('  1. The pattern it belongs to')
print('  2. The 2-3 key sub-problems')
print('  3. One insight you would not have had before solving it')

빠른 확인

이번 수업에서 배운 자료 구조 & 알고리즘 — 코딩 면접 준비 개념에 대한 이해도를 확인해 보십시오.

수업 요약

이번 수업에서는 단어 사다리 II가 BFS로 모든 최단 경로의 선행 단어를 담은 parents 맵을 만든 다음, 종료 단어에서 시작 단어까지 parents를 따라가며 DFS 백트래킹으로 모든 최단 경로를 열거한다는 점, 외계인 사전이 인접한 단어 쌍에서 방향성 제약 조건을 추출하고 칸의 위상 정렬을 적용해 문자의 순서를 정하며, 순환이 감지되면 빈 문자열을 반환한다는 점, 그리고 어려운 문제는 그래프 구축, 거리 계산, 경로 복원과 같은 여러 하위 문제로 나뉘며, 각각을 익숙한 알고리즘으로 독립적으로 해결한다는 점을 배웠습니다. 이제 DSA 면접 준비 과정을 모두 마쳤습니다. 이 과정에서 배운 모든 패턴과 기법을 면접에 자신 있게 적용해 보십시오.

자주 묻는 질문

“어려운 문제 풀이: 단어 사다리 II와 외계인 사전” 강의는 무료인가요?

네 — “어려운 문제 풀이: 단어 사다리 II와 외계인 사전” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Coding Interview Prep 강의 전체를 잠금 해제할 수 있습니다. Coding Interview Prep 강의에는 총 4개의 강의가 포함되어 있습니다.

“어려운 문제 풀이: 단어 사다리 II와 외계인 사전”에서 뭘 배우나요?

BFS와 백트래킹을 사용하는 단어 사다리 II, 위상 정렬을 사용하는 외계인 사전, 두 가지 어려운 문제를 처음부터 끝까지 자세히 설명하며 해결합니다. 브라우저에서 직접 실행하는 실습 코드로 Coding Interview Prep을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Coding Interview Prep을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Coding Interview Prep은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“어려운 문제 풀이: 단어 사다리 II와 외계인 사전” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Coding Interview Prep 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Coding Interview Prep 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 패턴 인식 요약표
  2. 시간 제한 모의 면접: 쉬운 문제와 중간 난이도 문제
  3. 예외 상황 처리와 면접 대상자의 의사소통
  4. 어려운 문제 풀이: 단어 사다리 II와 외계인 사전
← Coding Interview Prep(으)로 돌아가기