-
Notifications
You must be signed in to change notification settings - Fork 0
Add removeDuplicates function for sorted array #10
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
Add removeDuplicates function for sorted array #10
Conversation
Implement function to remove duplicates from sorted array.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
問題内容を確認しました。それでは、あなたの解答を詳しく評価いたします。
📊 総合評価:8.5点 / 10点
✅ 良い点
- 正しいアルゴリズム: Two-pointer手法を正しく実装しており、問題の要件を満たしています。
- 適切なエッジケース処理: 空配列のチェック(
len(nums) == 0)を最初に行っています。 - In-place操作: 追加のメモリを使わず、元の配列を直接変更しています。
- 読みやすいコード: 変数名が明確で、ロジックが理解しやすい構造になっています。
- 正しい返り値: ユニークな要素の個数
kを正しく返しています。
⚠️ 改善が必要な点
-
不要なエッジケースチェック: 問題の制約条件に
1 <= nums.lengthとあるため、空配列のチェックは不要です(ただし、防御的プログラミングとしては有効)。 -
微細な非効率性:
len(nums) - 1をループ内で毎回評価しています(Go言語のコンパイラが最適化する可能性はありますが)。 -
より直感的なアプローチの余地: 現在のコードは正しいですが、「次の異なる要素を見つけたら配置する」という考え方よりも、「現在の要素が前の要素と異なれば配置する」という考え方の方がより自然です。
🏆 最適解との比較
あなたのアプローチ
// 「次の要素が現在の要素と異なる」をチェック
if nums[i] != nums[i + 1] {
nums[k] = nums[i + 1]
k++
}より標準的なアプローチ
// 「現在の要素が前の要素と異なる」をチェック
for i := 1; i < len(nums); i++ {
if nums[i] != nums[i - 1] {
nums[k] = nums[i]
k++
}
}違い:
- あなたのコード:
iとi+1を比較(前向き比較) - 標準的なコード:
iとi-1を比較(後ろ向き比較)
両方とも正解ですが、標準的なアプローチの方が「現在処理している要素」に焦点を当てているため、より直感的です。
⏱️ 計算量の比較
| 項目 | あなたのコード | 最適解 |
|---|---|---|
| 時間計算量 | O(n) | O(n) |
| 空間計算量 | O(1) | O(1) |
結論: 計算量は最適です!どちらも配列を一度だけ走査し、追加メモリを使用していません。
🔧 あなたのコードの具体的な改善
改善版1: より標準的なアプローチ
func removeDuplicates(nums []int) int {
if len(nums) == 0 {
return 0
}
k := 1
for i := 1; i < len(nums); i++ {
if nums[i] != nums[i-1] {
nums[k] = nums[i]
k++
}
}
return k
}改善版2: よりシンプル(エッジケース省略)
func removeDuplicates(nums []int) int {
if len(nums) <= 1 {
return len(nums)
}
k := 1
for i := 1; i < len(nums); i++ {
if nums[i] != nums[i-1] {
nums[k] = nums[i]
k++
}
}
return k
}改善版3: 最もシンプル(制約条件を信頼)
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
}📚 学習ポイント
1. Two-Pointer テクニック
このアルゴリズムはTwo-Pointerパターンの典型例です:
- 読み取りポインタ (
i): 配列を順次走査 - 書き込みポインタ (
k): ユニークな要素を配置する位置
2. In-place アルゴリズム
追加のメモリを使わずに配列を変更する技術は、空間計算量を最適化する重要なテクニックです。
3. ソート済み配列の特性
ソート済み配列では、重複要素は必ず隣接しているため、O(n)の一度の走査で重複を検出できます。
4. エッジケースの判断
- 問題の制約条件を確認し、必要なエッジケース処理を判断する
- 過剰な防御的プログラミングは可読性を下げることもある
5. 前向き vs 後ろ向き比較
- 前向き (
nums[i] != nums[i+1]): 次を見る - 後ろ向き (
nums[i] != nums[i-1]): 前を見る
どちらも有効ですが、「現在処理中の要素」に焦点を当てる後ろ向き比較の方が直感的です。
📝 まとめ
あなたの解答は非常に優れています。アルゴリズムの本質を理解し、正しく実装できています。
強み:
- ✅ 正しいTwo-Pointerアプローチ
- ✅ 最適な時間・空間計算量
- ✅ 読みやすいコード
さらなる向上のために:
- 🔄 標準的なパターン(後ろ向き比較)にも慣れる
- 📋 問題の制約条件を活用し、不要なチェックを減らす
- 💡 同じ問題に対する複数のアプローチを学ぶ
このレベルの理解があれば、類似の配列操作問題(例: Remove Element, Move Zeros)にも応用できます。引き続き頑張ってください! 🚀
| for i := 0; i < len(nums) - 1; i++ { | ||
| if nums[i] != nums[i + 1] { |
Copilot
AI
Oct 29, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
より効率的なアプローチとして、iとi+1を比較するのではなく、kとの比較を行う方法があります。これにより、ループの範囲もlen(nums)全体に拡張でき、ロジックがよりシンプルになります。
推奨解法:
k := 1
for i := 1; i < len(nums); i++ {
if nums[i] != nums[k-1] {
nums[k] = nums[i]
k++
}
}メリット:
- ✅ インデックス計算(
i+1)が不要になり、可読性が向上 - ✅ ループ範囲が
0からlen(nums)-1ではなく1からlen(nums)-1となり、意図がより明確
Status
Accepted
Runtime
0 ms
Memory
6.24 MB
Time Taken
9 m 46 s