Algorithms · lab d'ingénierie

Résoudre Two Sum en C# : de la force brute aux tables de hachage

Un problème, deux approches. Échangez de la mémoire contre une recherche plus rapide et expliquez pourquoi la solution fonctionne.

2 min de lecture Beginner 30 min
C#AlgorithmsHash Maps

// avant de commencer

  • Tableaux, boucles, dictionnaires
  1. 1Comprendre
  2. 2Réfléchir
  3. 3Concevoir
  4. 4Implémenter
  5. 5Tester
  6. 6Améliorer
  7. 7Comparer à l'IA

01 / Comprendre le problème

Étant donné un tableau d'entiers et une cible, renvoyez deux indices distincts dont la somme des valeurs atteint la cible. Sans paire, renvoyez un tableau vide. On suppose ici que les valeurs et opérations tiennent dans un entier signé sur 32 bits.

nums = [2, 7, 11, 15], cible = 9 donne [0, 1]. Un même indice ne peut pas être réutilisé.

02 / Réfléchir avant de coder

Énumérez les paires possibles. Quelle information permettrait d'éviter une nouvelle recherche complète pour chaque valeur ?

Indice 1 : transformer la somme en recherche

Pour une valeur x, la valeur manquante vaut cible − x.

Indice 2 : mémoriser le passé

Conservez chaque valeur déjà rencontrée avec son indice. Cherchez le complément avant d'ajouter la valeur actuelle.

03 / Concevoir la solution

Parcourez le tableau de gauche à droite. Calculez le complément. S'il est déjà présent dans le dictionnaire, renvoyez son indice et l'indice actuel. Sinon, mémorisez la valeur actuelle.

04 / Implémenter

Révéler la force brute
public static int[] TwoSumBrute(int[] nums, int target)
{
    for (int i = 0; i < nums.Length; i++)
        for (int j = i + 1; j < nums.Length; j++)
            if (nums[i] + nums[j] == target)
                return new[] { i, j };
    return Array.Empty<int>();
}

Il existe n(n−1)/2 paires : temps O(n²), espace supplémentaire O(1), hors résultat.

Révéler la version avec dictionnaire
public static int[] TwoSum(int[] nums, int target)
{
    var seen = new Dictionary<int, int>();
    for (int i = 0; i < nums.Length; i++)
    {
        int complement = target - nums[i];
        if (seen.TryGetValue(complement, out int previous))
            return new[] { previous, i };
        seen[nums[i]] = i;
    }
    return Array.Empty<int>();
}

Temps attendu O(n), espace O(n). Les opérations du dictionnaire sont en O(1) attendu, pas garanties dans tous les cas. Chercher avant d'insérer évite de réutiliser le même indice.

05 / Tester

TwoSum(new[] { 2, 7, 11, 15 }, 9); // [0, 1]
TwoSum(new[] { 3, 3 }, 6); // [0, 1]
TwoSum(new[] { -3, 4, 3 }, 0); // [0, 2]
TwoSum(new[] { 1 }, 2); // []
TwoSum(Array.Empty<int>(), 0); // []

06 / Améliorer

Définissez le comportement pour une entrée nulle et le dépassement d'entier. Pour des valeurs int sans restriction, calculez le complément avec long puis vérifiez avant conversion. Documentez la paire renvoyée lorsque plusieurs solutions existent.

07 / Comparer avec l'IA

Faites résoudre le même contrat à un assistant. Vérifiez les doublons, la réutilisation d'indice, le dépassement et les annonces de complexité. Le succès du premier exemple n'est pas une preuve.

Pause. Essayez d'abord vous-même.

Ouvrez votre éditeur et accordez-vous quinze minutes honnêtes. Revenez ensuite ouvrir un indice à la fois.

hint 1/2 Révéler l'indice

Calculez cible moins la valeur actuelle.

hint 2/2 Révéler l'indice

Mémorisez les valeurs précédentes dans un dictionnaire.

// le carnet, par e-mail

Apprenez avec moi.

Des idées d'ingénierie qui méritent d'être comprises.