Skip to content
Open
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
102 changes: 102 additions & 0 deletions 300. Longest Increasing Subsequence/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
Amazon SDE1のOnline Assessmentを受けてみたが2問目のDynamic Programmingを使うHardレベルの問題が解けなかった...これまで3回Online Assessmentを受けてきたがどれもDP問題で失敗している気がする、、、動的計画法の考え方のコツを掴むために重点的にやっていきたい。

## step1:
まず1つのポストを色塗りする方法はk種類ある。なので3連続した色を塗ってはならないという制約なしで考えてみると、k種類の絵の具でn個のポストを塗る方法はk^n通り存在する。バックトラックで全通りを探索し、1個前と2個前のポストでどんな色で塗られたかを渡していき、もし塗ろうとしている色とそれらが一致している場合はスキップするという手法をとれば制約内で全ての通りを探索できそうである。早速これを実装してみる。色0、色1、、、色k-1として塗っていく。
### code
```Python
class Solution:
def num_ways(self, n: int, k: int) -> int:
num_of_ways = 0
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

こちらのコメントをご参照ください。
h-masder/Arai60#18 (comment)

def _count_ways(i, color_before, color_before_before):
nonlocal num_of_ways
if i == n:
num_of_ways += 1
return
for color in range(k):
if color_before == color_before_before == color:
continue
_count_ways(i + 1, color, color_before)

_count_ways(0, -1, -1)

return num_of_ways
```

この解法はO(k^n)であり、nかkの数が大きいときは避けたい解法である。なので次は動的計画法を用いた解法を考えていきたい。
全くわからなかったのでGeeksForGeeksの解法をみてみる。
まずi個までのポストでの3つ以上同じ色が並ばない塗り方の通りをnum_of_ways[i]と定義する。すると、num_of_ways[i-1]の最後のポストの色と違う色を置く通り(num_of_ways[i-1]*(k-1))と、num_of_ways[i-2]の最後のポストの色と違う色を2つ連続でおく通り(num_of_ways[i-2]*(k-1))を足したものとなる。これをコードにしていく。

```Python
class Solution:
def countWays(self,n,k):
if n == 1:
return k

num_of_ways = [0]*n
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

こちらのコメントをご参照ください。
mt2324/leetcode#2 (comment)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

配列の時だとそのクセが抜けておりました...
開けるように心がけます。

num_of_ways[0] = k
num_of_ways[1] = k * k
for i in range(2, n):
num_of_ways[i] = (k-1) * num_of_ways[i-1] + (k-1) * num_of_ways[i-2]

return num_of_ways[n - 1]
```
空間計算量はO(N), 時間計算量はO(N)である。
他にも解法を見てみたが、prev1, prev2に一個前と二個前の答えを置いておくことで空間計算量をO(1)に抑えることができるものもあった。

```Python
def countWays(n, k):

# base cases
if n == 1:
return k
if n == 2:
return k * k

# Fill value for 1 and 2 fences
prev2 = k
prev1 = k * k

for i in range(3, n + 1):
curr = prev1 * (k - 1) + prev2 * (k - 1)

# update the values
prev2 = prev1
prev1 = curr

return prev1
```

## step2:
個人的には配列にi個目のポストまでの塗り方の答えを入れる方がぱっと見でなんの値を参照してるのかわかりやすいのでこっちでいく。
### code
```python
class Solution:
def countWays(self,n,k):
if n == 1:
return k

num_of_ways = [0]*n
num_of_ways[0] = k
num_of_ways[1] = k * k
for i in range(2, n):
num_of_ways[i] = (k-1) * num_of_ways[i-1] + (k-1) * num_of_ways[i-2]

return num_of_ways[n - 1]
```

## step3:
### code
```python
class Solution:
def countWays(self,n,k):
if n == 1:
return k
num_of_ways = [0] * n
num_of_ways[0] = k
num_of_ways[1] = k * k

for i in range(2, n):
num_of_ways[i] = (k - 1) * num_of_ways[i - 1] + (k - 1) * num_of_ways[i - 2]

return num_of_ways[n - 1]
```