From 96b2ac363c753b8dcdd3d216e4021707f71066dc Mon Sep 17 00:00:00 2001 From: Ryohei Sato <130881456+Satorien@users.noreply.github.com> Date: Sat, 14 Jun 2025 12:58:40 +0900 Subject: [PATCH] Create 276. Paint Fence.md --- Python3/276. Paint Fence.md | 122 ++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 Python3/276. Paint Fence.md diff --git a/Python3/276. Paint Fence.md b/Python3/276. Paint Fence.md new file mode 100644 index 0000000..eb08bf2 --- /dev/null +++ b/Python3/276. Paint Fence.md @@ -0,0 +1,122 @@ +## Step 1. Initial Solution + +- 初めは制約を気にせずに全ての出現をカウントする方法で実装したがTLEになったので修正 + - O(k^n)なので最大10^1500となり、明らかに不可能 +- 数学的に一つ前の状態からの遷移を考えて以下のように実装 + +```python +class Solution: + def countWays(self, n: int, k: int) -> int: + nonconsecutive = k + consecutive = 0 + for i in range(1, n): + temp = nonconsecutive + nonconsecutive = (k - 1) * (nonconsecutive + consecutive) + consecutive = temp + return consecutive + nonconsecutive +``` + +### Complexity Analysis + +- 時間計算量:O(n) +- 空間計算量:O(1) + +## Step 2. Alternatives + +- nonconsecutive, consecutiveとかではなく、一個前, 更にその前という意味で捉えている人が多そう + - https://github.com/ryoooooory/LeetCode/pull/33/files#diff-5f9ade2f5113d8c983ce290c7d633764f0878ef32ad9d23c1b924860ca38bf43R29 +- 他の選択肢の幅としては上の理解を踏まえるとリストや辞書型にそのインデックスまでの方法を保持しておくものがある +- 再帰的に解く方法もある + - その際、@cacheで2回以上使う出力を保持する方法がある + - 注意点として、countWaysが複数回呼ばれる場合やインスタンスによってキャッシュが使えるかという問題がある + - 基本的には使う関数の上で良いが、複数インスタンス間で共有したい場合はメソッドとして定義せずに外部で関数として定義するのが良いかもしれないという話 + - https://github.com/olsen-blue/Arai60/pull/30/files#r1957966512 +- 行列の累乗で求めることもできるらしい + - 累乗は繰り返し二乗法によりlog nで求められる、とのこと + - 使うかはさておき面白い知識だと思った + - https://github.com/tokuhirat/LeetCode/pull/30/files#r2126104372 +- あとはlru_cacheが話題に上っているので実装してみる + - 基本的にはHashMapでキャッシュした値にアクセスし、最近アクセスしていないものを消せるようにすることが目的 + - https://leetcode.com/problems/lru-cache/ + - を元にしてgetとputが外部から呼び出される前提で実装 + - https://github.com/olsen-blue/Arai60/pull/30/files#diff-50f7b6331a7f8355594f718601d9bd00080e614a343f52dd67abdc08da922ebaR76 + - 凡その流れは分かったのでそのうち復習する + +```python +class Node: + def __init__(self, key: int, val: int): + self.key = key + self.val = val + self.previous = None + self.next = None + +class LRUCache: + def __init__(self, capacity: int): + self.capacity = capacity + self.cache = {} + self.sentinel = Node(-1, -1) + self.sentinel.previous = self.sentinel + self.sentinel.next = self.sentinel + self.size = 0 + + def get(self, key: int) -> int: + if key not in self.cache: + return -1 + node = self.cache[key] + self.remove(key) + self.add(key, node.val) + return node.val + + def put(self, key: int, val: int) -> None: + if key in self.cache: + self.remove(key) + if key not in self.cache and self.size == self.capacity: + self.remove(self.sentinel.previous.key) + self.add(key, val) + + def remove(self, key: int) -> None: + node = self.cache[key] + node.previous.next = node.next + node.next.previous = node.previous + del self.cache[key] + self.size -= 1 + + def add(self, key: int, val:int) -> None: + node = Node(key, val) + self.cache[key] = node + if self.sentinel.previous == self.sentinel: + self.sentinel.previous = node + node.previous = self.sentinel + node.next = self.sentinel.next + node.next.previous = node + self.sentinel.next = node + self.size += 1 +``` + +## Step 3. Final Solution + +- 上も悪くはないが、下のStep1のやり方の方が良さそう + +```python +class Solution: + def countWays(self, n: int, k: int) -> int: + ways_to_index: dict[int, int] = {} + ways_to_index[1] = k + ways_to_index[2] = k*k + for i in range(3, n + 1): + ways_to_index[i] = \ + (k - 1) * (ways_to_index[i-1] + ways_to_index[i-2]) + return ways_to_index[n] +``` + +```python +class Solution: + def countWays(self, n: int, k: int) -> int: + end_same = k + end_dif = 0 + for i in range(1, n): + temp = end_same + end_same = (k - 1) * (end_same + end_dif) + end_dif = temp + return end_same + end_dif +```