-
Notifications
You must be signed in to change notification settings - Fork 0
solved: 122.Best Time to Buy and Sell Stock II #38
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| // Step1a | ||
| // 目的: 練習のために再帰による実装を行う | ||
|
|
||
| /* | ||
| 問題の理解 | ||
| - 整数配列pricesが与えられる。prices[i]は株価を表している。株の売買を行って得られる最大利益を解として返す。 | ||
| 利益が発生しなければ0を返す。売買するかを決められるので損失がでるような売買は行わない。 | ||
| 制約 | ||
| - 一度に保有できる株式は最大1株のみ | ||
| - 同じ日に複数回の売買は可能 | ||
|
|
||
| 何がわからなかったか | ||
| - 特になし | ||
|
|
||
| 何を考えて解いていたか | ||
| - prices=[7, 1, 5, 3, 6, 4]の時 | ||
| - day=1の時買い、day=2の時売る。 profit=5-1=4 | ||
| - day=3の時買い、day=4の時売る。 profit=6-3=3 | ||
| max_profit=4+3=7 | ||
| - prices=[1, 2, 3, 4, 5]の時 | ||
| - day=0の時買い、day=4の時売る。 profit=5-1=4 | ||
| max_profit=4 | ||
| - prices=[7, 6, 4, 3, 2, 1]の時 | ||
| - どの時点で買っても利益が発生しないので、max_profit=0 | ||
|
|
||
| 再帰関数の設計 | ||
| - 基本ケース | ||
| - 売買対象がなければ0を返す。 | ||
| - 再帰ケース | ||
| - 持っている株よりも売買候補の株が安ければ、所持する株を安い株に更新して日付を一日進めて再帰に入る。 | ||
| - 持っている株を売って利益を計算する。次の日付の売買を行うために再帰に入る。 | ||
| - 計算した利益を全て合算して返す。 | ||
|
|
||
| step1で見積もった空間計算量(スタックオーバーフローしないか) | ||
| 入力の制約 prices.length <= 3 * (10 ^ 4) = 30_000 | ||
| スタックサイズ上限7MBとすると、7 * 1024 * 1024 / 30_000 = 約244Byte となり、1スタックフレームあたり244Byteまでならスタックオーバーフローとならない。 | ||
| 余裕そうなのでstep1a.rsで再帰による実装を練習する。 | ||
| */ | ||
|
|
||
| pub struct Solution {} | ||
| impl Solution { | ||
| pub fn max_profit(prices: Vec<i32>) -> i32 { | ||
| let Some((initial_holding_price, remaining_prices)) = prices.split_first() else { | ||
| return 0; | ||
| }; | ||
|
|
||
| Self::make_max_profit(remaining_prices, 0, *initial_holding_price) | ||
| } | ||
|
|
||
| fn make_max_profit(prices: &[i32], day: usize, holding_price: i32) -> i32 { | ||
| let Some(price) = prices.get(day) else { | ||
| return 0; | ||
| }; | ||
|
|
||
| if *price < holding_price { | ||
| return Self::make_max_profit(prices, day + 1, *price); | ||
| } | ||
|
|
||
| let current_profit = *price - holding_price; | ||
| let future_profits = Self::make_max_profit(prices, day + 1, *price); | ||
|
|
||
| current_profit + future_profits | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
|
|
||
| #[test] | ||
| fn step1a_test() { | ||
| assert_eq!(Solution::max_profit(vec![7, 1, 5, 3, 6, 4]), 7); | ||
| assert_eq!(Solution::max_profit(vec![1, 2, 3, 4, 5]), 4); | ||
| assert_eq!(Solution::max_profit(vec![7, 6, 4, 3, 1]), 0); | ||
|
|
||
| assert_eq!(Solution::max_profit(vec![2, 2, 4, 8]), 6); | ||
| assert_eq!(Solution::max_profit(vec![2, 2, 4, 1]), 2); | ||
|
|
||
| assert_eq!(Solution::max_profit(vec![1, 5]), 4); | ||
| assert_eq!(Solution::max_profit(vec![1]), 0); | ||
| assert_eq!(Solution::max_profit(vec![]), 0); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -12,26 +12,54 @@ | |||||||||||||||||||||||
| // 改善する時に考えたこと | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| /* | ||||||||||||||||||||||||
| 講師陣はどのようなコメントを残すだろうか? | ||||||||||||||||||||||||
| - | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| 他の人のコードを読んで考えたこと | ||||||||||||||||||||||||
| - | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| 他の想定ユースケース | ||||||||||||||||||||||||
| - | ||||||||||||||||||||||||
| - 今回は特に思うところはなかった。 | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| 改善する時に考えたこと | ||||||||||||||||||||||||
| - | ||||||||||||||||||||||||
| - max_profitよりも通算利益っぽいtotal_profitの方が適切だと感じた | ||||||||||||||||||||||||
| - 前回の問題のレビューで提案を受けたsplit_firstによる分割で書いてみた。 | ||||||||||||||||||||||||
| https://github.com/t9a-dev/LeetCode_arai60/pull/37#discussion_r2575562337 | ||||||||||||||||||||||||
| remaining(残りの)という語彙も増えたし、すっきり書けていて良いと思う。 | ||||||||||||||||||||||||
| - price - holding_priceはprofit変数に入れた方が丁寧な気がしたが、一度しか使わないのとtotal_profitに加算していることから過剰かなと思って止めた。 | ||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| pub struct Solution {} | ||||||||||||||||||||||||
| impl Solution {} | ||||||||||||||||||||||||
| impl Solution { | ||||||||||||||||||||||||
| pub fn max_profit(prices: Vec<i32>) -> i32 { | ||||||||||||||||||||||||
| let Some((mut holding_price, remaining_prices)) = prices.split_first() else { | ||||||||||||||||||||||||
| return 0; | ||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||
| let mut total_profit = 0; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| for price in remaining_prices { | ||||||||||||||||||||||||
| if price < holding_price { | ||||||||||||||||||||||||
| holding_price = price; | ||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| total_profit += price - holding_price; | ||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. また、holding_priceという命名にも違和感があります。 |
||||||||||||||||||||||||
| holding_price = price; | ||||||||||||||||||||||||
|
Comment on lines
+35
to
+41
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. holding_priceの更新はif節の成立によらず行うのでわざわざ別々に書かれていることに違和感を持ちました。
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. あと、ここのif分岐をなくして常にprice - holding_priceと0のうち大きい方をtotal_profitに加えると書く方法もあると思います。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
重複しているコードなので違和感を感じるのがソフトウェアエンジニアとしての普通の反応だと思いました。 if holding_price < price {
total_profit += price - holding_price;
}
holding_price = price;
なるほど、こんな感じになると理解しました。 let min_profit = 0;
for price in remaining_prices {
total_profit += min_profit.max(price - holding_price);
holding_price = price;
}There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. すみません、不等号の向き逆でした. ご提案で違和感ないです。(0はハードコードしちゃってもいいかもですが、そちらだとより意図が明確で良いですね。) |
||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| total_profit | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| #[cfg(test)] | ||||||||||||||||||||||||
| mod tests { | ||||||||||||||||||||||||
| use super::*; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| #[test] | ||||||||||||||||||||||||
| fn step2_test() {} | ||||||||||||||||||||||||
| fn step2_test() { | ||||||||||||||||||||||||
| assert_eq!(Solution::max_profit(vec![7, 1, 5, 3, 6, 4]), 7); | ||||||||||||||||||||||||
| assert_eq!(Solution::max_profit(vec![1, 2, 3, 4, 5]), 4); | ||||||||||||||||||||||||
| assert_eq!(Solution::max_profit(vec![7, 6, 4, 3, 1]), 0); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| assert_eq!(Solution::max_profit(vec![2, 2, 4, 8]), 6); | ||||||||||||||||||||||||
| assert_eq!(Solution::max_profit(vec![2, 2, 4, 1]), 2); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| assert_eq!(Solution::max_profit(vec![1, 5]), 4); | ||||||||||||||||||||||||
| assert_eq!(Solution::max_profit(vec![1]), 0); | ||||||||||||||||||||||||
| assert_eq!(Solution::max_profit(vec![]), 0); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
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.
自分がこの書き方するならあえて下のように分けたいですね。