diff --git a/300. Longest Increasing Subsequence/memo.md b/300. Longest Increasing Subsequence/memo.md new file mode 100644 index 0000000..035fe70 --- /dev/null +++ b/300. Longest Increasing Subsequence/memo.md @@ -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 + 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 + 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] +```