1. Écrivez sur le devant
Au début de cet article, je me prépare à revenir sur la revue de la structure de base des données, comprenant principalement les tableaux, les tables de hachage, les listes chaînées, les chaînes, les piles et les files d'attente. Les sujets ici sont comparés à ceux du niveau d'algorithme précédent. Pensez-y un peu mieux, la difficulté diminuera, et il y a des idées très clés, vous pouvez généralement résoudre le problème après avoir écrit en silence. Tels que la méthode du double pointeur, la fenêtre coulissante, la pile monotone, etc. Cet article passe en revue les tableaux et les tables de hachage. En fait, j'estime que les tables de hachage sont un outil auxiliaire pour résoudre les problèmes de tableaux. Les méthodes et idées couramment utilisées sur les tableaux sont les suivantes: reconstruction de tableaux, double pointeurs, fenêtres coulissantes, outils couramment utilisés, dictionnaires, et collections.
À propos d'Array, nous devons connaître les points de connaissance:
- Opérations courantes sur les tableaux: ajouter, supprimer, modifier, vérifier et déplacer des éléments
- Accès au tableau à la complexité temporelle du tableau O (1), complexité temporelle d'insertion et de suppression O (n), mémoire continue
- Les sujets les plus classiques sont généralement d'étudier la combinaison, l'échange, l'ajout, la suppression, etc. d'éléments, et le parcours de tableaux
- Quelques idées impliquées ici:
- Les deux pointeurs sont parcourus l'un après l'autre, cela peut être inversé pour le tableau
- Les deux pointeurs sont parcourus de l'avant vers l'arrière, vous pouvez filtrer les éléments qui répondent à des conditions spécifiques
- Reconstruisez l'idée de la baie
- Fenêtre coulissante
- Espace pour le temps
- Stockage de hachage
- Pensée de traversée inversée
- Les avantages et inconvénients des tableaux (pour maîtriser une structure de données, il faut savoir analyser ses avantages et ses inconvénients)
- L'avantage du tableau est qu'il est très simple à construire et peut interroger un élément en fonction de l'index du tableau en temps O (1)
- Les inconvénients des tableaux sont: un espace continu doit être alloué pendant la construction, le tableau entier doit être parcouru lors de la requête pour savoir si un élément existe, et cela prend O (n) temps (où n est le nombre d'éléments), la suppression et l'ajout un élément Temps, il prend aussi O (n) temps
Par conséquent, lorsque vous envisagez d'utiliser un tableau pour aider votre algorithme, assurez-vous de prendre en compte ses avantages et ses inconvénients, et voyez si ses inconvénients entraveront la complexité de votre algorithme et la complexité de l'espace.
2. Idées de questions et tri du code
2.1 L'idée de reconstruire un tableau
- LeetCode283: Déplacer zéro : L'idée de reconstruire le tableau est de traiter le tableau actuel comme un tableau vide, puis d'utiliser un pointeur pour
non_zero_index
toujours pointer vers la fin du nouveau tableau (la valeur initiale est 0). Parcourez ensuite le tableau actuel, s'il n'est pas égal à 0, ajoutez-le au tableau vide etnon_zero_index
reculez en même temps , en pointant toujours vers la fin du nouveau tableau. Une fois ce parcours terminé, tous les élémentsnon_zero_index
suivants deviendront 0. code montrer comme ci-dessous:
- LeetCode27: Supprimer des éléments : L'idée de reconstruire le tableau est toujours l'idée de reconstruire le tableau, de traiter le tableau actuel comme un tableau vide, puis d'utiliser un pointeur pour
non_target_index
toujours pointer vers la fin du nouveau tableau (initialement 0). Parcourez ensuite le tableau actuel, s'il ne s'agit pas de la cible, ajoutez-le au tableau vide etnon_target_index
reculez en même temps , en pointant toujours vers la fin du nouveau tableau. Une fois cette traversée terminée, revenez simplementnon_target_index
.
- LeetCode26: Supprimer les doublons dans un tableau trié : L'idée de reconstruire le tableau est de traiter le tableau actuel comme un tableau vide, puis d'utiliser un pointeur pour
non_repeat_index
toujours pointer vers la fin du nouveau tableau (la valeur initiale est 1). Parcourez ensuite le tableau actuel (à partir de 1), s'il n'est pas égal au nombre précédent, ajoutez-le au tableau vide etnon_repeat_index
reculez en même temps , en pointant toujours vers la fin du nouveau tableau. Une fois cette traversée terminée, revenez simplementnon_repeat_index
.
L'idée de créer un nouveau tableau sur le tableau d'origine est très importante. Elle convient parfaitement au problème de la suppression d'éléments non qualifiés de la table de séquence, comme la suppression des éléments en double et la garantie que la position reste inchangée, la suppression des nombres négatifs, la suppression 0 éléments, et élever un niveau plus haut. Ce qui est pratique, c'est la pensée inverse , ne laisse-t-elle pas supprimer 0? Je ne recherche pas directement 0, puis je le supprime. Je recherche plutôt un autre élément que 0 à conserver. Ne supprime-je pas les doublons? Ne trouvez pas les doublons, puis supprimez-les, mais trouvez les non-dupliqués et conservez-les. Vivez bien.
2.2 Double pointeur
-
LeetCode11: Le contenant qui contient le plus d'eau : Ce mot violent est une boucle for à deux couches. Trouvez la zone délimitée par deux piliers, ce qui est évidemment trop inefficace. Voici donc la solution du double pointeur. Tout d'abord, vous devez savoir calculer la zone délimitée par les deux piliers :, La
min(柱子高) * (两根柱子之间的距离)
méthode du double pointeur est un pointeur gauche et un pointeur droit, marchant des deux côtés vers le milieu. le cœur de ce problème est de déterminer la taille de la zone. Le plus court des deux piliers (effet de tonneau) . Après avoir calculé la zone des piliers pointés par les deux pointeurs, comparez leurs longueurs et déplacez le pointeur sur le côté le plus court (s'il s'agit de i, déplacez-le vers la droite. j fait référence au décalage vers la gauche). Pourquoi? Étant donné que le côté court ne peut plus être optimisé, si vous ne déplacez pas le côté court à ce stade, puis déplacez le plus grand, la distance entre les deux piliers restants devient de plus en plus petite et la zone devient plus petite. Seul le côté avec le mouvement court, bien que la distance entre les deux soit plus courte, il peut être récupéré de la hauteur. code montrer comme ci-dessous:
-
LeetCode15: Somme de trois nombres : Le double pointeur de cette question est très intelligent. Triez d' abord le tableau de petit à grand , puis définissez le pointeur k pour qu'il commence à parcourir les éléments depuis le début. Pour chaque parcours, définissez les pointeurs i et j pour qu'ils pointent vers le début et la fin des éléments restants derrière k , puis juger si les trois pointeurs pointent vers les éléments égal à 0, enregistrer le résultat. Sinon, si la somme des trois est inférieure à 0, alors i recule. Comme l'élément pointé par i est petit, la somme totale est petite (là encore, l'effet barillet est construit). Si la somme des trois est supérieure à 0, j se déplace vers la gauche, car l'élément pointé par j est trop grand et la somme totale est grande. De cette manière, lorsque i et j se rencontrent, toutes les combinaisons du courant k ont été parcourues, recule k et répète les étapes ci-dessus. Mais la chose à laquelle il faut prêter attention dans ce processus est d'éviter de répéter des éléments . Comment éviter les répétitions? Parce que nous trions d'abord le tableau de petit à grand, si nous trouvons que l'élément pointé par le k courant est égal au k-1 précédent, nous sautons, indiquant que nous avons déjà trouvé cette situation. Ainsi, les points clés de cette question sont triés de petit à grand, fixez l'un des extrêmes et examinez les deux autres . code montrer comme ci-dessous:
-
LeetCode18: La somme de quatre nombres : Par rapport à la somme de trois chiffres, la somme de quatre chiffres ajoutera ici une couche de boucle, laissez m traverser chaque nombre, pour chaque nombre parcouru par m, k traverser le courant m Tout ce qui suit nombres, puis les deux pointeurs i et j pointent vers le début et la fin du tableau après k, puis jugent selon la logique ci-dessus. Si les quatre nombres s'additionnent pour être supérieurs à la cible, je recule et moins que la cible , j avancer et égaliser la cible, enregistrer le résultat, déplacer i vers l'arrière et avancer j. Mais il doit également y avoir des opérations de déduplication, et les opérations de déduplication doivent être dédupliquées partout où chaque pointeur est requis . Le code final est le suivant:
Dans la somme de trois nombres et la somme de quatre nombres, le tri est très important. -
LeetCode88: Combinez deux tableaux ordonnés : Cette question peut utiliser deux pointeurs pour parcourir le tableau de l'arrière vers l' avant . C'est la différence entre un tableau et une liste liée. La liste liée ne connaît pas la dernière queue, mais le tableau le sait à partir de de l'arrière vers l'avant, si le nombre le plus élevé, placez-le à la fin. À ce stade, si nums2 a un surplus, insérez-le directement à l'avant de nums1. S'il n'y a pas de surplus, cela signifie qu'il a été complètement inséré dans nums1 . code montrer comme ci-dessous:
2.3 Petit frais
-
Faire pivoter le tableau : une façon intelligente de réfléchir à cette question consiste à obtenir l'ordre de trois fois dans l'ordre inverse. Commencez par inverser l'ordre des éléments globaux, puis ajoutez 1 11 àkkLes éléments de k sont dans l'ordre inverse, et enfinkkk ~len (nums) len (nums)Les éléments de l e n ( n u m s ) peuvent être dans l'ordre inverse. Mais il y a un petit piège dans cette question est que sikkk est supérieur à la longueur du tableau et le reste doit être pris en premier.
-
Ajoutez-en un : inversez d'abord l'ordre, ajoutez 1 au premier chiffre, puis considérez l'opération de report arrière, puis inversez-la.
-
LeetCode54: Matrice en spirale : Il s'agit d'un processus de simulation de parcours de tableau, qui n'implique aucun algorithme, mais il examine la capacité de contrôle du code. La spirale parcourt la matrice vers l'intérieur, tout comme la trajectoire, la tétralogie est également considérée ici, qui sont la position de départ, la direction de déplacement, la limite et les conditions de fin . Prenez ce sujet pour analyser:
- Position de départ: Le point de départ de ce parcours est le coin supérieur gauche de la matrice, qui est la position (0,0)
- Direction du déplacement: chaque tour est d'abord vers la droite jusqu'à la fin, puis vers le bas jusqu'à la fin, puis vers la gauche jusqu'à la fin, puis jusqu'à la fin. Donc pour chaque tour, la direction est la même, c'est-à-dire droite -> bas -> gauche -> haut.
- Limite: C'est le cœur de cette question, car à chaque cercle, cette limite changera. La règle est qu'une fois le parcours de ligne (colonne) en cours terminé, la limite de cette ligne (colonne) doit être déplacée d'un carré vers l'intérieur. , Alors quand cette question se pose, il faut contrôler la frontière à tout moment, c'est la clé de la solution
- Condition de fin: La condition de fin de la traversée en spirale est que toutes les positions sont traversées.
Regardez le code:
-
LeetCode59: Spiral Matrix II : Cette rubrique est fondamentalement la même que celle ci-dessus, changez simplement le code, car la rubrique ci-dessus reçoit une matrice, laissez la spirale traverser la valeur de sortie, et cette rubrique est la traversée en spirale pour construire la matrice , Il y aura donc des différences dans le stockage des résultats. code montrer comme ci-dessous:
-
LeetCode885: Spiral Matrix III : Ce sujet est assez différent des deux précédents: le premier est que le point de départ n'est pas fixe et le second est la limite, si elle est déterminée par des pas de marche. Suivez les quatre étapes ci-dessus pour analyser:
-
Point de départ: c'est le titre (r0, c0) qui sera donné
-
La direction de déplacement est toujours droite -> bas -> gauche -> haut
-
Conditions aux limites, cette limite est modifiée dynamiquement et peut être divisée en fonction du cercle
- Au premier tour, j'ai marché 1 pas vers la droite de (r0, c0), 1 pas vers le bas, 2 pas vers la gauche, 2 pas vers le haut, jusqu'à (r1, c1)
- Dans le deuxième cercle, nous avons marché 3 pas vers la droite de (r1, c1), 3 pas vers le bas, 4 pas vers la gauche, 4 pas vers le haut, jusqu'à (r2, c2)
- Au troisième tour, faites 5 pas vers la droite depuis (r2, c2), 5 marches vers le bas, 6 marches vers la gauche, 6 marches vers le haut, jusqu'à (r3, c3)
- …
À partir de là, nous pouvons trouver la règle selon laquelle dans chaque cycle, le nombre de pas vers la droite et vers le bas est le même, et le nombre de pas vers la gauche et vers le haut est le même, et un pas de plus que d'aller vers la droite . Nous devons donc définir une étape pour contrôler les changements de limites.
-
Condition de terminaison: ici peut être contrôlée par le nombre de points passés
code montrer comme ci-dessous:
-
2.4 Fenêtre coulissante
-
LeetCode209: Le plus petit sous-tableau de longueur : J'ai appris une technique de fenêtre coulissante. Cette chose est encore une opération de double pointeur dans la langue vernaculaire, mais cette fois le double pointeur maintient une fenêtre en mouvement, donc la fenêtre coulissante sonne mieux. Et pour résoudre certains problèmes de tableau et de chaîne, la fenêtre coulissante est également un outil très utile, alors comment utiliser cette fenêtre coulissante? Tout d'abord, il y a plusieurs questions à considérer Lors du déplacement de la
right
fenêtre agrandie, comment la mettre à jour? ② Dans quelles conditions, la fenêtre doit faire une pause pour s'agrandir et commencer à se déplacer pourleft
réduire la fenêtre? ③Commentleft
mettre à jour lors du déplacement de la fenêtre réduite? ④Le résultat souhaité doit-il être mis à jour lorsque la fenêtre est agrandie ou lorsque la fenêtre est réduite?
Avec ce sujet, j'ai soigneusement traité ces problèmes, et j'ai trouvé que la fenêtre glissante est similaire à la dichotomie, et c'est aussi une sorte de framework. Tant que ces problèmes sont résolus, l'écriture du framework de code est fondamentalement corrigée .- Lors du déplacement de la
right
fenêtre agrandie, comment la mettre à jour? Pour cette question, lorsque vous vous déplacez vers la droite pour ajouter un nouvel élément,win_sum
vous devez accumuler le nouvel élément. - Dans quelles conditions, la fenêtre doit faire une pause pour se développer et commencer à se déplacer pour
left
réduire la fenêtre? Lorsque les éléments de la fenêtre sont supérieurs ou égaux à la cible , essayez de réduire la fenêtre. left
Que dois-je mettre à jour lors du déplacement de la fenêtre réduite?win_sum
Pour soustraire les éléments supprimés.- Le résultat souhaité doit-il être mis à jour lorsque la fenêtre est agrandie ou lorsque la fenêtre est réduite? Puisque nous voulons le plus petit nombre ici, nous devons mettre à jour le résultat lors de la réduction de la fenêtre, c'est-à-dire en
left
cours de déplacement vers la gauche.
Le code est le suivant: le
sujet de chaîne suivant, vous rencontrerez cet outil, puis le résumerez ici. - Lors du déplacement de la
2.5 Table de hachage
En python, les tables de hachage couramment utilisées sont les dictionnaires et les collections set (). Ces deux outils sont également très utiles. En python, les collections fournissent également defaultdict, Orderdict, etc. Examinons quelques problèmes de tableau qui peuvent atteindre l'objectif d'espace-temps en établissant un mappage de dictionnaire.
- LeetCode242: dyslexie des lettres valides: pour cette question, vous pouvez utiliser un dictionnaire pour compter le nombre de chaque lettre dans la première chaîne, puis parcourir la deuxième chaîne et les caractères qui apparaissent sont décalés. Lorsque le nombre de caractères dans le dictionnaire apparaît Si le nombre est négatif, cela signifie qu'il y a un caractère qui n'est pas apparu dans la chaîne précédente. À ce stade, renvoie False. code montrer comme ci-dessous:
-
LeetCode349: Intersection de deux tableaux : Ce problème peut utiliser la collection de jeux, car les éléments en double peuvent être supprimés ici. L'idée est de parcourir à partir de la liste courte. Pour chaque élément, s'il apparaît dans une autre liste, ajoutez-le à Par conséquent, le résultat est stocké ici en tant que collection, et finalement il peut être basculé vers la liste.
-
LeetCode202: Happy Number : La boucle infinie dans cette question est très importante. S'il y a une somme répétée, elle bouclera indéfiniment. Donc la clé de cette question est de voir s'il y a une somme répétée, et de juger la répétition, le La première chose qui me vient à l'esprit devrait être C'est une collection d'ensemble. L'idée est de calculer d'abord la somme des carrés du nombre de positions de n, et de renvoyer True s'il est égal à 1, sinon, de déterminer s'il est apparu avant, et si c'est le cas, de retourner False. Sinon, rejoignez l'ensemble, puis déterminez la somme des carrés de la somme des carrés et répétez. code montrer comme ci-dessous:
-
LeetCode1: La somme de deux nombres : Avec map, ce problème peut être complété avec une complexité temporelle O (n). Ici, vous devez d'abord créer un
值:索引
dictionnaire de mappage, puis parcourir le tableau depuis le début . Pour le nombre actuel, vérifiez si le nombre cible est dans le dictionnaire. Si tel est le cas, renvoyez l'index du nombre et la valeur correspondant à la clé du dictionnaire. Sinon, enregistrez le numéro dans le dictionnaire. -
LeetCode454: Ajout de quatre nombres II : Ce n'est pas la même chose que la somme de quatre nombres. Les éléments de celui-ci sont placés dans chaque tableau indépendant, et il n'est pas nécessaire de se demander s'il faut supprimer les doublons, tant que quatre éléments sont trouvés La somme est égale à 0. Ensuite, ce problème peut être converti en la somme de deux nombres, car
A+B+C+D = 0
, en fait, il peut être vu comme(A+B) + (C+D) = 0
, de cette manière, traverser A, B, obtenir un mappage de dictionnaire{A+B: count}
, cout représente le nombre d'occurrences de A + B, et puis traversez C, D, aussi longtemps que 0 La clé de - (C + D) est dans le dictionnaire ci-dessus, indiquant que le groupe de comptage égal à 0 est trouvé, et le compteur peut être incrémenté de comptage. Le code spécifique est le suivant:
-
LeetCode383: Lettre de rançon : Il s'agit d'un autre problème de compensation des nombres. Définissez un dictionnaire pour compter le nombre de chaque caractère dans le magazine, puis traversez la rançon. Si le caractère actuel n'est pas dans le dictionnaire, renvoyez False. Le nombre de caractères correspondants dans le dictionnaire est décalé de 1. Lorsqu'il s'agit d'un nombre négatif, il renvoie False. Lorsque la rançon est traversée, elle renvoie True.
3. M. Général
Les méthodes couramment utilisées pour le sujet du tableau sont l'idée de reconstruire le tableau, la méthode du double pointeur, la méthode de la table de hachage et la fenêtre glissante. L'idée de reconstruire des tableaux reflète une sorte de réflexion inverse. Les doubles pointeurs sont très importants. En fait, les doubles pointeurs ne sont pas seulement des pointeurs gauche et droit, mais aussi des pointeurs rapides et lents, ainsi que la méthode de la fenêtre glissante. les scénarios ne sont pas les mêmes.:
- Les pointeurs rapides et lents conviennent généralement aux problèmes de liste chaînée. Ce type d'anneau existe. Cela se produira lors de la liaison de listes.
- Les pointeurs gauche et droit sont généralement utilisés dans la recherche binaire. Pour la somme de trois nombres et la somme de quatre nombres ici, les pointeurs gauche et droit sont utilisés pour résoudre le problème très intelligemment, à condition que le tri soit nécessaire. Ce commun est utilisé dans le problème des opérations de tableau
- La fenêtre coulissante est aussi la première fois à apprendre, et je pense que c'est aussi un outil très utile qui résoudra généralement les problèmes liés aux sous-chaînes, et vous les rencontrerez dans des chaînes.
En ce qui concerne la méthode de la table de hachage, ce scénario couramment utilisé consiste à compter le nombre d'éléments dans une carte, à déterminer des ensembles répétés, à voir si les éléments sont dans un certain ensemble, etc. L'idée de décalage de caractère est également courante dans ce domaine.
Enfin, il y a quelques petites questions claires. Il existe de pures questions de simulation de traversée de tableau, comme la matrice en spirale. Ce type de concentration est sur les capacités de base de manipulation de tableau. Généralement, le point de départ, la direction du déplacement, les limites et les conditions de fin doivent être déterminé., Ce genre de besoin de trouver la loi de la marche en premier. D'autres sujets sont la recherche d'idées intelligentes, cela n'a pas de routine fixe et est bien informé.
Tout en brossant la programmation dynamique, j'ai pris un certain temps pour passer en revue les connaissances précédentes. La section sur les tableaux a pris quatre ou cinq jours pour passer en revue, environ 10 questions, résumées comme suit:
L'idée de reconstruire le tableau
- LeetCode283: Déplacement du zéro
- LeetCode27: Supprimer des éléments
- LeetCode26: Supprimer les éléments en double dans un tableau trié
Double pointeur
- LeetCode11: Le contenant avec le plus d'eau
- LeetCode15: Somme de trois nombres
- LeetCode18: Somme de quatre nombres
- LeetCode88: Combinez deux tableaux ordonnés
Petit frais :
- Faire pivoter le tableau
- un de plus
- LeetCode54: Matrice en spirale
- LeetCode59: Matrice spirale II
- LeetCode885: Matrice spirale III
Fenêtre coulissante :
Table de hachage :