Two Sum
Vous recevez un tableau d’entiers nums et un entier target. Exactement deux éléments de nums, situés à deux positions différentes, ont une somme égale à target. Renvoyez les indices de ces deux éléments, le plus petit indice en premier.
Fonction
- numsinteger-array
- le tableau d’entiers dans lequel effectuer la recherche
- targetinteger
- la somme que les deux entrées doivent atteindre
- Renvoieinteger-array
- les deux indices, le plus petit en premier
Contraintes
2 ≤ nums.length ≤ 104-109 ≤ nums[i] ≤ 109-109 ≤ target ≤ 109- Il existe exactement une paire de positions distinctes dont la somme est égale à
target.
Exemples
- Entrée
- nums = [3, 8, 12, 5]target = 17
- Sortie
- [2, 3]
- Explication
- 12 se trouve à l’indice 2 et 5 à l’indice 3, et 12 + 5 = 17. Aucune autre paire n’atteint 17.
- Entrée
- nums = [6, 1, 4, 10]target = 7
- Sortie
- [0, 1]
- Explication
- 6 à l’index 0 et 1 à l’index 1 donnent un total de 7 : la paire peut être constituée des deux premières entrées.
- Entrée
- nums = [2, -6, 9, 4, 13]target = 3
- Sortie
- [1, 2]
- Explication
- -6 à l’indice 1 et 9 à l’indice 2 donnent 3. Les nombres négatifs s’associent de la même manière que les nombres positifs.
Pour aller plus loin
Si nums était déjà trié, pourrais-tu trouver la paire en O(n) temps avec seulement O(1) mémoire supplémentaire ?
Indices
Ouvrez-les un par un. Chacun en dévoile un peu plus.
Essayer chaque paire avec deux boucles imbriquées est correct, mais avec 10 000 nombres, cela représente environ 50 millions de vérifications. Peux-tu trouver le partenaire de chaque nombre sans parcourir à nouveau la liste ?
Quand tu es sur une valeur
x, tu sais déjà quelle valeur compléterait la paire : la cible moinsx. La seule question est de savoir si tu as déjà rencontré cette valeur auparavant, et à quel indice.Parcourez la liste une seule fois et conservez une table de hachage associant chaque valeur déjà parcourue à son indice. À chaque position, recherchez d’abord la valeur complémentaire manquante ; si elle se trouve dans la table, vous avez les deux indices. Sinon, stockez la valeur actuelle et continuez. C’est le fait de rechercher avant de stocker qui empêche un nombre de s’associer à lui-même.
Solution
Vérifier chaque paire fonctionne, mais le travail augmente avec le carré de la longueur. Inverse la question : en partant d’un nombre x, tu sais déjà que son partenaire doit être target - x. Une table de hachage te permet de savoir en temps constant si tu es déjà passé par cette valeur, donc un seul parcours suffit.
Vérifiez chaque paire
Correcte, mais ne termine pas sur les plus gros tests
Intuition
Fixe un premier indice i et essaie chaque indice j à sa droite jusqu’à ce que nums[i] + nums[j] soit égal à target. Commencer j à i + 1 empêche une position de s’associer à elle-même, essaie chaque paire une seule fois et place le plus petit indice en premier. La paire recherchée fait partie des paires que tu essaies, donc tu la trouveras.
n nombres forment environ n²/2 paires : n = 10^4 signifie près de 5 × 10^7 additions.
Algorithme
- Parcourez chaque indice de
numsaveci. - Pour chaque
i, parcourez les indices à partir dei + 1jusqu'au dernier indice avecj. - Si
nums[i] + nums[j]est égal àtarget, renvoyez[i, j]. - Si les deux boucles se terminent, renvoyez un tableau vide. L'énoncé garantit que cela ne se produit jamais.
def twoSum(nums, target):
n = len(nums)
for i in range(n):
# Only look at partners to the right, so each pair is checked once.
for j in range(i + 1, n):
if nums[i] + nums[j] == target:
return [i, j]
return []Un passage avec une table de hachage
Intuition
Pour un nums[i] donné, la boucle interne de la méthode par force brute cherche une valeur que tu connais à l’avance : target - nums[i]. Cette recherche est en fait une consultation, et une table de hachage associant chaque valeur à un indice permet d’effectuer des consultations en temps constant en moyenne.
Consulte d’abord, stocke ensuite. Ainsi, un nombre ne peut être associé qu’à un nombre qui le précède, jamais à lui-même, et comme le nombre associé est toujours antérieur, son indice vient en premier. Chaque nombre est parcouru une seule fois, avec des opérations sur la table en temps constant ; la recherche est donc en O(n), au prix d’une table pouvant contenir jusqu’à n entrées.
Algorithme
- Créez une map vide associant chaque valeur à son index.
- Pour chaque index
i, calculezneed, la valeur qui complète la paire :targetmoinsnums[i]. - Si
needse trouve dans la map, renvoyez son index enregistré, suivi dei. - Sinon, enregistrez
nums[i]avec l’indexiet continuez.
def twoSum(nums, target):
seen = {}
for i, num in enumerate(nums):
need = target - num
if need in seen:
return [seen[need], i]
seen[num] = i
return []
Pièges et cas limites
- Stocker un nombre avant de chercher son complément. Avec
[4, 2, 6]ettarget = 8, le 4 se trouve lui-même et tu renvoies[0, 0]. - Renvoyer les indices dans le mauvais ordre. Lorsque la recherche précède le stockage, l’indice de la map est le plus petit et vient en premier.
- Trier le tableau pour utiliser deux pointeurs, puis renvoyer les positions dans la copie triée. Conserve l’indice d’origine à côté de chaque valeur.
- Supposer que les valeurs sont positives ou distinctes.
[0, 7, -3, 0]avectarget = 0associe les deux zéros :[0, 3]. - En Lua et en R, renvoyer les indices à base 1. Soustrais 1 à chacun.
Questions fréquentes3
Quelle est la complexité temporelle de Two Sum ?
La solution avec table de hachage s’exécute en O(n) temps, car elle parcourt chaque nombre une seule fois et que chaque recherche ou insertion prend un temps constant en moyenne. Elle utilise un espace supplémentaire de O(n) pour la table. Vérifier chaque paire prend O(n²) temps et O(1) espace.
Peut-on résoudre Two Sum sans espace supplémentaire ?
Pas en temps linéaire sur un tableau non trié. Avec un espace supplémentaire de O(1), tu dois vérifier chaque paire, ce qui prend O(n²). La table de hachage échange une mémoire de O(n) contre un temps linéaire.
Comment Two Sum gère-t-il les nombres en double ?
Les doublons fonctionnent quand tu recherches le nombre complémentaire avant de stocker le nombre actuel. Dans [7, 3, 7] avec target = 14, le premier 7 est stocké à l’index 0 et le second 7 le trouve, ce qui donne [0, 2]. Un 7 isolé ne peut jamais être associé à lui-même : il ne se trouve pas encore dans la map au moment où tu le recherches.
Problèmes similaires
Des problèmes qui reposent sur les mêmes idées. En résoudre deux ou trois, c’est ce qui ancre un schéma.
def twoSum(nums, target):
# Écrivez le code iciTest #1
Test #2
Test #3
Arguments
nums = [3, 8, 12, 5] target = 17
Résultat attendu
[2, 3]