0Pricing
DSA Interview Prep · Leçon

Étude de problèmes difficiles : Word Ladder II et Alien Dictionary

Abordez deux problèmes difficiles de bout en bout — word-ladder-II avec BFS et retour arrière, et alien-dictionary avec tri topologique — avec une explication complète.

Étude de problèmes difficiles : Word Ladder II et Alien Dictionary est une leçon DSA Interview Prep gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage DSA Interview Prep, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours DSA Interview Prep comprend 4 leçons au total.

Pourquoi les problèmes difficiles sont différents

Les problèmes difficiles de LeetCode se distinguent des problèmes de difficulté moyenne de deux façons essentielles : (1) ils exigent de combiner au moins deux techniques algorithmiques, et (2) la solution optimale n'est souvent pas évidente à partir du seul énoncé — vous devez dépasser la description superficielle pour percevoir la structure de graphe ou de DP sous-jacente. Échelle de mots II et Dictionnaire extraterrestre sont des problèmes difficiles emblématiques qui reviennent régulièrement dans les entretiens chez FAANG.

Pour aborder les problèmes difficiles, n'essayez pas de voir immédiatement la solution complète. Décomposez-les plutôt en sous-problèmes, identifiez la structure de chaque sous-problème, résolvez-les séparément, puis reliez-les. Cette réflexion modulaire est la clé pour résoudre des problèmes difficiles sous pression.

# 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}')

Échelle de mots II : énoncé du problème

Échelle de mots II (LeetCode 126) : étant donné un mot de départ, un mot de fin et une liste de mots, trouvez toutes les séquences de transformation les plus courtes du début à la fin. À chaque étape, exactement un caractère est transformé, et chaque mot intermédiaire doit figurer dans la liste de mots. Ce problème est nettement plus difficile qu'Échelle de mots I, qui ne trouve qu'un seul chemin le plus court, car vous devez énumérer tous les chemins optimaux.

Exemple : beginWord='hit', endWord='cog', wordList=['hot','dot','dog','lot','log','cog'] → [['hit','hot','dot','dog','cog'],['hit','hot','lot','log','cog']]. Les deux séquences ont une longueur de 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]]')

Échelle de mots II : phase BFS

À la phase 1, effectuez un parcours en largeur BFS niveau par niveau à partir du mot de départ. À chaque niveau, nous trouvons tous les voisins, c'est-à-dire les mots qui diffèrent d'un seul caractère. Nous enregistrons le niveau, c'est-à-dire la distance depuis le départ, auquel chaque mot est atteint pour la première fois. Nous ne nous arrêtons donc pas (NOT) lorsque nous atteignons le mot de fin : nous continuons jusqu'à la fin du niveau où le mot de fin a été trouvé, afin de nous assurer d'explorer tous les chemins les plus courts.

Il est essentiel de construire un dictionnaire parents associant chaque mot à l'ensemble des mots qui peuvent le précéder dans un chemin le plus court. C'est le graphe que nous utiliserons à la phase 2 pour le retour en arrière.

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}')

Échelle de mots II : phase de retour en arrière avec DFS

À la phase 2, effectuez un retour en arrière avec DFS à partir du mot de fin, en parcourant la carte parents dans le sens inverse. Nous construisons les chemins de la fin vers le début, puis nous les inversons. Lorsque nous atteignons le mot de départ, nous avons trouvé un chemin le plus court complet. La carte des parents garantit que tous les chemins trouvés ont une longueur minimale : il est impossible de bifurquer vers un chemin plus long.

Cette approche en deux phases (BFS pour les niveaux, DFS pour reconstruire les chemins) est la solution standard. Elle s'exécute en O(n × L × 26) pour BFS, où n = taille de la liste de mots et L = longueur d'un mot, puis en O(K × L) pour DFS, où K = nombre de chemins les plus courts.

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']))

Dictionnaire extraterrestre : énoncé du problème

Dictionnaire extraterrestre (LeetCode 269) : étant donné une liste de mots triés dans l'ordre lexicographique d'une langue extraterrestre, déterminez l'ordre des caractères de cette langue. Renvoyez l'ordre des caractères sous forme de chaîne. Si aucun ordre valide n'existe, parce que les contraintes sont contradictoires, renvoyez une chaîne vide.

Exemple : ['wrt','wrf','er','ett','rftt'] → 'wertf'. En comparant les mots adjacents : 't' < 'f' (d'après wrt et wrf), 'w' < 'e' (d'après wrt et er), 'r' < 't' (d'après er et ett), 'e' < 'r' (d'après ett et rftt). Il s'agit d'un tri topologique de ces contraintes d'ordre entre caractères.

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')

Dictionnaire extraterrestre : construction du graphe

La première étape consiste à extraire les contraintes : comparez chaque paire de mots adjacents, trouvez le premier caractère différent et ajoutez une arête orientée du caractère le plus petit vers le caractère le plus grand. Si un mot est un préfixe du mot suivant mais est plus long, par exemple « abc » avant « ab », l'entrée n'est pas valide : renvoyez immédiatement une chaîne vide.

Tous les caractères qui apparaissent dans la liste de mots sont des nœuds du graphe, même s'ils ne sont soumis à aucune contrainte d'ordre. Ces nœuds isolés peuvent apparaître n'importe où dans l'ordre final.

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)

Dictionnaire extraterrestre : tri topologique

Une fois le graphe construit, appliquez le tri topologique BFS de Kahn : initialisez une file avec tous les caractères dont le degré entrant est égal à 0, c'est-à-dire ceux qui n'ont aucun prérequis. Traitez chaque caractère et décrémentez le degré entrant de ses successeurs. Lorsque le degré entrant d'un successeur atteint 0, ajoutez-le à la file. Rassemblez les caractères dans l'ordre de traitement : vous obtenez ainsi l'ordre alphabétique extraterrestre.

Si le résultat contient tous les caractères, l'ordre est valide. S'il contient moins de caractères que prévu, le graphe comporte un cycle : les contraintes sont contradictoires et nous renvoyons une chaîne vide.

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)

Gestion des cas limites : les deux problèmes

Échelle de mots II et Dictionnaire extraterrestre comportent tous deux des cas limites subtils qui entraînent des réponses incorrectes s'ils ne sont pas traités :

  • Échelle de mots II : beginWord et endWord sont identiques (renvoyez [[beginWord]] ou une séquence de longueur 1). endWord ne figure pas dans wordList (renvoyez une chaîne vide). Aucun chemin n'existe (renvoyez une chaîne vide).
  • Dictionnaire extraterrestre : mots en double (duplicate) (n'extrayez aucune contrainte). Un seul mot (renvoyez tous les caractères uniques). Cycle dans les contraintes (renvoyez une chaîne vide). Un mot est un préfixe plus long que le mot suivant (entrée invalide, renvoyez une chaîne vide). Tous les caractères sont isolés (renvoyez n'importe quel ordre).
# 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()

Analyse de la complexité : les deux problèmes

Complexité d'Échelle de mots II : la phase BFS s'exécute en O(n × L × 26), où n = nombre de mots dans la liste et L = longueur d'un mot. Pour chaque mot à chaque niveau BFS, nous générons 26L mots candidats et vérifions leur présence dans l'ensemble de mots, avec un coût O(1) par vérification. La phase DFS s'exécute en O(K × L), où K = nombre de chemins les plus courts, qui peut être exponentiel en théorie.

Complexité du Dictionnaire extraterrestre : la construction du graphe s'exécute en O(C), où C = nombre total de caractères dans tous les mots. Le tri topologique s'exécute en O(V + E), où V = nombre de caractères uniques et E = nombre de contraintes d'ordre. La complexité globale est O(C), soit O(nombre total de caractères de l'entrée).

# 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()

Résumé des schémas : deux modèles réutilisables

Les deux problèmes enseignent des modèles réutilisables. Échelle de mots II = BFS pour les distances + DFS pour reconstruire les chemins : ce modèle apparaît chaque fois que vous devez trouver tous les chemins les plus courts dans un graphe non pondéré. Construisez la carte des parents pendant BFS, puis remontez du point d'arrivée au point de départ.

Dictionnaire extraterrestre = extraction d'arêtes + tri topologique : ce modèle apparaît chaque fois qu'on vous donne une séquence triée et que vous devez déduire les règles d'ordre sous-jacentes. Extrayez les contraintes orientées à partir des paires adjacentes, puis appliquez l'algorithme de Kahn. Renvoyez une chaîne vide lorsqu'un cycle est détecté, car l'ordre est impossible.

# 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)

Prendre confiance face aux problèmes difficiles

Les problèmes difficiles semblent impossibles au premier abord, mais deviennent abordables avec le bon modèle mental. Voici les idées clés :

  • Séparez les préoccupations : résolvez chaque sous-problème séparément avant de les relier
  • Maîtrisez vos briques de base : BFS/DFS, tri topologique, Dijkstra, tableaux de DP — les problèmes difficiles combinent ces éléments de façon peu évidente
  • Commencez par des exemples : suivez manuellement un petit exemple pour découvrir la structure sous-jacente
  • Vérifiez les sous-problèmes : après avoir implémenté la phase 1, qui consiste à construire le graphe, affichez le graphe et vérifiez-le manuellement avant de passer à la phase 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')

Vérification rapide

Vérifiez votre compréhension des notions de structures de données et d'algorithmes — préparation aux entretiens de programmation abordées dans cette leçon.

Récapitulatif de la leçon

Dans cette leçon, vous avez appris : Échelle de mots II utilise BFS pour construire une carte des prédécesseurs de tous les chemins les plus courts, puis un retour en arrière avec DFS pour énumérer tous les chemins les plus courts en parcourant les parents de la fin vers le début, le Dictionnaire extraterrestre extrait les contraintes orientées de paires de mots adjacentes et applique le tri topologique de Kahn pour ordonner les caractères, en renvoyant une chaîne vide lorsqu'un cycle est détecté, et les problèmes difficiles se décomposent en plusieurs sous-problèmes — construire le graphe, trouver les distances et reconstruire les chemins — que l'on résout séparément avec des algorithmes familiers. Vous avez maintenant terminé le cours complet de préparation aux entretiens DSA. Appliquez avec confiance à vos entretiens tous les modèles et toutes les techniques de ce parcours.

Questions Fréquemment Posées

La leçon « Étude de problèmes difficiles : Word Ladder II et Alien Dictionary » est-elle gratuite ?

Oui — le texte complet de « Étude de problèmes difficiles : Word Ladder II et Alien Dictionary » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours DSA Interview Prep, passe à CoddyKit PRO. Le cours DSA Interview Prep comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Étude de problèmes difficiles : Word Ladder II et Alien Dictionary » ?

Abordez deux problèmes difficiles de bout en bout — word-ladder-II avec BFS et retour arrière, et alien-dictionary avec tri topologique — avec une explication complète. Tu pratiques DSA Interview Prep avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer DSA Interview Prep ?

Aucune expérience préalable n'est requise. DSA Interview Prep sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.

Combien de temps prend la leçon « Étude de problèmes difficiles : Word Ladder II et Alien Dictionary » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon DSA Interview Prep ?

Oui. Chaque leçon DSA Interview Prep inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Aide-mémoire de reconnaissance des schémas
  2. Entretien blanc chronométré : problèmes faciles et intermédiaires
  3. Gestion des cas limites et communication avec la personne interrogée
  4. Étude de problèmes difficiles : Word Ladder II et Alien Dictionary
← Retour à DSA Interview Prep