Conversation
|
|
||
| 小田さんのコメントで、自分で実装できるならキャッシュなどのライブラリを使ってもよいとあるので、 | ||
| こういうのは自分で実装できるようにならないといけないんだろうなというところで、自分でキャッシュを実装してみる。 | ||
| まずデコレータをどう作るのかから手間取った。 |
| return ways_to_paint[n] | ||
| ``` | ||
|
|
||
| 結局1つ前と同じ色で塗るか、違う色で塗るかの違いなので、配列ではなく |
There was a problem hiding this comment.
Maximum Product Subarrayの話( https://discord.com/channels/1084280443945353267/1196498607977799853/1358753010670637149 の周辺)を見ていたときも思ったのですが、odaさんは再帰で引き継ぐ最小の条件を特によく考えているような印象があります。(私個人の感覚としては、より純粋数学に近いイメージです。メモリを保持して塗り替えていく・埋めていくというよりは、ある式に従って引き継ぎながら計算をするというような。もちろん、最小の引き継ぎ対象が結果的に配列になるケースもありますが。)
| return count_ways(n) | ||
| ``` | ||
|
|
||
| あと、この関数が2回呼ばれたときどうなるのかついて、 |
There was a problem hiding this comment.
あっていると思います。以下の認識です。
同一インスタンス&num_ways呼び出し:
→ 毎回index_to_waysが初期化されるため前回のメモ化データは保持されない
同一インスタンス&count_ways呼び出し:
→ メモ化がが保持される
異なるインスタンス:
→ メモ化されたデータは共有されない
| return k | ||
| if index == 2: | ||
| return k * k | ||
| index_to_ways[index] = (k-1) * (count_ways(index -1) + count_ways(index - 2)) |
There was a problem hiding this comment.
k-1
index -1
index - 2
- の前後の空白有無がバラバラなので統一した方がいいと思います。
There was a problem hiding this comment.
この辺の意識抜けていました。気を付けます。
| cache = LRU_Cache(maxsize) | ||
| def wrap(*args, **kwargs): | ||
| result = cache.get(args) | ||
| if result is not None: |
There was a problem hiding this comment.
今回の場合は問題ないんですが、結果がNoneになる場合はこの判定が使えないので、一般の場合ではargs in cacheに相当する条件で判定したいですね。(ただ、このcacheがdictではないので、そのための実装が必要になってしまうのと、普通はキャッシュする関数は値を返すことがほとんどだとは思いますが)
|
|
||
|
|
||
| def _lru_cache_wrapper(func, maxsize): | ||
| cache = LRU_Cache(maxsize) |
There was a problem hiding this comment.
このmaxsizeとcapacityの語は統一してもいいかなという気がしました。
|
|
||
| def lru_cache(maxsize=1): | ||
| def decorating_function(func): | ||
| nonlocal maxsize |
There was a problem hiding this comment.
nonlocalがあると若干身構えるなあと思って改善を考えていたのですが、この場合maxsizeのチェックと代入をシンプルに関数定義の上に出すのがよいですか?
こちらでやった方がよい理由はなにかあるでしょうか。
| class LRU_Cache: | ||
| def __init__(self, capacity): | ||
| self.capacity = capacity | ||
| self.size = 0 |
There was a problem hiding this comment.
size == len(self.cache)だと思うので、sizeは保持しないほうがすっきりするかもしれません。
| next_node.prev = node | ||
| self.size += 1 | ||
| self.cache[key] = node | ||
| if self.size > self.capacity: |
There was a problem hiding this comment.
今回は動的にcapacityが変わることはないと思いますが、なんとなくwhile self.size > self.capacity:のほうが良いかなと思いました。
| return ways_to_paint[n] | ||
| ``` | ||
|
|
||
| 結局1つ前と同じ色で塗るか、違う色で塗るかの違いなので、配列ではなく |
There was a problem hiding this comment.
Maximum Product Subarrayの話( https://discord.com/channels/1084280443945353267/1196498607977799853/1358753010670637149 の周辺)を見ていたときも思ったのですが、odaさんは再帰で引き継ぐ最小の条件を特によく考えているような印象があります。(私個人の感覚としては、より純粋数学に近いイメージです。メモリを保持して塗り替えていく・埋めていくというよりは、ある式に従って引き継ぎながら計算をするというような。もちろん、最小の引き継ぎ対象が結果的に配列になるケースもありますが。)
| class Solution: | ||
| @lru_cache(maxsize=None) | ||
| def num_ways(self, n: int, k: int) -> int: | ||
| if n == 0 or k ==0: |
|
|
||
| 2nd | ||
| 1を読みやすくする。 | ||
| cacheして少し効率化した。とはいえrangeの中に3などのハードコードされた値があるのが気持ち的にいやだなあ。 |
There was a problem hiding this comment.
認識されていたら申し訳ないのですが、cacheとlru_cacheは別物です
| ways_to_paint_different_color = (ways_to_paint_same_color + ways_to_paint_different_color) * (k -1) | ||
| ways_to_paint_same_color = temp | ||
| return ways_to_paint_different_color + ways_to_paint_same_color | ||
|
|
There was a problem hiding this comment.
自分はこの解答が好みでした。
直近の2つの状態だけもっていればよいので、dpといえど配列で管理していく必要はないのですよね。
There was a problem hiding this comment.
私はdpテーブルでやってしまっていましたが、自然言語で表現すると、2変数なのがしっくりときますね。
元の問題(有料)
https://leetcode.com/problems/paint-fence/description/
https://www.lintcode.com/problem/514/
Description
There is a fence with n posts, each post can be painted with one of the k colors.
You have to paint all the posts such that no more than two adjacent fence posts have the same color.
Return the total number of ways you can paint the fence.
n and k are non-negative integers.