Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
start_new_problem.sh
main.go
go.mod
go.sum
*.go
103 changes: 103 additions & 0 deletions 122BestTimeToBuyAndSellStockII.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
問題: https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/description/

### Step 1
- 購入価格を覚えておき、次の日に株価が下がるなら売って次の日に買う
- 方針はすぐに思いついたが、末尾要素の扱いに手こずった
- テストケース
- [0] -> 0
- [0,0] -> 0
- [0,1] -> 1
- [1,0] -> 0
- [0,1,2,0,2] -> 4
- [1,0,1,0,1] -> 2
- [2,0,2,1,0] -> 2

```Go
func maxProfit(prices []int) int {
purchasedPrice := prices[0]
res := 0
for i := 0; i < len(prices)-1; i++ {
// When to sell
if prices[i] > prices[i+1] {
res += prices[i] - purchasedPrice
purchasedPrice = prices[i+1]
}
}
res += max(0, prices[len(prices)-1]-purchasedPrice)
return res
}
```

### Step 2
#### 2a
- 前日から上がったらその差分を累積していく考え方
- 実装がシンプルになる
- 前日より株価が上がったらすぐ売っているというのがちょっと現実に即さない感じはある

```Go
func maxProfit(prices []int) int {
accumulatedProfit := 0
for i := 1; i < len(prices); i++ {
if prices[i-1] < prices[i] {
accumulatedProfit += prices[i] - prices[i-1]
}
}
return accumulatedProfit
}
```

#### 2b
- 株を持っている状態と持っていない状態それぞれの場合の最良の収支を更新していく方法
- 理解するのにかなり時間がかかった
- profitWithStockがマイナスになる部分の理解に苦しんだ
- 参考
- https://github.com/fhiyo/leetcode/pull/39#pullrequestreview-216579962
- https://github.com/goto-untrapped/Arai60/pull/59/files#diff-c59f6e68b39b5b00cc1d1fd0ff30aa94e7e2a882d9daefdfb73eda1b94fb3e17R53-R54

```
入力: [7,1,5,3,6,4]
-7 -1 -> -1 1 -> 1 3
↗︎ ↓ ↗️ ↓ ↗️
0 -> 0 4 -> 4 7 -> 7

上がprofitWithStock、下がprofitWithoutStock
```

```Go
func maxProfit(prices []int) int {
profitWithStock := -prices[0]
profitWithoutStock := 0
for i := 1; i < len(prices); i++ {
profitWithStock = max(profitWithStock, profitWithoutStock-prices[i])
profitWithoutStock = max(profitWithoutStock, profitWithStock+prices[i])
Comment on lines +71 to +72
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

これでも結果的には問題がないですが、本当は、この2変数は同時に更新したほうが意味としては自然に思います。

profitWithStock (株を持った状態で夜を越すときの持ち金の最大値。)
profitWithoutStock (株を持たない状態で夜を越すときの持ち金の最大値。)

なのだから、「前日、株を持った状態で夜を越すときの持ち金の最大値 + 株を売った利益」としたほうが自然に思います。結果的にはこれでもいいのですが。(それとも自然な解釈がありますでしょうか。)

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

profitWithStock, profitWithoutStock = max(profitWithStock, profitWithoutStock-prices[i]), max(profitWithoutStock, profitWithStock+prices[i])

あるいは

lastProfitWithStock := profitWithStock
profitWithStock = max(profitWithStock, profitWithoutStock-prices[i])
profitWithoutStock = max(profitWithoutStock, lastProfitWithStock+prices[i])

ということですね。たしかに前日の値を元に当日の値を更新した方が自然ですね

}
return profitWithoutStock
}
```

### Step 3

```Go
func maxProfit(prices []int) int {
res := 0

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

個人的には変に省略語を使わずmaxProfitか、resultぐらいがいいと思います
最後まで読まないとresが何かわからないので

(Goの慣習だったらすいません)

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resやresult以外で名前をつけるとしたらmaxProfitかなと思いましたが、関数名と被るので避けました
Goの慣習については、スタイルガイドに

Function and method names should not use a Get or get prefix, unless the underlying concept uses the word “get” (e.g. an HTTP GET). Prefer starting the name with the noun directly, for example use Counts over GetCounts.

とあるので関数名をgetMaxProfit、変数名をmaxProfitにするのも微妙かなと思いました。
関数名をcomputeMaxProfit、変数名をmaxProfitあるいはaccumulatedProfitにするのも一つの選択肢かなと思います

for i := 1; i < len(prices); i++ {
if prices[i-1] < prices[i] {
res += prices[i] - prices[i-1]
}
}
return res
}
```

### CS
- Rust
- なんで人気なんだろうと気になった

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

仕事で使うんですが、コンパイラがかなり賢くて関数型言語っぽい型計算ができたりします

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C/C++と比べて型推論に任せられる場面が多いということですか?(RustはC/C++と比較されることが多いと感じたので引き合いに出してみました)

- C/C++に比べてメモリの管理がしやすい
- ガベージコレクションの代わりにオーナーシップという手法を用いている
- 組み込みシステム開発などの低レイヤーでよく使われる
- 参考: https://github.blog/developer-skills/programming-languages-and-frameworks/why-rust-is-the-most-admired-language-among-developers/
- トップダウン vs ボトムアップ
- ソフトウェア工学における設計戦略
- トップダウン: 全体を決めてから詳細を決める
- ボトムアップ: 個々の部品を作り、それらを集積して全体を作る
- 参考: https://ja.wikipedia.org/wiki/%E3%83%88%E3%83%83%E3%83%97%E3%83%80%E3%82%A6%E3%83%B3%E8%A8%AD%E8%A8%88%E3%81%A8%E3%83%9C%E3%83%88%E3%83%A0%E3%82%A2%E3%83%83%E3%83%97%E8%A8%AD%E8%A8%88