-
Notifications
You must be signed in to change notification settings - Fork 0
Create 20251118.ts #23
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
Create 20251118.ts #23
Conversation
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.
コーディング面接対策:解答評価レポート
総合評価:3点 / 10点
良い点
-
基本的な構造は理解している
- ループで配列を走査する基本的なアプローチは正しい
- 変数の初期化が適切に行われている
-
コードの可読性
- 変数名が分かりやすい(maxProfit, minPrice, totalProfit)
- シンプルな構造でコードが読みやすい
改善が必要な点
1. アルゴリズムの根本的な誤り
あなたのコードには致命的な論理エラーがあります。このコードは正しい結果を返しません。
問題点:
- maxProfitを毎回リセットしていないため、利益の計算が正しく行われない
- 例:prices = [7,1,5,3,6,4]の場合
- i=1: maxProfit=0, minPrice=1, totalProfit=0
- i=2: maxProfit=4, minPrice=1, totalProfit=4
- i=3: maxProfit=4, minPrice=1, totalProfit=8 ← 誤り(正解は4)
- i=4: maxProfit=5, minPrice=1, totalProfit=13 ← 誤り(正解は7)
2. 問題の本質を理解していない
この問題の鍵は「複数回の売買が可能」という点です。最適戦略は:
- 価格が上昇するたびに、その差分を全て利益として加算する
- つまり、prices[i] > prices[i-1]のとき、差分prices[i] - prices[i-1]を加算
最適解との比較
最適解(Greedy Algorithm)
function maxProfit(prices: number[]): number {
let totalProfit = 0;
for (let i = 1; i < prices.length; i++) {
if (prices[i] > prices[i - 1]) {
totalProfit += prices[i] - prices[i - 1];
}
}
return totalProfit;
}なぜこれが最適か:
- 価格が上昇する部分は全て利益として取得できる
- 下降する部分は取引しなければよい
- 「前日に買って今日売る」を繰り返すことで、全ての上昇トレンドを捉える
計算量の比較
| 項目 | あなたのコード | 最適解 |
|---|---|---|
| 時間計算量 | O(n) | O(n) |
| 空間計算量 | O(1) | O(1) |
| 正確性 | ❌ 不正確 | ✅ 正確 |
時間計算量は同じですが、あなたのコードは正しい結果を返さないため、実質的に使用できません。
あなたのコードの具体的な改善
改善版コード
function maxProfit(prices: number[]): number {
let totalProfit = 0;
// 隣接する日の価格差を見て、上昇分を全て加算
for (let i = 1; i < prices.length; i++) {
// 今日の価格が昨日より高ければ、その差分が利益
if (prices[i] > prices[i - 1]) {
totalProfit += prices[i] - prices[i - 1];
}
}
return totalProfit;
}変更点の説明
-
maxProfitとminPrice変数を削除
- これらは「1回だけ売買する」問題(Best Time to Buy and Sell Stock I)で使う変数
- 今回は複数回売買できるため不要
-
隣接要素の比較に変更
- prices[i] > prices[i-1]のときだけ差分を加算
- これで全ての上昇トレンドを捉えられる
-
条件分岐を簡略化
- 正の差分のみ加算することで、自動的に利益のある取引だけを行う
学習ポイント
1. 問題の制約を正確に理解する
- 「複数回売買可能」という条件をアルゴリズムに反映させる
- 異なる問題(Stock I vs Stock II)で異なるアプローチが必要
2. Greedy Algorithmの適用
- この問題はGreedy(貪欲法)で解ける典型例
- 「各ステップで最良の選択をする」→ 上昇する度に利益を取る
3. 具体例でのシミュレーション
prices = [7, 1, 5, 3, 6, 4]
日々の差分:
1-7 = -6 (無視)
5-1 = +4 (加算) → totalProfit = 4
3-5 = -2 (無視)
6-3 = +3 (加算) → totalProfit = 7
4-6 = -2 (無視)
最終利益:7
4. 関連問題との違い
- Stock I(1回のみ売買):最小値と最大値の差を求める
- Stock II(複数回売買):全ての上昇分を加算
- Stock III(最大2回):Dynamic Programming
- Stock IV(最大k回):Dynamic Programming
まとめ
あなたのコードはアルゴリズムの根本的な誤りがあり、正しい結果を返しません。問題の本質である「複数回売買可能」という条件を正しく理解し、Greedy Algorithmで解くべきです。
今後の学習ステップ:
- LeetCodeの「Best Time to Buy and Sell Stock」シリーズ全体を解く
- Greedy Algorithmの基本概念を学習する
- 具体的な例でコードをトレースし、期待値と実際の出力を比較する習慣をつける
- 問題の制約条件(1回のみ vs 複数回)がアルゴリズムにどう影響するか意識する
頑張ってください!この問題を理解できれば、Greedy Algorithmの重要な基礎が身につきます。
隣接する日だけの売買を考えれば良い理由
素晴らしい質問です!これは多くの人が疑問に思う重要なポイントです。
なぜ隣接する日だけで考えればいいのか?
数学的な証明
例を使って説明します。
例:prices = [1, 3, 5]
パターンA:1日目に買って3日目に売る
- 利益 = 5 - 1 = 4
パターンB:隣接する日で取引
- 1日目に買って2日目に売る:3 - 1 = 2
- 2日目に買って3日目に売る:5 - 3 = 2
- 合計利益 = 2 + 2 = 4
結果は同じ!
一般的な証明
離れた日付での取引:
買値:prices[i]
売値:prices[j] (j > i)
利益:prices[j] - prices[i]
これを隣接する日の取引に分解すると:
prices[j] - prices[i]
= (prices[i+1] - prices[i]) + (prices[i+2] - prices[i+1]) + ... + (prices[j] - prices[j-1])
つまり、どんな取引も隣接する日の取引の合計に分解できるのです!
具体例で確認
prices = [7, 1, 5, 3, 6, 4]
問題の例の解き方:
- 2日目(1)に買って3日目(5)に売る:5 - 1 = 4
- 4日目(3)に買って5日目(6)に売る:6 - 3 = 3
- 合計:7
隣接する日で考える:
- 1→5の取引を分解:
- 1→5 = (5-1) = (5-3) + (3-1) = 2 + 2 = 4
- でも、3は下がっているので実際は:(5-1) = 4だけ
- もっとシンプルに:
- 2日目→3日目:5 - 1 = 4(上昇)
- 3日目→4日目:3 - 5 = -2(下降、取引しない)
- 4日目→5日目:6 - 3 = 3(上昇)
- 5日目→6日目:4 - 6 = -2(下降、取引しない)
- 合計:4 + 3 = 7
なぜこのアプローチが最適なのか?
-
上昇部分は全て利益になる
- 隣接する日で上昇していれば、その差分は必ず利益になる
- 下降部分は取引しなければ損失を避けられる
-
取引回数に制限がない
- 同じ日に売買できるので、連続した上昇を細かく分割しても問題ない
- 1→5の取引は、1→3→5と分割しても同じ利益
-
手数料がない
- 実際の株式市場では手数料があるので離れた日の方が有利だが、この問題では手数料がない
- だから細かく分割しても不利にならない
視覚的な理解
価格: [1, 3, 2, 5, 4, 6]
6 ─────────────────●
5 ──────────●
4 ────────────────×─●
3 ───●
2 ──────×
1 ●
上昇部分(利益):
1→3: +2
2→5: +3
4→6: +2
合計: 7
これは以下と同じ:
1で買って6で売る: 6-1=5
でも途中で下がっているので、実際は:
(3-1) + (5-2) + (6-4) = 2+3+2 = 7
まとめ
離れた日の取引 = 隣接する日の取引の合計
なので、アルゴリズムとしては隣接する日だけチェックすれば十分です。これが Greedy Algorithm の美しさです!
あなたの疑問は非常に本質的で、この理解があれば問題を完全にマスターしたと言えます。素晴らしい質問でした!
Status
Wrong Answer
Time Taken
15 m 43 s