0Pricing
Coding Interview Prep · Leçon

Two-Sum et ses nombreuses variantes

Résolvez two-sum, three-sum, four-sum et two-sum with sorted array avec des tables de hachage et deux pointeurs, en comparant les coûts en temps et en espace.

Two-Sum et ses nombreuses variantes est une leçon Coding Interview Prep gratuite sur CoddyKit. Ceci est la leçon 2 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 Coding Interview Prep, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Coding Interview Prep comprend 4 leçons au total.

Somme de deux nombres : problème classique d’entretien

Le problème 1 de LeetCode, « Somme de deux nombres » : étant donné un tableau non trié et une cible, renvoyez les indices de deux éléments dont la somme est égale à la cible. L’approche par force brute en O(n²) examine toutes les paires. L’approche optimale en O(n) utilise une table de hachage : pour chaque élément x, vérifiez si target - x existe déjà dans la table. Si oui, renvoyez la paire d’indices. Sinon, stockez x et son indice dans la table.

La somme de deux nombres est souvent le tout premier problème posé lors d’un entretien — le maîtriser parfaitement montre que vous êtes prêt à passer à des problèmes plus difficiles.

def twoSum(nums, target):
    seen = {}   # val -> index
    for i, x in enumerate(nums):
        complement = target - x
        if complement in seen:
            return [seen[complement], i]
        seen[x] = i
    return []

print(twoSum([2, 7, 11, 15], 9))   # [0, 1]
print(twoSum([3, 2, 4], 6))        # [1, 2]
print(twoSum([3, 3], 6))           # [0, 1]

Pourquoi la table de hachage fonctionne pour la somme de deux nombres

La table de hachage stocke chaque élément rencontré jusqu’à présent. Lors du traitement de l’élément x, si target - x se trouve dans la table, ces deux éléments forment une paire valide. Point essentiel, le complément est toujours vérifié avant que x soit stocké, ce qui évite qu’un élément soit associé à lui-même (par exemple, si x == target/2, la vérification de la table a lieu avant le stockage de x ; il ne correspondra donc pas, sauf s’il existe deux copies).

# Trace two-sum on [2, 7, 11, 15], target=9
nums, target = [2, 7, 11, 15], 9
seen = {}
for i, x in enumerate(nums):
    complement = target - x
    print(f'i={i} x={x} complement={complement} seen={seen}')
    if complement in seen:
        print(f'  Found: indices [{seen[complement]}, {i}]')
        break
    seen[x] = i

Somme de deux nombres dans un tableau trié (deux pointeurs)

Si le tableau est déjà trié et que vous avez besoin des indices des valeurs (et non des indices d’origine), utilisez la technique des deux pointeurs : des pointeurs gauche et droit partant des extrémités opposées. Si la somme est égale à la cible, renvoyez le résultat. Si la somme est trop petite, déplacez le pointeur gauche vers la droite. Si elle est trop grande, déplacez le pointeur droit vers la gauche. Cette méthode s’exécute en O(n) et utilise un espace O(1) — elle est préférable à l’approche par table de hachage lorsque le tableau est trié et que la mémoire est limitée.

def twoSumSorted(numbers, target):
    lo, hi = 0, len(numbers) - 1
    while lo < hi:
        s = numbers[lo] + numbers[hi]
        if s == target:
            return [lo + 1, hi + 1]   # 1-indexed as per LeetCode 167
        elif s < target:
            lo += 1
        else:
            hi -= 1
    return []

print(twoSumSorted([2, 7, 11, 15], 9))   # [1, 2]
print(twoSumSorted([2, 3, 4], 6))         # [1, 3]
print(twoSumSorted([-1, 0], -1))          # [1, 2]

Somme de trois nombres (LeetCode 15)

Le problème 15 de LeetCode, « Somme de trois nombres » : trouvez tous les triplets distincts dont la somme est nulle. Triez le tableau, fixez un élément à la fois, puis appliquez la technique des deux pointeurs au sous-tableau trié restant. Ignorez les valeurs en double pour éviter les triplets dupliqués. Complexité temporelle : O(n²) — optimale pour ce problème, puisque la sortie elle-même peut contenir O(n²) triplets.

def threeSum(nums):
    nums.sort()
    result = []
    for i in range(len(nums) - 2):
        if i > 0 and nums[i] == nums[i-1]:  # skip duplicates
            continue
        lo, hi = i + 1, len(nums) - 1
        while lo < hi:
            s = nums[i] + nums[lo] + nums[hi]
            if s == 0:
                result.append([nums[i], nums[lo], nums[hi]])
                while lo < hi and nums[lo] == nums[lo+1]: lo += 1
                while lo < hi and nums[hi] == nums[hi-1]: hi -= 1
                lo += 1; hi -= 1
            elif s < 0:
                lo += 1
            else:
                hi -= 1
    return result

print(threeSum([-1, 0, 1, 2, -1, -4]))  # [[-1,-1,2],[-1,0,1]]
print(threeSum([0, 0, 0, 0]))            # [[0,0,0]]

Somme de quatre nombres (LeetCode 18)

Le problème 18 de LeetCode, « Somme de quatre nombres » : trouvez tous les quadruplets distincts dont la somme est égale à la cible. Étendez la somme de trois nombres : fixez deux éléments à l’aide de deux boucles imbriquées (en ignorant les doublons), puis appliquez la technique des deux pointeurs au sous-tableau intérieur. Complexité temporelle : O(n³). Pour une somme de k nombres en général, répétez la récursion k-2 fois, puis appliquez la technique des deux pointeurs, ce qui donne une complexité temporelle en O(n^(k-1)).

def fourSum(nums, target):
    nums.sort()
    n, result = len(nums), []
    for i in range(n - 3):
        if i > 0 and nums[i] == nums[i-1]:
            continue
        for j in range(i+1, n-2):
            if j > i+1 and nums[j] == nums[j-1]:
                continue
            lo, hi = j+1, n-1
            while lo < hi:
                s = nums[i]+nums[j]+nums[lo]+nums[hi]
                if s == target:
                    result.append([nums[i],nums[j],nums[lo],nums[hi]])
                    while lo < hi and nums[lo] == nums[lo+1]: lo += 1
                    while lo < hi and nums[hi] == nums[hi-1]: hi -= 1
                    lo += 1; hi -= 1
                elif s < target: lo += 1
                else: hi -= 1
    return result

print(fourSum([1,0,-1,0,-2,2], 0))
# [[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]

Somme de deux nombres la plus proche de la cible

Une variante courante consiste à trouver la paire dont la somme est la plus proche de la cible (sans nécessairement lui être exactement égale). Triez le tableau et utilisez deux pointeurs. Suivez la somme la plus proche rencontrée jusqu’à présent et mettez-la à jour chaque fois que vous trouvez une paire dont l’écart absolu avec la cible est plus petit. Cette approche en O(n log n) est simple à appliquer après le tri.

def twoSumClosest(nums, target):
    nums.sort()
    lo, hi  = 0, len(nums) - 1
    best    = float('inf')
    best_pair = None
    while lo < hi:
        s = nums[lo] + nums[hi]
        if abs(s - target) < abs(best - target):
            best = s
            best_pair = (nums[lo], nums[hi])
        if s < target:
            lo += 1
        elif s > target:
            hi -= 1
        else:
            return best_pair  # exact match
    return best_pair

print(twoSumClosest([1, 3, 4, 7, 10], 15))  # (7, 10) => 17, closest to 15
print(twoSumClosest([2, 5, 8, 11], 10))     # (2, 8) => 10, exact!

Somme de deux nombres avec plusieurs paires (toutes les paires)

Pour trouver toutes les paires dont la somme est égale à une cible, triez le tableau et utilisez deux pointeurs en recueillant toutes les paires. Après avoir trouvé une paire valide, ignorez les doublons des deux côtés avant de continuer. Cela donne O(n log n) pour le tri, plus O(n) pour le parcours — soit O(n log n) au total. Utiliser une table de hachage pour recueillir les paires est également valable, mais nécessite de gérer soigneusement les doublons.

def twoSumAllPairs(nums, target):
    nums.sort()
    lo, hi = 0, len(nums) - 1
    pairs  = []
    while lo < hi:
        s = nums[lo] + nums[hi]
        if s == target:
            pairs.append((nums[lo], nums[hi]))
            while lo < hi and nums[lo] == nums[lo+1]: lo += 1
            while lo < hi and nums[hi] == nums[hi-1]: hi -= 1
            lo += 1; hi -= 1
        elif s < target:
            lo += 1
        else:
            hi -= 1
    return pairs

print(twoSumAllPairs([1,1,2,3,4,4,5], 5))  # [(1,4),(1,4)-deduped,(2,3)]
# After duplicate-skipping: [(1,4),(2,3)]

Compter les paires dont la somme est inférieure à K

Une autre variante consiste à compter le nombre de paires dont la somme est inférieure à k. Triez le tableau et utilisez deux pointeurs. Lorsque nums[lo] + nums[hi] < k, toutes les paires (lo, lo+1), (lo, lo+2), ..., (lo, hi) sont valides — il s’agit de hi - lo paires. Avancez lo. Sinon, réduisez hi. Temps total : O(n log n) pour le tri, plus O(n) pour le comptage.

def countPairsLessThan(nums, k):
    nums.sort()
    lo, hi = 0, len(nums) - 1
    count  = 0
    while lo < hi:
        if nums[lo] + nums[hi] < k:
            count += hi - lo   # all (lo, lo+1)...(lo, hi) are valid
            lo += 1
        else:
            hi -= 1
    return count

print(countPairsLessThan([1, 3, 7, 11, 12], 10))  # (1,3),(1,7),(3,7) => 3
print(countPairsLessThan([3, 5, 2, 3], 7))         # (2,3),(2,3) => 2... verify

Somme de deux nombres avec une table de hachage : gestion des doublons

Lorsque la même valeur peut apparaître plusieurs fois et que vous devez compter les paires valides (et pas seulement vérifier leur existence), stockez les fréquences dans la table. Pour les paires dont les deux éléments sont égaux, le nombre de paires correspondant à une fréquence f est f*(f-1)//2. Pour les paires dont les deux éléments sont différents, multipliez leurs fréquences. Cela permet de compter toutes les paires valides en O(n).

from collections import Counter

def countTwoSumPairs(nums, target):
    freq  = Counter(nums)
    count = 0
    seen  = set()
    for x in freq:
        y = target - x
        if y in freq and (x, y) not in seen:
            if x == y:
                count += freq[x] * (freq[x] - 1) // 2
            else:
                count += freq[x] * freq[y]
            seen.add((x, y))
            seen.add((y, x))
    return count

print(countTwoSumPairs([1,1,2,3,4,4,3], 4))
# Pairs summing to 4: (1,3)x2x2=4, (0+more)...

Reconnaître les variantes du schéma de la somme de deux nombres

Le schéma de la somme de deux nombres apparaît sous de nombreuses formes. Reconnaissez-le lorsqu’un problème demande de trouver au moins deux éléments satisfaisant une relation numérique (somme, produit, différence). La stratégie fondamentale est toujours la même : fixer un élément, puis trouver son complément dans une structure précalculée (table de hachage ou tableau trié accompagné d’un pointeur). Étendez-la à la somme de k nombres en fixant k-2 éléments avec des boucles imbriquées, puis en appliquant le cas de base.

# Summary of approaches by scenario
scenarios = [
    ('Unsorted array, any indices, one pair',   'hash map O(n) time O(n) space'),
    ('Sorted array, any indices, one pair',      'two pointers O(n) time O(1) space'),
    ('All unique pairs summing to target',        'sort + two pointers O(n log n)'),
    ('Three numbers summing to zero (3-sum)',     'sort + fix + two pointers O(n^2)'),
    ('k numbers summing to target (k-sum)',       'sort + k-2 loops + two pointers O(n^(k-1))')
]
for scenario, approach in scenarios:
    print(f'{scenario}\n  => {approach}\n')

Communiquer sur la somme de deux nombres en entretien

Lorsque le problème de la somme de deux nombres se présente en entretien, expliquez votre raisonnement à voix haute : « Je dois trouver deux nombres dont la somme est égale à la cible. Pour chaque nombre x, je dois vérifier si cible-x existe. Je peux répondre à cette question en O(1) avec une table de hachage, pour un temps total de O(n) et un espace de O(n). Autrement, si le tableau était trié, je pourrais utiliser deux pointeurs avec un espace O(1). » Présentez les deux approches et demandez s’il existe des contraintes d’espace avant de faire votre choix.

Vérification rapide

Évaluez votre compréhension des concepts de Structures de données et algorithmes — préparation aux entretiens de programmation présentés dans cette leçon.

Récapitulatif de la leçon

Dans cette leçon, vous avez appris : le problème des deux sommes utilise une table de hachage pour vérifier l’existence du complément en O(1), ce qui donne une complexité globale de O(n), pour les tableaux triés, la méthode des deux pointeurs atteint une complexité spatiale de O(1), et les problèmes des trois sommes et des quatre sommes se ramènent au problème des deux sommes grâce au tri et à des boucles imbriquées, avec des complexités respectives de O(n²) et O(n³). Ensuite, nous étudierons les schémas de comptage des fréquences et le regroupement avec defaultdict et Counter.

Questions Fréquemment Posées

La leçon « Two-Sum et ses nombreuses variantes » est-elle gratuite ?

Oui — le texte complet de « Two-Sum et ses nombreuses variantes » 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 Coding Interview Prep, passe à CoddyKit PRO. Le cours Coding Interview Prep comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Two-Sum et ses nombreuses variantes » ?

Résolvez two-sum, three-sum, four-sum et two-sum with sorted array avec des tables de hachage et deux pointeurs, en comparant les coûts en temps et en espace. Tu pratiques Coding 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 Coding Interview Prep ?

Aucune expérience préalable n'est requise. Coding 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 2 sur 4.

Combien de temps prend la leçon « Two-Sum et ses nombreuses variantes » ?

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 Coding Interview Prep ?

Oui. Chaque leçon Coding 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. Fonction de hachage : fonctionnement interne et gestion des collisions
  2. Two-Sum et ses nombreuses variantes
  3. Comptage des fréquences et regroupement
  4. Plus longue séquence consécutive et cache LRU
← Retour à Coding Interview Prep