|
| 1 | +# 885. Spiral Matrix III |
| 2 | + |
| 3 | +## Énoncé |
| 4 | + |
| 5 | +Vous commencez à la cellule `(rStart, cStart)` d'une grille de dimensions `rows x cols`, face à l'est. Le coin nord-ouest se trouve à la première ligne et la première colonne de la grille, et le coin sud-est se trouve à la dernière ligne et colonne. |
| 6 | + |
| 7 | +Vous allez marcher en spirale dans le sens des aiguilles d'une montre pour visiter chaque position de cette grille. Chaque fois que vous sortez des limites de la grille, vous continuez votre marche en dehors de la grille (mais il est possible de revenir plus tard à la frontière de la grille). Finalement, vous atteignez toutes les `rows * cols` cases de la grille. |
| 8 | + |
| 9 | +Retournez un tableau de coordonnées représentant les positions de la grille dans l'ordre dans lequel vous les avez visitées. |
| 10 | + |
| 11 | +## Exemple |
| 12 | + |
| 13 | +**Exemple 1:** |
| 14 | + |
| 15 | +<img src="./imgs/img1.png"/> |
| 16 | + |
| 17 | +**Input:** rows = 1, cols = 4, rStart = 0, cStart = 0 |
| 18 | +**Output:** [[0,0],[0,1],[0,2],[0,3]] |
| 19 | + |
| 20 | +**Exemple 2:** |
| 21 | + |
| 22 | +<img src="./imgs/img2.png"/> |
| 23 | + |
| 24 | +**Input:** rows = 5, cols = 6, rStart = 1, cStart = 4 |
| 25 | +**Output:** [[1,4],[1,5],[2,5],[2,4],[2,3],[1,3],[0,3],[0,4],[0,5],[3,5],[3,4],[3,3],[3,2],[2,2],[1,2],[0,2],[4,5],[4,4],[4,3],[4,2],[4,1],[3,1],[2,1],[1,1],[0,1],[4,0],[3,0],[2,0],[1,0],[0,0]] |
| 26 | + |
| 27 | +## Contraintes |
| 28 | + |
| 29 | +`1 <= rows, cols <= 100` |
| 30 | +`0 <= rStart < rows` |
| 31 | +`0 <= cStart < cols` |
| 32 | + |
| 33 | +## Note personnelle |
| 34 | + |
| 35 | +### Approche 1: Simulation |
| 36 | + |
| 37 | +En examinant les illustrations de l'exemple, on constate qu'à chaque changement de direction, la longueur du déplacement sur l'axe concerné augmente tous les deux mouvements. |
| 38 | + |
| 39 | +Cela crée une séquence de longueurs comme suit : [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, ...]. |
| 40 | + |
| 41 | +L'algorithme simule simplement cette séquence de longueurs tout en parcourant la matrice. Si la position actuelle se trouve dans les limites de la matrice, on ajoute ses coordonnées à notre tableau de réponse. |
| 42 | + |
| 43 | +```cpp |
| 44 | +// Directions correspondantes aux mouvements dans l'ordre : droite, bas, gauche, haut |
| 45 | +vector<vector<int>> dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; |
| 46 | + |
| 47 | +vector<vector<int>> spiralMatrixIII(int rows, int cols, int rStart, int cStart) { |
| 48 | + // Calcul de la taille totale de la matrice |
| 49 | + int size = rows * cols; |
| 50 | + |
| 51 | + // Initialisation de la matrice de résultat avec la position de départ |
| 52 | + vector<vector<int>> ans = {{rStart, cStart}}; |
| 53 | + |
| 54 | + // Variables pour garder la trace de la position actuelle |
| 55 | + int currR = rStart; |
| 56 | + int currC = cStart; |
| 57 | + // Variable pour indiquer la direction actuelle |
| 58 | + int d = 0; |
| 59 | + |
| 60 | + // Boucle jusqu'à ce que toutes les positions valides soient visitées |
| 61 | + while (ans.size() != size) { |
| 62 | + // Détermine la longueur de la prochaine étape dans la direction courante |
| 63 | + int length = (d / 2) + 1; |
| 64 | + // Sélectionne la direction actuelle (0: droite, 1: bas, 2: gauche, 3: haut) |
| 65 | + int curr = d % 4; |
| 66 | + |
| 67 | + // Avance dans la direction choisie pour la longueur déterminée |
| 68 | + for(int i = 0; i < length; i++){ |
| 69 | + currR += dir[curr][0]; // Mise à jour de la ligne courante |
| 70 | + currC += dir[curr][1]; // Mise à jour de la colonne courante |
| 71 | + |
| 72 | + // Vérifie si la nouvelle position est dans les limites de la matrice |
| 73 | + if (currR >= 0 && currR < rows && currC >= 0 && currC < cols) { |
| 74 | + // Si c'est le cas, ajoute cette position à la liste des résultats |
| 75 | + ans.push_back({currR, currC}); |
| 76 | + } |
| 77 | + } |
| 78 | + |
| 79 | + // Passe à la direction suivante |
| 80 | + d++; |
| 81 | + } |
| 82 | + |
| 83 | + return ans; |
| 84 | +} |
| 85 | +``` |
| 86 | +
|
| 87 | +- Complexité Temporelle: `O(m * n)`. |
| 88 | +- Complexité Spatiale: `O(m * n)`. |
| 89 | +
|
| 90 | +### Optimisation |
| 91 | +
|
| 92 | +Pour améliorer l'approche précédente, l'idée est de sauter les positions invalides, ce qui permet de réduire le nombre d'itérations. |
| 93 | +
|
| 94 | +Il existe quatre types de sauts possibles : |
| 95 | +
|
| 96 | +- Lorsque l'on incrémente la position sur un axe: |
| 97 | + - Si la position actuelle est inférieure à 0, on saute jusqu'à -1. |
| 98 | + - Si la position actuelle est supérieure ou égale à 0, on saute jusqu'à avoir parcouru `length` cases au total. |
| 99 | +- Lorsque l'on décrémente la position sur un axe: |
| 100 | + - Si la position actuelle dépasse la dernière case de l'axe, on saute jusqu'à cette dernière case. |
| 101 | + - Si la position actuelle est inférieure à la dernière case de l'axe, on saute jusqu'à avoir parcouru `length` cases au total. |
| 102 | +
|
| 103 | +Ici, `length` représente le nombre de cases à parcourir sur l'axe en cours. |
| 104 | +
|
| 105 | +```cpp |
| 106 | +// Définition des directions de mouvement : droite, bas, gauche, haut |
| 107 | +vector<vector<int>> dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; |
| 108 | +
|
| 109 | +// Fonction pour ajuster les coordonnées lorsqu'on dépasse les limites sur les axes positif |
| 110 | +void jumpA(int &i, int &curr, int length){ |
| 111 | + // Si on sort du côté négatif, on ramène curr à -1 et ajuste l'indice i |
| 112 | + if(curr < 0){ |
| 113 | + i += abs(curr) - 1; |
| 114 | + curr = -1; |
| 115 | + } |
| 116 | + // Sinon, on avance curr au maximum permis par la longueur restante et ajuste i |
| 117 | + else{ |
| 118 | + curr += length - i - 1; |
| 119 | + i = length; |
| 120 | + } |
| 121 | +} |
| 122 | +
|
| 123 | +// Fonction pour ajuster les coordonnées lorsqu'on dépasse les limites sur les axes négatif |
| 124 | +void jumpB(int &i, int &curr, int length, int n){ |
| 125 | + // Si curr dépasse la limite supérieure, on l'ajuste à la limite et ajuste l'indice i |
| 126 | + if(curr >= n){ |
| 127 | + i += curr - n; |
| 128 | + curr = n; |
| 129 | + } |
| 130 | + // Sinon, on recule curr de la longueur restante et ajuste i |
| 131 | + else{ |
| 132 | + curr -= length - i - 1; |
| 133 | + i = length; |
| 134 | + } |
| 135 | +} |
| 136 | +
|
| 137 | +// Génère une matrice parcourue en spirale à partir d'une position de départ |
| 138 | +vector<vector<int>> spiralMatrixIII(int rows, int cols, int rStart, int cStart) { |
| 139 | + // Calcul de la taille totale de la matrice |
| 140 | + int size = rows * cols; |
| 141 | +
|
| 142 | + // Initialisation de la matrice de résultat avec la position de départ |
| 143 | + vector<vector<int>> ans = {{rStart, cStart}}; |
| 144 | +
|
| 145 | + // Variables pour garder la trace de la position actuelle |
| 146 | + int currR = rStart; |
| 147 | + int currC = cStart; |
| 148 | + // Variable pour indiquer la direction actuelle |
| 149 | + int d = 0; |
| 150 | +
|
| 151 | + // Boucle jusqu'à ce que toutes les positions valides soient visitées |
| 152 | + while (ans.size() != size) { |
| 153 | + // Détermine la longueur de la prochaine étape dans la direction courante |
| 154 | + int length = (d / 2) + 1; |
| 155 | + // Sélectionne la direction actuelle (0: droite, 1: bas, 2: gauche, 3: haut) |
| 156 | + int curr = d % 4; |
| 157 | +
|
| 158 | + // Avance dans la direction choisie pour la longueur déterminée |
| 159 | + for(int i = 0; i < length; i++){ |
| 160 | + currR += dir[curr][0]; // Mise à jour de la ligne courante |
| 161 | + currC += dir[curr][1]; // Mise à jour de la colonne courante |
| 162 | +
|
| 163 | + // Si la nouvelle position est à l'intérieur de la matrice, l'ajoute au résultat |
| 164 | + if (currR >= 0 && currR < rows && currC >= 0 && currC < cols) { |
| 165 | + ans.push_back({currR, currC}); |
| 166 | + } |
| 167 | + // Si la position dépasse les limites elle est ajusté |
| 168 | + else { |
| 169 | + if(curr == 0){ |
| 170 | + jumpA(i, currC, length); // Ajuste la colonne en cas de dépassement à droite |
| 171 | + } |
| 172 | + else if(curr == 1){ |
| 173 | + jumpA(i, currR, length); // Ajuste la ligne en cas de dépassement en bas |
| 174 | + } |
| 175 | + else if(curr == 2){ |
| 176 | + jumpB(i, currC, length, cols); // Ajuste la colonne en cas de dépassement à gauche |
| 177 | + } |
| 178 | + else { |
| 179 | + jumpB(i, currR, length, rows); // Ajuste la ligne en cas de dépassement en haut |
| 180 | + } |
| 181 | + } |
| 182 | + } |
| 183 | +
|
| 184 | + // Passe à la direction suivante |
| 185 | + d++; |
| 186 | + } |
| 187 | +
|
| 188 | + return ans; |
| 189 | +} |
| 190 | +``` |
| 191 | + |
| 192 | +- Complexité Temporelle: `O(m * n)`. |
| 193 | +- Complexité Spatiale: `O(m * n)`. |
| 194 | + |
| 195 | +Cette optimisation n'affecte pas la complexité temporelle, cependant elle permet de réduire de manière significative le nombre d'itérations lorsque le point de départ est proche des bords de la matrice. |
| 196 | + |
| 197 | +<img src="./imgs/runtime.png"/> |
| 198 | +<img src="./imgs/memory.png"/> |
0 commit comments