|
6 | 6 | <title>LeetCode: Snail Traversal - 蛇行パターンで1D→2D配列変換</title> |
7 | 7 |
|
8 | 8 | <!-- Tailwind CSS --> |
9 | | - <script src="https://cdn.tailwindcss.com"></script> |
| 9 | + <script |
| 10 | + src="https://cdn.tailwindcss.com/3.4.1" |
| 11 | + crossorigin="anonymous" |
| 12 | + ></script> |
10 | 13 |
|
11 | 14 | <!-- Google Fonts --> |
12 | 15 | <link rel="preconnect" href="https://fonts.googleapis.com" /> |
|
20 | 23 | <link |
21 | 24 | href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css" |
22 | 25 | rel="stylesheet" |
| 26 | + integrity="sha384-wFjoQjtV1y5jVHbt0p35Ui8aV8GVpEZkyF99OXWqP/eNJDU93D3Ugxkoyh6Y2I4" |
| 27 | + crossorigin="anonymous" |
23 | 28 | /> |
24 | 29 | <link |
25 | 30 | href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.css" |
26 | 31 | rel="stylesheet" |
| 32 | + integrity="sha384-AnUkTNLI8COlMCRJ0FHIdX76If83145OTCLUx4gQyfnO0gGeO/sD9czGEUBxtkUU" |
| 33 | + crossorigin="anonymous" |
27 | 34 | /> |
28 | 35 | <link |
29 | 36 | href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/toolbar/prism-toolbar.min.css" |
30 | 37 | rel="stylesheet" |
| 38 | + integrity="sha384-vEUzJ34/1CCeefTGUKLgvA5Z/vYIwi+Jyu8aAaCfFDxfwZ3Xs3OfkkIeegsLRM11" |
| 39 | + crossorigin="anonymous" |
31 | 40 | /> |
32 | 41 |
|
33 | 42 | <style> |
@@ -242,44 +251,40 @@ <h3 class="text-xl font-semibold text-teal-800 mt-6 mb-3">戦略のポイント< |
242 | 251 | TypeScript実装(最適化版) |
243 | 252 | </h2> |
244 | 253 |
|
245 | | - <pre class="line-numbers"><code class="language-typescript">declare global { |
246 | | - interface Array<T> { |
247 | | - snail(rowsCount: number, colsCount: number): number[][]; |
248 | | - } |
| 254 | + <pre class="line-numbers"><code class="language-typescript">declare interface Array<T> { |
| 255 | + snail(rowsCount: number, colsCount: number): T[][]; |
249 | 256 | } |
250 | 257 |
|
251 | 258 | /** |
252 | | - * 1D配列をSnail traversal patternで2D配列に変換(最適化版) |
253 | | - * ビット演算と整数除算でパフォーマンス向上 |
| 259 | + * 1D配列をSnail traversal patternで2D配列に変換 |
254 | 260 | * |
255 | 261 | * @param rowsCount - 結果の行数 |
256 | 262 | * @param colsCount - 結果の列数 |
257 | 263 | * @returns 2D配列(Snail pattern)、無効な入力の場合は空配列 |
258 | | - * @complexity Time: O(n), Space: O(n) |
| 264 | + * @complexity Time: O(n), Space: O(n) where n = this.length |
259 | 265 | */ |
260 | | -Array.prototype.snail = function(rowsCount: number, colsCount: number): number[][] { |
261 | | - const n = this.length; |
262 | | - |
263 | | - // 入力バリデーション(早期リターン) |
264 | | - if (rowsCount * colsCount !== n) return []; |
265 | | - |
266 | | - // 1段階での配列初期化(メモリ効率向上) |
267 | | - const result: number[][] = []; |
268 | | - for (let i = 0; i < rowsCount; i++) { |
269 | | - result[i] = []; |
| 266 | +Array.prototype.snail = function<T>(rowsCount: number, colsCount: number): T[][] { |
| 267 | + // 入力バリデーション |
| 268 | + if (rowsCount * colsCount !== this.length) { |
| 269 | + return []; |
270 | 270 | } |
271 | 271 |
|
272 | | - // メインループ(最適化) |
273 | | - for (let i = 0; i < n; i++) { |
274 | | - // 列番号を計算(ビットOR演算で整数化、Math.floorより高速) |
275 | | - const col = (i / rowsCount) | 0; |
| 272 | + // 結果配列の初期化 |
| 273 | + const result: T[][] = Array.from({ length: rowsCount }, () => |
| 274 | + new Array(colsCount) |
| 275 | + ); |
| 276 | + |
| 277 | + // Snail traversal pattern実装 |
| 278 | + for (let i = 0; i < this.length; i++) { |
| 279 | + // 列番号を計算 |
| 280 | + const col = Math.floor(i / rowsCount); |
276 | 281 |
|
277 | 282 | // 列内での位置 |
278 | | - const pos = i % rowsCount; |
| 283 | + const positionInCol = i % rowsCount; |
279 | 284 |
|
280 | 285 | // 偶数列: 上から下、奇数列: 下から上 |
281 | | - // ビット演算での偶奇判定(col % 2より約2倍高速) |
282 | | - const row = (col & 1) ? rowsCount - 1 - pos : pos; |
| 286 | + const row = |
| 287 | + col % 2 === 0 ? positionInCol : rowsCount - 1 - positionInCol; |
283 | 288 |
|
284 | 289 | result[row][col] = this[i]; |
285 | 290 | } |
@@ -1156,9 +1161,14 @@ <h3 class="text-xl font-semibold text-teal-800 mt-8 mb-4">実装方法の比較< |
1156 | 1161 | ></script> |
1157 | 1162 |
|
1158 | 1163 | <!-- Babel Standalone --> |
1159 | | - <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> |
| 1164 | + <script src="https://unpkg.com/@babel/standalone@7.23.5/babel.min.js" integrity="sha384-1qlE7MZPM2pHD/pBZCU/yB8UCP52RYL8bge/qNdfNBCWToySp8/M+JL2waXU4hjJ" crossorigin="anonymous"></script> |
1160 | 1165 |
|
1161 | | - <!-- Prism.js --> |
| 1166 | + <!-- Prism.js & Plugins (SRI Protected) --> |
| 1167 | + <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js" integrity="sha384-06z5D//U/xpvxZHuUz92xBvq3DqBBFi7Up53HRrbV7Jlv7Yvh/MZ7oenfUe9iCEt" crossorigin="anonymous"></script> |
| 1168 | + <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-typescript.min.js" integrity="sha384-PeOqKNW/piETaCg8rqKFy+Pm6KEk7e36/5YZE5XO/OaFdO+/Aw3O8qZ9qDPKVUgx" crossorigin="anonymous"></script> |
| 1169 | + <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.js" integrity="sha384-6QJu8apxMmB9TiPVWzYKF5pRgKcz7snO0/QU+MrWmgBLECQjoa6erxX2VQ5t41Jd" crossorigin="anonymous"></script> |
| 1170 | + <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/toolbar/prism-toolbar.min.js" integrity="sha384-jC1G68eGEXJpPwMDNqyIUQsQlcUCdCU+a7GGuoV4TUZvM1gLYTMJUDvqBnxtZLWA" crossorigin="anonymous"></script> |
| 1171 | + <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js" integrity="sha384-ZdEfx8sYX8i4IVXU1tUbqwOp4PBUCCmnpagpiHchnstXkEczkzPfUd9fvBrntM+F" crossorigin="anonymous"></script> |
1162 | 1172 |
|
1163 | 1173 | <!-- React Component --> |
1164 | 1174 | <script type="text/babel"> |
@@ -1287,36 +1297,18 @@ <h3 class="text-xl font-semibold text-teal-800 mt-8 mb-4">実装方法の比較< |
1287 | 1297 | <p className="font-semibold text-emerald-900"> |
1288 | 1298 | Snail Traversalパターン: |
1289 | 1299 | </p> |
1290 | | - <ul className="space-y-1 text-slate-700 mt-2"> |
1291 | | - <li> |
1292 | | - • 列0: 上から下 [ |
1293 | | - {visual.result2d.map((r) => r[0]).join(', ')}] |
1294 | | - </li> |
1295 | | - <li> |
1296 | | - • 列1: 下から上 [ |
1297 | | - {[...visual.result2d] |
1298 | | - .reverse() |
1299 | | - .map((r) => r[1]) |
1300 | | - .join(', ')} |
1301 | | - ] |
1302 | | - </li> |
1303 | | - {visual.result2d[0].length > 2 && ( |
1304 | | - <li> |
1305 | | - • 列2: 上から下 [ |
1306 | | - {visual.result2d.map((r) => r[2]).join(', ')}] |
1307 | | - </li> |
1308 | | - )} |
1309 | | - {visual.result2d[0].length > 3 && ( |
1310 | | - <li> |
1311 | | - • 列3: 下から上 [ |
1312 | | - {[...visual.result2d] |
1313 | | - .reverse() |
1314 | | - .map((r) => r[3]) |
1315 | | - .join(', ')} |
1316 | | - ] |
1317 | | - </li> |
1318 | | - )} |
1319 | | - </ul> |
| 1300 | + {visual.result2d[0].map((_, colIdx) => { |
| 1301 | + const isEvenCol = colIdx % 2 === 0; |
| 1302 | + const colValues = isEvenCol |
| 1303 | + ? visual.result2d.map(r => r[colIdx]) |
| 1304 | + : [...visual.result2d].reverse().map(r => r[colIdx]); |
| 1305 | + |
| 1306 | + return ( |
| 1307 | + <li key={colIdx}> |
| 1308 | + • 列{colIdx}: {isEvenCol ? '上から下' : '下から上'} [{colValues.join(', ')}] |
| 1309 | + </li> |
| 1310 | + ); |
| 1311 | + })} |
1320 | 1312 | </div> |
1321 | 1313 | </div> |
1322 | 1314 | )} |
@@ -1486,12 +1478,6 @@ <h3 class="text-xl font-semibold text-teal-800 mt-8 mb-4">実装方法の比較< |
1486 | 1478 |
|
1487 | 1479 | useEffect(() => { |
1488 | 1480 | if (isPlaying) { |
1489 | | - if (activeStep > stepsData.length) { |
1490 | | - setIsPlaying(false); |
1491 | | - setActiveStep(1); |
1492 | | - return; |
1493 | | - } |
1494 | | - |
1495 | 1481 | timerRef.current = setTimeout(() => { |
1496 | 1482 | if (activeStep === stepsData.length) { |
1497 | 1483 | setActiveStep(1); |
|
0 commit comments