Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
743e57a
docs(leetcode/20): add Valid Parentheses solution documents and React UI
myoshi2891 Aug 8, 2026
d25d0ff
docs(leetcode/14): add Longest Common Prefix solution documents and R…
myoshi2891 Aug 8, 2026
4bd8130
build: auto-generate public directory
myoshi2891 Aug 8, 2026
e793a49
docs(leetcode/20): fix Java Character caching explanation, align Rust…
myoshi2891 Aug 8, 2026
bb7bd2a
docs(leetcode/14): update Go/TS/Python explanations, remove unreachab…
myoshi2891 Aug 8, 2026
0d0def0
Merge branch 'dev-from-macmini' of github.com:myoshi2891/AlgorithmStu…
myoshi2891 Aug 8, 2026
4b29aa4
docs(leetcode/20): fix markdownlint MD031 and clarify non-determinist…
myoshi2891 Aug 8, 2026
74c3986
docs(leetcode/20): use Object.prototype.hasOwnProperty.call in TypeSc…
myoshi2891 Aug 8, 2026
a04d0d9
build: auto-generate public directory
myoshi2891 Aug 8, 2026
d8fe90d
docs(leetcode/21): add Sonnet 5 solutions and documentation (Go, Java…
myoshi2891 Aug 9, 2026
70e7b04
Merge branch 'dev-from-macmini' of github.com:myoshi2891/AlgorithmStu…
myoshi2891 Aug 9, 2026
fcf444f
docs(leetcode-21): update section numbering, heading levels, and dumm…
myoshi2891 Aug 9, 2026
c69a1f2
build: auto-generate public directory
myoshi2891 Aug 9, 2026
279065a
docs(leetcode-21-go): update type safety explanation for Go vs TypeSc…
myoshi2891 Aug 9, 2026
61ad940
docs(leetcode-21-rust): align heap allocation explanations with dummy…
myoshi2891 Aug 9, 2026
4c217fa
Merge branch 'dev-from-macmini' of github.com:myoshi2891/AlgorithmStu…
myoshi2891 Aug 9, 2026
e2f0975
docs(leetcode): add multi-language explanations for LeetCode 21 Merge…
myoshi2891 Aug 10, 2026
a28e5de
docs(leetcode): add multi-language explanations for LeetCode 26 Remov…
myoshi2891 Aug 10, 2026
cf85d8d
build: auto-generate public directory
myoshi2891 Aug 10, 2026
24f98c6
docs(leetcode/26): add Sonnet 5 documentation and React UI for Remove…
myoshi2891 Aug 11, 2026
9a8c169
Merge branch 'dev-from-macmini' of github.com:myoshi2891/AlgorithmStu…
myoshi2891 Aug 11, 2026
e516040
docs: LeetCode 21および26の解説ドキュメントの計算量表記と記述の推敲
myoshi2891 Aug 11, 2026
7578073
build: auto-generate public directory
myoshi2891 Aug 11, 2026
7336434
docs(leetcode-26): update C++, C#, and TS descriptions in README
myoshi2891 Aug 11, 2026
cdf861b
docs(leetcode-26): update variable count and escape analysis in Go doc
myoshi2891 Aug 11, 2026
ffd0040
docs(leetcode-26): update variable count and error handling in Python…
myoshi2891 Aug 11, 2026
0cc3045
Merge branch 'dev-from-macmini' of github.com:myoshi2891/AlgorithmStu…
myoshi2891 Aug 11, 2026
d6721a7
docs(leetcode-21): remove redundant 'suru' verb in Dart, Kotlin, and …
myoshi2891 Aug 11, 2026
7a52c18
build: auto-generate public directory
myoshi2891 Aug 11, 2026
f38599c
docs(algorithm): update enumerate explanation for LeetCode 26 Python doc
myoshi2891 Aug 11, 2026
74c205f
docs(datastructures): fix comment on val parameters and local var reb…
myoshi2891 Aug 11, 2026
b8644b8
Merge branch 'dev-from-macmini' of github.com:myoshi2891/AlgorithmStu…
myoshi2891 Aug 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,028 changes: 1,028 additions & 0 deletions Algorithm/BinarySearch/leetcode/20. Valid Parentheses/claude sonnet 5/README.md

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

600 changes: 600 additions & 0 deletions Algorithm/Other/leetcode/14. Longest Common Prefix/Sonnet 5/README.md

Large diffs are not rendered by default.

1,652 changes: 1,652 additions & 0 deletions Algorithm/Other/leetcode/14. Longest Common Prefix/Sonnet 5/README_react.html

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
# LeetCode解答フォーマット

---

## 1. 問題の分析

> 💡 **初学者向け補足**:この問題は、一言で言うと「すでに並び替え済みの配列から、同じ値が連続している部分をひとつにまとめて、前方に詰め直す問題」です。配列自体を直接書き換える(in-place=その場で操作する)必要がある点がポイントです。

### 競技プログラミング視点での分析

- 配列はすでにソート済みなので、**同じ値は必ず隣り合っている**という性質を利用できます。これにより、余計な探索(例えば全要素同士を比較する)をせず、**配列を1回だけ左から右へなめる(1パス)だけ**で処理が完結します。
- 実行速度を最優先するなら、時間計算量 O(n)(nは配列の要素数)が理論上の最速ラインです。全要素を最低1回は確認する必要があるため、これより速くはなりません。
- メモリ使用量の最小化方針としては、新しい配列やSet(=重複を許さない集合を表すデータ構造)を作らず、**与えられた配列そのものを書き換える**ことで、追加メモリを定数個の変数(インデックス用の整数など)だけに抑えます。これが空間計算量 O(1) を実現する鍵です。

### 業務開発視点での分析

- この問題では境界条件(配列が空、要素が1個だけ、全要素が同じ値、全要素がバラバラ等)を正しく処理できるかが保守性・堅牢性の観点で重要です。
- Swiftでは配列は「値型(`struct`)(=代入時に値そのものがコピーされる型。詳しくは後述)」ですが、この問題のシグネチャは `inout` (イン・アウト。=関数の外にある変数を直接書き換えられるようにする仕組み) を使って参照渡しのように振る舞わせているため、呼び出し元の配列を安全に直接変更できます。
- エラーハンドリングについては、この問題は「`nums.length >= 1`」という制約が保証されているため例外を投げる(`throws`)必要はありませんが、念のため空配列に対しても安全に動くようガード(`guard`)を入れておくと、将来的な仕様変更にも耐えられる堅牢なコードになります。

### Swift特有の考慮点

- **値型(`struct`)と参照型(`class`)の使い分け**:Swiftの`Array`は値型です。Javaの配列やC++の生ポインタ配列のように「複数の変数が同じメモリ領域を指す」ということは基本的に起きません。しかし今回は`inout`を使うことで、まるで参照渡しのように、呼び出し元の配列を直接編集できます。これにより新しい配列をコピーして返す必要がなくなり、メモリ効率が良くなります。
- **ジェネリクス・プロトコル境界**:今回のシグネチャは`Int`型固定ですが、もし汎用化するなら`<T: Comparable>`(=「大小比較ができる型」という制約付きの型パラメータ)を使うことで、`Int`以外の型(`Double`や`String`など)にも対応できる汎用的な実装が可能です。
- **Optionalバインディングによるnull安全性**:今回のアルゴリズムでは配列の添字アクセスのみを使い、`Optional`型(=値があるかもしれないし、ないかもしれないことを表す型。`T?`と書く)は登場しません。ただし、範囲外アクセスによるクラッシュを防ぐため、ループの範囲指定を正確に行う必要があります。

> 📖 **このセクションで登場した用語**
>
> - **in-place(インプレース)**:新しい配列を作らず、与えられた配列そのものを直接書き換える操作方式。
> - **`inout`**:Swiftで、関数の引数を「呼び出し元の変数を直接書き換えられる形」で受け取るためのキーワード。C++の参照渡し(`&`)に近い概念。
> - **値型(`struct`)**:代入時に値そのものがコピーされる型。SwiftのArray・Int・Stringなどが該当。
> - **1パスアルゴリズム**:配列やリストを先頭から末尾まで1回だけ走査して処理を完了させるアルゴリズムのこと。

---

## 2. アルゴリズムアプローチ比較

> 💡 **初学者向け補足**:同じ問題でも解き方は複数あります。それぞれの「速さ(時間計算量)」と「メモリの使いやすさ(空間計算量)」を比べて、この問題の制約(in-place・O(1)空間)に最も適したものを選びます。

| アプローチ | 時間計算量 | 空間計算量 | Swift実装コスト | 型安全性 | 可読性 | 備考 |
| ---------------------------------------- | ---------- | ---------- | --------------- | -------- | ------ | ------------------------------------------------------------ |
| **A. Two-Pointer(低速・高速ポインタ)** | O(n) | O(1) | 低 | 高 | 高 | ソート済みという前提を最大限活用。in-place要件を満たす最適解 |
| B. Setを使った重複除去 | O(n) | O(n) | 低 | 高 | 中 | Setは順序を保証しないため、別途ソートし直す必要があり非効率 |
| C. 新配列にfilterして結果を返す | O(n) | O(n) | 低 | 高 | 高 | シンプルだが「in-place」というこの問題の要件そのものに反する |

> 💡 **Big-O記法の読み方**(初学者向け)
>
> - `O(1)`:入力の大きさに関わらず、常に一定の時間・メモリで済む(最速・最小)
> - `O(n)`:入力が2倍になると、処理も約2倍になる(線形)
> - `O(n²)`:入力が2倍になると、処理は約4倍になる(二重ループに多い、今回は該当なし)

**Swift特有の値型コピーコストについて**:方法B・Cでは新しい`Array`(Setから配列への変換、あるいは`filter`の結果)を生成するため、要素数分のメモリ確保とコピーが発生します。SwiftのArrayはCopy-on-Write(COW。=実際に変更が加えられるまではコピーを作らず、参照を共有し続ける最適化)を採用していますが、それでも「新しい配列を作る」という行為自体はO(n)のメモリ確保を伴います。一方、方法Aは既存の配列を直接上書きするだけなので、この追加コストが一切発生しません。

> 📖 **このセクションで登場した用語**
>
> - **時間計算量**:入力の大きさに対して、処理にかかる手間がどう増えるかの目安。
> - **空間計算量**:処理中に使うメモリ量がどう増えるかの目安。
> - **Copy-on-Write(COW)**:SwiftのArrayなどが採用する最適化。変更が実際に発生するまでコピーを作らない仕組み。

---

## 3. 選択したアルゴリズムと理由

> 💡 **初学者向け補足**:他の方法と比較しながら、なぜ二重ポインタ法を選んだのかを説明します。

- **選択したアプローチ**: A. Two-Pointer(slow / fast の2つのインデックスを使う方法)
- **理由**:
- **計算量的な優位性**:Set(方法B)や新配列生成(方法C)はどちらもO(n)の追加メモリが必要ですが、Two-Pointer法はO(1)の追加メモリ(`slow`という整数変数ひとつ)だけで済みます。**この問題は「in-placeで行うこと」自体が明示的な要件**なので、O(n)空間を使う方法B・Cはそもそも要件を満たしません。
- **Swift環境での型安全性**:`Int`同士の比較演算子`!=`はコンパイル時に型チェックされるため、誤った型同士を比較してしまうミスがそもそも起こり得ません。
- **保守性・可読性の観点**:ループはひとつだけで、条件分岐も「値が変わったかどうか」のシンプルな1行のみです。将来的にコードを読む人にとっても意図が追いやすい構造です。
- **Swift特有の最適化ポイント**:
- `inout`引数を使うことで、配列のコピーを一切発生させずに呼び出し元の配列を直接書き換えられます。
- `guard`文による早期リターンで、空配列という特殊ケース(今回の制約上は起こりませんが、防御的プログラミングとして)を先に弾き、メインロジックのネストを浅く保っています。

> 📖 **このセクションで登場した用語**
>
> - **Two-Pointer(二重ポインタ)法**:配列上で2つの添字(インデックス)を異なる速度・役割で動かしながら処理を進めるアルゴリズムパターン。
> - **防御的プログラミング**:想定外の入力(今回で言えば空配列など)が来ても安全に動作するよう、あらかじめ検証コードを入れておく設計方針。

---

## 4. 実装コード

> 💡 **初学者向け補足**:コード全体を示す前に、大まかな構造(骨格)を示します。
>
> 1. まず配列が空でないかを確認する(空なら結果は0個なのでそのまま`0`を返す)
> 2. 「まだユニークな要素を書き込んでよい位置」を指す`slow`ポインタを用意する
> 3. `fast`ポインタで配列を先頭から末尾まで1つずつなめていき、`slow`が指す値と違う値が見つかるたびに、その値を`slow`の次の位置に書き込む
> 4. 最後に`slow + 1`(=ユニークな要素の個数)を返す

```swift
class Solution {
/// ソート済み配列から重複要素を取り除き、前方にユニークな値だけを詰め直す
/// - Parameter nums: 非減少順(同じ値の連続を含む昇順)にソートされた整数配列。
/// `inout` により、この関数は呼び出し元の配列を直接書き換える。
/// - Returns: 重複を除いたあとのユニークな要素数 k
func removeDuplicates(_ nums: inout [Int]) -> Int {
// 配列が空の場合、ユニークな要素は0個なのでそのまま0を返す。
// (この問題の制約では nums.length >= 1 が保証されているが、
// 防御的プログラミングとして安全側に倒しておく)
guard !nums.isEmpty else {
return 0
}

// slow は「最後に確定したユニークな値」が置かれているインデックス。
// 最初はインデックス0の要素(nums[0])が唯一の確定済みユニーク値なので0から始める。
var slow = 0

// fast はこれから調べていく値を指すインデックス。
// インデックス1から末尾まで、配列を1回だけなめる(1パス)。
for fast in 1..<nums.count {
// 配列はソート済みなので、同じ値は必ず隣接している。
// fast が指す値が、直近の確定済みユニーク値(nums[slow])と異なるなら、
// それは「新しく見つかったユニークな値」ということになる。
if nums[fast] != nums[slow] {
// slow をひとつ進めて「次にユニーク値を書き込む位置」を確保する
slow += 1
// 新しく見つかったユニーク値を、確定済み領域の直後(nums[slow])に書き込む
nums[slow] = nums[fast]
}
// nums[fast] == nums[slow] の場合は「すでに確認済みの値の重複」なので、
// 何もせずに fast だけを次に進める(何もしないことがそのまま「重複を無視する」処理になる)
}

// slow は0始まりのインデックスなので、要素の個数に直すには+1する
return slow + 1
}
}
```

> 💡 **コードの動作トレース**(初学者向け)
>
> 具体例:`nums = [0,0,1,1,1,2,2,3,3,4]` で実際にトレースしてみます。
>
> ```
> 初期状態: nums = [0,0,1,1,1,2,2,3,3,4]、slow = 0
>
> fast=1: nums[1]=0, nums[slow]=nums[0]=0 → 同じ値なので何もしない
> fast=2: nums[2]=1, nums[slow]=nums[0]=0 → 値が違う!
> slow を 1 に進め、nums[1] = nums[2] = 1 を書き込む
> → nums = [0,1,1,1,1,2,2,3,3,4]
> fast=3: nums[3]=1, nums[slow]=nums[1]=1 → 同じ値なので何もしない
> fast=4: nums[4]=1, nums[slow]=nums[1]=1 → 同じ値なので何もしない
> fast=5: nums[5]=2, nums[slow]=nums[1]=1 → 値が違う!
> slow を 2 に進め、nums[2] = nums[5] = 2 を書き込む
> → nums = [0,1,2,1,1,2,2,3,3,4]
> fast=6: nums[6]=2, nums[slow]=nums[2]=2 → 同じ値なので何もしない
> fast=7: nums[7]=3, nums[slow]=nums[2]=2 → 値が違う!
> slow を 3 に進め、nums[3] = nums[7] = 3 を書き込む
> → nums = [0,1,2,3,1,2,2,3,3,4]
> fast=8: nums[8]=3, nums[slow]=nums[3]=3 → 同じ値なので何もしない
> fast=9: nums[9]=4, nums[slow]=nums[3]=3 → 値が違う!
> slow を 4 に進め、nums[4] = nums[9] = 4 を書き込む
> → nums = [0,1,2,3,4,2,2,3,3,4]
>
> ループ終了。 return slow + 1 = 4 + 1 = 5
>
> → k = 5、先頭5要素は [0,1,2,3,4] となり、期待される出力と一致する
> ```
>
> インデックス5以降の値(`[2,2,3,3,4]`の名残)は、問題文の指示どおり「気にしなくてよい部分」としてそのまま残っていますが、これは正解として扱われます(Custom Judgeは先頭k個しか見ないため)。

> 📖 **このセクションで登場した用語**
>
> - **`guard` 文**:条件を満たさない場合に早期リターンする構文。`if`と異なり、`guard`のスコープを抜けたあとは「条件が満たされている」ことがコンパイラにも保証されるため、その後のコードで余計なnilチェックが不要になる。
> - **`1..<nums.count`**:Swiftの範囲演算子(Range Operator)のひとつ。「1以上、`nums.count`未満」を意味する半開区間(=終端を含まない範囲)。終端を含めたい場合は`...`(クローズド・レンジ)を使う。
> - **添字(インデックス)アクセス `nums[i]`**:配列の`i`番目(0始まり)の要素にアクセスする構文。範囲外の`i`を指定すると実行時にクラッシュするため、ループ範囲の指定を正確に行うことが重要。

---

## 補足:計算量まとめ

- **時間計算量**: O(n) — 配列を1回だけ走査するため(n = `nums.count`)
- **空間計算量**: O(1) — 追加で使うメモリは`slow`という整数変数ひとつのみ(入力配列自体は書き換えているだけで、新規のメモリ確保は行っていない)
Loading
Loading