Add removeDuplicates function for sorted array#11
Conversation
Implement removeDuplicates function to handle duplicates in a sorted array.
There was a problem hiding this comment.
問題の概要を把握しましたので、評価を行います。
📊 総合評価:2点 / 10点
✅ 良い点
- 問題の方向性の理解: 重複をカウントする必要があることは理解されています。
- 配列を使った追跡の試み:
arrを使って同じ値の出現を追跡しようとしています。 - 異なる値の検出:
nums[i] != nums[i + 1]で値の切り替わりを検出しようとしています。
❌ 改善が必要な点
致命的な問題
-
未完成のコード:
kの値が更新されていない(常に0を返す)if len(arr) > 2 { }の中身が空- 最後の要素が処理されない(
i < len(nums) - 1のため)
-
問題要件の未達成:
- In-place操作が必要なのに、追加の配列
arrを使用 - 元の配列
numsを変更していない - O(1)の空間計算量が要求されているのに、O(n)の追加メモリを使用
- In-place操作が必要なのに、追加の配列
-
ロジックの問題:
- 重複を2つまで許可するロジックが実装されていない
- 値が変わるたびに
arrをリセットしているが、その情報をnumsに反映していない
-
バウンダリの問題:
- 配列の最後の要素を処理していない
🏆 最適解との比較
あなたのアプローチ(未完成)
// 追加配列を使用(In-place要件を満たさない)
// kが更新されない
// 最後の要素が処理されない最適解
func removeDuplicates(nums []int) int {
if len(nums) <= 2 {
return len(nums)
}
k := 2 // 最初の2要素は常に保持
for i := 2; i < len(nums); i++ {
// 現在の要素が、2つ前の書き込み位置の要素と異なれば追加
if nums[i] != nums[k-2] {
nums[k] = nums[i]
k++
}
}
return k
}核心的な違い:
- 最適解のキーアイデア: 現在の要素を
nums[k-2]と比較することで、自動的に「最大2回まで」を保証 - In-place操作: 追加メモリを使わず、元の配列内で操作
- シンプルさ: カウンター変数や一時配列が不要
⏱️ 計算量の比較
| 項目 | あなたのコード | 最適解 |
|---|---|---|
| 時間計算量 | O(n) (理論上) | O(n) |
| 空間計算量 | ❌ O(n) | ✅ O(1) |
| In-place要件 | ❌ 未達成 | ✅ 達成 |
| 正しい結果 | ❌ 常に0を返す | ✅ 正しい |
🔧 あなたのコードの具体的な改善
ステップ1: 基本的な修正(まだ不十分)
func removeDuplicates(nums []int) int {
k := 0
count := 1 // 現在の値の出現回数
for i := 0; i < len(nums); i++ {
if i == 0 || nums[i] != nums[i-1] {
// 新しい値が出現
count = 1
nums[k] = nums[i]
k++
} else if count < 2 {
// 同じ値の2回目まで許可
count++
nums[k] = nums[i]
k++
}
// count >= 2 の場合はスキップ
}
return k
}ステップ2: より洗練された解法
func removeDuplicates(nums []int) int {
if len(nums) <= 2 {
return len(nums)
}
k := 2
for i := 2; i < len(nums); i++ {
// 2つ前と比較することで、自動的に「最大2回」を保証
if nums[i] != nums[k-2] {
nums[k] = nums[i]
k++
}
}
return k
}ステップ3: 汎用的な解法(最大n回まで対応)
func removeDuplicates(nums []int) int {
return removeDuplicatesN(nums, 2)
}
func removeDuplicatesN(nums []int, maxCount int) int {
if len(nums) <= maxCount {
return len(nums)
}
k := maxCount
for i := maxCount; i < len(nums); i++ {
if nums[i] != nums[k-maxCount] {
nums[k] = nums[i]
k++
}
}
return k
}📚 学習ポイント
1. In-place アルゴリズムの理解
In-place = 元の配列を直接変更し、追加のメモリをO(1)しか使わない
❌ 新しい配列を作成
✅ 元の配列内で要素を移動
2. Two-Pointer テクニック
読み取りポインタ(i): 配列を順次走査
書き込みポインタ(k): 有効な要素を配置する位置
3. 「k-2との比較」の巧妙さ
nums[i] != nums[k-2] をチェックすることで:
- nums[k-2] = A
- nums[k-1] = A (可能性あり)
- nums[k] = A にしようとしている
→ 3回目のAになるので拒否される!
この比較だけで「最大2回」が自動的に保証される
4. 配列のインデックス処理
❌ i < len(nums) - 1 → 最後の要素を見逃す
✅ i < len(nums) → 全要素を処理
5. 問題を一般化する思考
- 「最大2回」→「最大k回」に拡張できる
nums[k-2]→nums[k-maxCount]に一般化
📝 まとめ
現状の課題
あなたのコードは未完成で、以下の重大な問題があります:
- ❌ コードが動作しない(kが常に0)
- ❌ In-place要件を満たしていない
- ❌ 最後の要素を処理していない
- ❌ 問題の本質的な要件を満たしていない
根本的な問題
問題を正しく理解できていない可能性があります:
- In-place操作の意味(追加配列は不可)
- Two-Pointerパターンの適用方法
- 「k-n との比較」による回数制限の巧妙なアプローチ
改善のための具体的なステップ
ステップ1: 前の問題(Remove Duplicates I)を完全に理解する
// まずこれを完璧にマスター
func removeDuplicates(nums []int) int {
k := 1
for i := 1; i < len(nums); i++ {
if nums[i] != nums[i-1] {
nums[k] = nums[i]
k++
}
}
return k
}ステップ2: 「最大2回」版を理解する
// k-2 との比較がキーポイント
func removeDuplicates(nums []int) int {
if len(nums) <= 2 {
return len(nums)
}
k := 2
for i := 2; i < len(nums); i++ {
if nums[i] != nums[k-2] {
nums[k] = nums[i]
k++
}
}
return k
}ステップ3: なぜ k-2 と比較するのかを図で理解する
[1,1,1,2,2,3] の処理過程:
初期状態: k=2
[1,1,1,2,2,3]
^
k
i=2: nums[2]=1, nums[k-2]=nums[0]=1 → 同じなのでスキップ
i=3: nums[3]=2, nums[k-2]=nums[0]=1 → 異なる!
nums[k]=2, k++ → [1,1,2,2,2,3], k=3
i=4: nums[4]=2, nums[k-2]=nums[1]=1 → 異なる!
nums[k]=2, k++ → [1,1,2,2,2,3], k=4
i=5: nums[5]=3, nums[k-2]=nums[2]=2 → 異なる!
nums[k]=3, k++ → [1,1,2,2,3,3], k=5
結果: [1,1,2,2,3,_], k=5
次のアクション
- 📖 In-place アルゴリズムの概念を再学習
- 🎯 Two-Pointer パターンの基礎問題を解く
- 💡 LeetCode 26(Remove Duplicates I)を完璧にする
- 🚀 その後、この問題(LeetCode 80)に再挑戦
頑張ってください! 基礎をしっかり固めれば、必ず解けるようになります。🌟
| } | ||
| } | ||
|
|
||
| return k |
There was a problem hiding this comment.
変数kは初期化されているものの、ループ内で更新されていません。常に0が返されるため、関数が正しい結果を返しません。kは処理された有効な要素数を追跡し、適切にインクリメントする必要があります。
| if len(arr) > 2 { | ||
| } |
There was a problem hiding this comment.
条件分岐の中身が空です。len(arr) > 2の場合、配列に要素を追加しない処理が必要ですが、現在は何も実装されていません。この条件でarrへの追加をスキップするか、または配列の長さを制限するロジックを実装する必要があります。
| var arr []int | ||
| k := 0 | ||
|
|
||
| for i := 0; i < len(nums) - 1; i++ { |
There was a problem hiding this comment.
ループがlen(nums) - 1で終了するため、配列の最後の要素が処理されません。これにより、最後の要素が結果に含まれない可能性があります。ループ条件をi < len(nums)に変更するか、ループ後に最後の要素を別途処理する必要があります。
| @@ -0,0 +1,17 @@ | |||
| func removeDuplicates(nums []int) int { | |||
| var arr []int | |||
There was a problem hiding this comment.
補助配列arrを使用していますが、この問題はin-placeで解くべき問題です。LeetCode 80の要件では、追加のO(n)空間を使わずに元の配列を直接変更する必要があります。ツーポインタ手法を使用して、空間計算量をO(1)に改善することを推奨します。
|
|
||
| for i := 0; i < len(nums) - 1; i++ { | ||
| if nums[i] != nums[i + 1] { | ||
| arr = []int{} |
There was a problem hiding this comment.
ループ内でarrを新しい空のスライスで再初期化していますが、これは以前に割り当てられたメモリを無駄にします。arr = arr[:0]を使用してスライスの長さをリセットする方が効率的です。ただし、この問題はin-placeで解くべきなので、補助配列自体を使わないアプローチが望ましいです。
Status
Wrong Answer