-
Notifications
You must be signed in to change notification settings - Fork 0
Add LeetCode 88. Merge Sorted Array (Claude 4.6 Sonnet) implementatio… #325
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
deeaaab
Add LeetCode 88. Merge Sorted Array (Claude 4.6 Sonnet) implementatio…
myoshi2891 3285bec
Refine LeetCode 88 implementations: Update complexity notes, Rust ind…
myoshi2891 61c21df
Refine LeetCode 88 (Python, Rust, TS): Correct space complexity for P…
myoshi2891 303c39d
Refine LeetCode 88 (Python, Rust, TS): Synchronize complexity tables,…
myoshi2891 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
129 changes: 129 additions & 0 deletions
129
.../claude 4.6 sonnet extended/88. Merge Sorted Array/Merge_Sorted_Array_Python.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,129 @@ | ||
| ## 1. 問題分析結果 | ||
|
|
||
| ### 競技プログラミング視点 | ||
|
|
||
| `nums1` の末尾から逆順に埋める3ポインタ法が最適。CPython では `list` のインデックスアクセスは O(1) の C 実装であり、本実装のようにスライス代入を用いると最悪ケース O(n) の追加空間を消費しますが、時間計算量 O(m+n) を達成できます。 | ||
|
|
||
| ### 業務開発視点 | ||
|
|
||
| LeetCode のシグネチャは `None` 返却の破壊的操作。Pylance 対応のため `List[int]` 型ヒントを厳密に付与し、`m`/`n` は `int` として明示します。エッジケース(`n == 0`)は早期リターンで明示的に処理します。 | ||
|
|
||
| ### Python特有分析 | ||
|
|
||
| - `list.__setitem__` は C レイヤーで動作し、純粋な Python ループでも高速 | ||
| - `nums1[k], i, j, k` のローカル変数参照はグローバル参照より高速(LOAD_FAST) | ||
| - 競技版では `while` + インデックス直接操作が最速(イテレータ生成コスト不要) | ||
| - `nums1[:j+1] = nums2[:j+1]` のスライス代入は C の `memmove` 相当で残余コピーを一括処理可能 | ||
|
|
||
| --- | ||
|
|
||
| ## 2. アルゴリズムアプローチ比較 | ||
|
|
||
| | アプローチ | 時間計算量 | 空間計算量 | Python実装コスト | 可読性 | 標準ライブラリ活用 | CPython最適化 | 備考 | | ||
| | ---------------------- | ---------------- | ---------- | ---------------- | ------ | ------------------ | ------------------- | ------------------------- | | ||
| | 後ろから3ポインタ | O(m+n) | O(n) | 低 | ★★★ | なし | 適 | 追加アロケーションなし ✅ | | ||
| | コピー後 `list.sort()` | O((m+n)log(m+n)) | O(m+n) | 最低 | ★★★ | なし | 適(Timsort C実装) | 競技次善策 | | ||
| | `heapq.merge` + 展開 | O(m+n) | O(m+n) | 低 | ★★☆ | heapq | 適 | 一時リスト生成が発生 | | ||
|
|
||
| --- | ||
|
|
||
| ## 3. 採用アルゴリズムと根拠 | ||
|
|
||
| - **選択**: 後ろからの3ポインタマージ(業務版・競技版ともに同一戦略) | ||
| - **Python最適化戦略**: 残余コピーをスライス代入 `nums1[:j+1] = nums2[:j+1]` に置換することで、CPython 内部の `memmove` が発動し逐次代入より高速 | ||
| - **トレードオフ**: スライス代入は最大 O(n) サイズの一時リストオブジェクトを生成するため、厳密な O(1) 空間計算量が必要な場合は while ループで要素ごとにコピーする手法が適している | ||
|
|
||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| --- | ||
|
|
||
| ## 4. 実装パターン | ||
|
|
||
| ```python | ||
| # Runtime 0 ms | ||
| # Beats 100.00% | ||
| # Memory 19.42 MB | ||
| # Beats 35.99% | ||
| from typing import List | ||
|
|
||
| class Solution: | ||
| def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None: | ||
| """ | ||
| 2つのソート済み配列を nums1 にインプレースでマージする。 | ||
| 後ろから走査する3ポインタ法により O(m+n) 時間・O(n) 追加空間(スライス代入による最悪ケース)を実現。 | ||
|
|
||
| 不変条件: k >= i が常に成立するため nums1 の未処理要素を上書きしない。 | ||
| 初期値 k - i = n >= 0 が各イテレーションで保持される。 | ||
|
|
||
| Args: | ||
| nums1: マージ先リスト(長さ m+n、末尾 n 要素は 0 で埋められている) | ||
| m: nums1 の有効要素数 | ||
| nums2: マージ元リスト(長さ n) | ||
| n: nums2 の要素数 | ||
|
|
||
| Time Complexity: O(m + n) | ||
| Space Complexity: O(n) ※スライス代入の一時オブジェクトによる最悪ケース | ||
| """ | ||
| # ── 業務開発版 ───────────────────────────────────────────── | ||
| # n == 0 のとき nums1 は既に完成しているため早期リターン | ||
| if n == 0: | ||
| return | ||
|
|
||
| i: int = m - 1 # nums1 有効末尾ポインタ | ||
| j: int = n - 1 # nums2 末尾ポインタ | ||
| k: int = m + n - 1 # 書き込み位置ポインタ | ||
|
|
||
| # どちらかが尽きるまで大きい方を末尾に書き込む | ||
| while i >= 0 and j >= 0: | ||
| if nums1[i] >= nums2[j]: | ||
| nums1[k] = nums1[i] | ||
| i -= 1 | ||
| else: | ||
| nums1[k] = nums2[j] | ||
| j -= 1 | ||
| k -= 1 | ||
|
|
||
| # nums2 の残余要素を一括スライス代入(CPython の memmove 相当で高速) | ||
| # nums1 の残余は既に正しい位置にあるため操作不要 | ||
| if j >= 0: | ||
| nums1[: j + 1] = nums2[: j + 1] | ||
|
|
||
| def merge_competitive( | ||
| self, nums1: List[int], m: int, nums2: List[int], n: int | ||
| ) -> None: | ||
| """ | ||
| 競技プログラミング向け最適化実装。 | ||
| ローカル変数へのキャッシュで LOAD_FAST を最大活用。 | ||
|
|
||
| Time Complexity: O(m + n) | ||
| Space Complexity: O(n) | ||
| """ | ||
| # ローカル変数へのバインドで属性ルックアップを排除 | ||
| i, j, k = m - 1, n - 1, m + n - 1 | ||
|
|
||
| while i >= 0 and j >= 0: | ||
| if nums1[i] >= nums2[j]: | ||
| nums1[k] = nums1[i] | ||
| i -= 1 | ||
| else: | ||
| nums1[k] = nums2[j] | ||
| j -= 1 | ||
| k -= 1 | ||
|
|
||
| if j >= 0: | ||
| nums1[: j + 1] = nums2[: j + 1] | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Python特有の追加考慮事項 | ||
|
|
||
| **スライス代入 `nums1[:j+1] = nums2[:j+1]` の内部動作** | ||
|
|
||
| CPython の `list_ass_slice` は `memmove` で連続メモリを一括コピーします。逐次 `while` ループに比べてインタープリタのディスパッチコストを排除でき、残余要素が多いほど効果的です。 | ||
|
|
||
| **`LOAD_FAST` 最適化(競技版)** | ||
|
|
||
| Python のバイトコードにおいて、メソッド内のローカル変数アクセス (`LOAD_FAST`) はグローバル変数アクセス (`LOAD_GLOBAL`) より約2倍高速です。`nums1`, `nums2` は引数として自動的にローカルスコープに入るため、競技版では追加のキャッシュは不要。カウンタ変数 `i`, `j`, `k` も同様です。 | ||
|
|
||
| **Pylance 型安全性** | ||
|
|
||
| `List[int]` を `from typing import List` で明示し、戻り値を `None` と宣言することで Pylance の strict モードでも警告ゼロを維持します。Python 3.9 以降では `list[int]` の組み込み記法も使用可能ですが、LeetCode の CPython 3.11 環境では `from typing import List` が最も互換性の高い記述です。 | ||
98 changes: 98 additions & 0 deletions
98
...de/claude 4.6 sonnet extended/88. Merge Sorted Array/Merge_Sorted_Array_Rust.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| ## 1. 問題の分析 | ||
|
|
||
| **競技プログラミング視点での分析** | ||
|
|
||
| `nums1`の末尾から逆順に埋めていく「後ろからマージ」戦略が最適です。追加アロケーションなしでインプレース処理でき、時間 O(m+n)・空間 O(1) が実現できます。前から埋めると上書きが発生するため、後ろからスキャンするのが核心です。 | ||
|
|
||
| **業務開発視点での分析** | ||
|
|
||
| LeetCode の関数シグネチャは `&mut Vec<i32>` の受け渡しを強制しますが、内部では `while i > 0 && j > 0` のような実行時のガード条件と構造的な順序付けにより、符号なし整数のアンダーフローを防止します。`i32 → usize` の変換は `as usize` で確実に行います。 | ||
|
|
||
| **Rust特有の考慮点** | ||
|
|
||
| - `i32` 引数 `m`, `n` は LeetCode の制約上 `0..=200` に収まるため、`as usize` キャストは安全 | ||
| - ランタイムのガードループ(`while i > 0 && j > 0` や `while j > 0`)によりインデックス計算のパニックを防止 | ||
| - 借用は `&mut Vec<i32>` のスライス操作に集約し、ライフタイムを単純化 | ||
|
|
||
| --- | ||
|
|
||
| ## 2. アルゴリズムアプローチ比較 | ||
|
|
||
| | アプローチ | 時間計算量 | 空間計算量 | Rust実装コスト | 安全性 | 可読性 | 備考 | | ||
| | --------------------------- | ---------------- | ---------- | -------------- | ------ | ------ | ------------------------- | | ||
| | 後ろからマージ(3ポインタ) | O(m+n) | O(1) | 低 | 高 | 高 | 追加アロケーションなし ✅ | | ||
| | 前からコピー後ソート | O((m+n)log(m+n)) | O(m+n) | 低 | 高 | 高 | 標準の `.sort()` 利用可 | | ||
| | 一時バッファにコピー | O(m+n) | O(m) | 低 | 高 | 中 | Vec への clone が発生 | | ||
|
|
||
| --- | ||
|
|
||
| ## 3. 選択したアルゴリズムと理由 | ||
|
|
||
| - **選択**: 後ろからの 3 ポインタマージ | ||
| - **理由**: O(m+n) の時間・O(1) の追加空間。末尾から書き込むことで`nums1`の有効領域を上書きせずマージできる。Rustの所有権モデルと完全に親和的(`split_at_mut` 不要、単純なインデックスアクセス)。 | ||
| - **最適化ポイント**: `usize` 算術のみでスタック完結、ヒープアロケーションゼロ、ループ本体は比較1回+代入1回のみ | ||
|
|
||
| --- | ||
|
|
||
| 以下に図解でアルゴリズムの動作を示します: | ||
|
|
||
|  | ||
|
|
||
| ## 4. 実装コード | ||
|
|
||
| ```rust | ||
| // Runtime 0 ms | ||
| // Beats 100.00% | ||
| // Memory 2.29 MB | ||
| // Beats 25.52% | ||
| impl Solution { | ||
| pub fn merge(nums1: &mut Vec<i32>, m: i32, nums2: &mut Vec<i32>, n: i32) { | ||
| // i32 → usize への安全なキャスト(制約: 0 <= m, n <= 200) | ||
| let mut i = m as usize; // nums1 の有効要素末尾(排他) | ||
| let mut j = n as usize; // nums2 の末尾(排他) | ||
| let mut k = (m + n) as usize; // 書き込み位置末尾(排他) | ||
|
|
||
| // 3ポインタを後ろから前へ動かしながらマージ | ||
| // | ||
| // 不変条件: k >= i が常に成立するため nums1 の未処理要素を上書きしない | ||
| // | ||
| // # Complexity | ||
| // - Time: O(m + n) — 各要素をちょうど1回だけ参照・書き込み | ||
| // - Space: O(1) — 追加ヒープアロケーションなし | ||
| while i > 0 && j > 0 { | ||
| k -= 1; | ||
| if nums1[i - 1] >= nums2[j - 1] { | ||
| nums1[k] = nums1[i - 1]; | ||
| i -= 1; | ||
| } else { | ||
| nums1[k] = nums2[j - 1]; | ||
| j -= 1; | ||
| } | ||
| } | ||
|
|
||
| // nums2 の残余要素を nums1 の先頭へコピー | ||
| // (nums1 の残余は既に正しい位置にあるのでコピー不要) | ||
| while j > 0 { | ||
| k -= 1; | ||
| nums1[k] = nums2[j - 1]; | ||
| j -= 1; | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Rust 固有の最適化観点 | ||
|
|
||
| **`usize` 算術によるゼロコスト安全性** | ||
|
|
||
| LeetCode の引数は `i32` ですが、配列インデックスは `usize` が必要です。制約上 `0 <= m, n <= 200` かつ `1 <= m + n <= 200` が保証されるため `as usize` キャストは常に安全。`i -= 1` 等のデクリメントは `i > 0` ガード後にのみ実行されるため、`usize` アンダーフロー(パニック)は構造的に排除されています。 | ||
|
|
||
| **借用規則との親和性** | ||
|
|
||
| `nums1` と `nums2` を同時に `&mut` で保持しますが、それぞれ独立した `Vec` への借用であるため借用チェッカーを通過します。`split_at_mut` 等の特別な操作は不要です。 | ||
|
|
||
| **ループ本体の最小化** | ||
|
|
||
| 比較1回・代入1回・デクリメント1回のみ。イテレータ抽象化より命令型ループが適切なケースで、コンパイラは最適化レベルや実装に依存してインライン展開を適用する可能性があります。 |
102 changes: 102 additions & 0 deletions
102
...ude 4.6 sonnet extended/88. Merge Sorted Array/Merge_Sorted_Array_TypeScript.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| ## 1. 問題の分析 | ||
|
|
||
| **競技プログラミング視点での分析** | ||
|
|
||
| Rustの回答と同様に、後ろからの3ポインタマージが最適解です。TypeScriptでは `number` 型が IEEE 754 倍精度浮動小数点のため整数演算に余分なオーバーヘッドはなく、インデックス操作はV8エンジンがSMI(Small Integer)最適化を適用します。 | ||
|
|
||
| **業務開発視点での分析** | ||
|
|
||
| LeetCode のシグネチャは `void` 返却の破壊的操作ですが、TypeScript の `strict` モードと `readonly` による境界を意識した実装で保守性を担保します。インデックス境界違反は実行時ではなくロジック上で構造的に防止します。 | ||
|
|
||
| **TypeScript特有の考慮点** | ||
|
|
||
| - `number` 型インデックスの減算は `0` ガード後にのみ実行し、負数インデックスアクセスを防止 | ||
| - `as const` は不要(可変配列操作のため) | ||
| - V8 の Packed SMI Arrays 最適化を維持するため、配列の型を混在させない | ||
|
|
||
| --- | ||
|
|
||
| ## 2. アルゴリズムアプローチ比較 | ||
|
|
||
| | アプローチ | 時間計算量 | 空間計算量 | TS実装コスト | 型安全性 | 可読性 | 備考 | | ||
| | --------------------------- | ---------------- | ---------- | ------------ | -------- | ------ | -------------------------- | | ||
| | 後ろからマージ(3ポインタ) | O(m+n) | O(1) | 低 | 高 | 高 | 追加アロケーションなし ✅ | | ||
| | コピー後 `.sort()` | O((m+n)log(m+n)) | O(m+n) | 最低 | 高 | 最高 | 比較関数必須・競技では次善 | | ||
| | 一時バッファにコピー | O(m+n) | O(m) | 低 | 高 | 中 | スプレッド構文でヒープ確保 | | ||
|
|
||
| --- | ||
|
|
||
| ## 3. 選択したアルゴリズムと理由 | ||
|
|
||
| - **選択**: 後ろからの3ポインタマージ | ||
| - **理由**: O(m+n) 時間・O(1) 追加空間。末尾書き込みにより有効要素の上書きが構造的に不可能。TypeScript の `number` 型インデックスは整数として扱われ、V8 の SMI 最適化が全体に適用される | ||
| - **TypeScript特有の最適化ポイント**: 変数を `let` で宣言し型推論に委ねることでコンパイラの最適化ヒントを最大化。`const` で宣言すると再代入不可になるため、カウンタ変数は `let` が適切 | ||
|
|
||
| --- | ||
|
|
||
| ## 4. 実装コード | ||
|
|
||
| ```typescript | ||
| // Runtime 0 ms | ||
| // Beats 100.00% | ||
| // Memory 54.72 MB | ||
| // Beats 93.68% | ||
|
|
||
| /** | ||
| * 2つのソート済み配列を nums1 にインプレースでマージする。 | ||
| * 後ろから走査する3ポインタ法により、追加アロケーションなしで O(m+n) を実現。 | ||
| * | ||
| * @param nums1 - マージ先配列(長さ m+n、末尾 n 要素は 0 で埋められている) | ||
| * @param m - nums1 の有効要素数 | ||
| * @param nums2 - マージ元配列(長さ n) | ||
| * @param n - nums2 の要素数 | ||
| * | ||
| * @complexity Time: O(m + n), Space: O(1) | ||
| * | ||
| * 不変条件: k >= i が常に成立するため nums1 の未処理要素を上書きしない | ||
| * 証明: 各イテレーションで k と (i または j) が同時に 1 減少する。 | ||
| * 初期値 k = m + n - 1, i = m - 1 より k - i = n >= 0 が保持される。 | ||
| */ | ||
| function merge(nums1: number[], m: number, nums2: number[], n: number): void { | ||
| // 各ポインタは「次に参照すべき要素のインデックス」を表す(0-based) | ||
| let i: number = m - 1; // nums1 有効末尾 | ||
| let j: number = n - 1; // nums2 末尾 | ||
| let k: number = m + n - 1; // 書き込み位置末尾 | ||
|
|
||
| // どちらかの配列が空になるまで大きい方を末尾から書き込む | ||
| while (i >= 0 && j >= 0) { | ||
| if (nums1[i]! >= nums2[j]!) { | ||
| nums1[k] = nums1[i]!; | ||
| i--; | ||
| } else { | ||
| nums1[k] = nums2[j]!; | ||
| j--; | ||
| } | ||
| k--; | ||
| } | ||
|
|
||
| // nums2 の残余要素をコピー | ||
| // (nums1 の残余は既に正しい位置にあるため操作不要) | ||
| while (j >= 0) { | ||
| nums1[k] = nums2[j]!; | ||
| j--; | ||
| k--; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## TypeScript固有の最適化観点 | ||
|
|
||
| **V8 エンジンと配列最適化** | ||
|
|
||
| `nums1` は `number[]` として渡されるため、V8 は内部的に `PACKED_SMI_ELEMENTS` または `PACKED_DOUBLE_ELEMENTS` として最適化されます。要素の書き込みを `nums1[k] = value` の単純代入に統一することで、この最適化が維持され `HOLEY_ELEMENTS` への降格を防ぎます。 | ||
|
|
||
| **型安全インデックス管理** | ||
|
|
||
| `i >= 0` / `j >= 0` のガードにより、TypeScript の `strict: true` 環境でも `number` 型のインデックスが負にならないことが実行フロー上保証されます。ただし `noUncheckedIndexedAccess` を有効にした場合、ガードだけでは `number | undefined` のままになるため、`nums1[i]!` のように非 null アサーションを用いるか、`if (i in nums1)` 等で存在チェックを行い型を明示的に狭める必要があります。 | ||
|
|
||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| **`while` vs イテレータ** | ||
|
|
||
| `.reduce()` や `.forEach()` はコールバック関数のクロージャ生成コストが発生します。本問題のようなインプレース操作かつ複数ポインタを連動させるケースでは、命令型 `while` ループが最も直接的で V8 の JIT 最適化が効きやすい選択です。 | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.