Skip to content

Create Paint Fence.md#33

Open
irohafternoon wants to merge 1 commit intomainfrom
Paint-Fecne
Open

Create Paint Fence.md#33
irohafternoon wants to merge 1 commit intomainfrom
Paint-Fecne

Conversation

@irohafternoon
Copy link
Copy Markdown
Owner

This Problem
Paint Fence
Next Problem
Longest Increasing Subsequence

問題文

You are painting a fence of n posts with k different colors. You must paint the posts following these rules:

Every post must be painted exactly one color.
There cannot be three or more consecutive posts with the same color.
Given the two integers n and k, return the number of ways you can paint the fence.

Example 1:
Input: n = 3, k = 2
Output: 6
Explanation: All the possibilities are shown.
Note that painting all the posts red or all the posts green is invalid because there cannot be three posts in a row with the same color.

Example 2:
Input: n = 1, k = 1
Output: 1

Example 3:
Input: n = 7, k = 2
Output: 42

Constraints:

1 <= n <= 50
1 <= k <= 10^5
The testcases are generated such that the answer is in the range [0, 2^31 - 1] for the given n and k.

問題文
```
You are painting a fence of n posts with k different colors. You must paint the posts following these rules:

Every post must be painted exactly one color.
There cannot be three or more consecutive posts with the same color.
Given the two integers n and k, return the number of ways you can paint the fence.

Example 1:
Input: n = 3, k = 2
Output: 6
Explanation: All the possibilities are shown.
Note that painting all the posts red or all the posts green is invalid because there cannot be three posts in a row with the same color.

Example 2:
Input: n = 1, k = 1
Output: 1

Example 3:
Input: n = 7, k = 2
Output: 42

Constraints:

1 <= n <= 50
1 <= k <= 10^5
The testcases are generated such that the answer is in the range [0, 2^31 - 1] for the given n and k.
```

#### STEP1以外の手法と感想
- DPはメモ化再帰と類似する(既に分かっている情報を記録しておいてそれを利用することで計算量を削減できる)という話を聞いたことがあるが、これを往々するイメージがなかった。ただ、1次元DP的な発想がないとこの手法はできない。
- メモ化再帰としてはmapを作ってメモを更新していく方法があるが、pythonのrlu_cacheのようなデータ構造を作成して使う方法もあるようだ
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

lru: least recently used です。

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.

ありがとうございます。
意味を思い出して間違えないようにします

- DPはメモ化再帰と類似する(既に分かっている情報を記録しておいてそれを利用することで計算量を削減できる)という話を聞いたことがあるが、これを往々するイメージがなかった。ただ、1次元DP的な発想がないとこの手法はできない。
- メモ化再帰としてはmapを作ってメモを更新していく方法があるが、pythonのrlu_cacheのようなデータ構造を作成して使う方法もあるようだ
- rlu_cacheは実装が大変そうなので2周目の宿題にする
- メモ化しないと2^nぐらいの計算量になるので n = 50が上限だと、メモ化は必須
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

これは 1.6^n くらいになります。

robHelper(100) と呼ぶと、robHelper(99) と robHelper(98) が呼ばれて、再帰的に木ができあがりますね。一番下の葉は robHelper(0) と robHelper(1) です。
robHelper(0) と robHelper(1) は、かかった計算コストの請求書を呼び出した人たちに提出します。呼び出した人たちは請求書をホチキスで止めて呼び出し元に送ります。
最後、請求書の束ができあがりますね。請求書は何枚あって、ホチキスは何回止められましたか。
https://discord.com/channels/1084280443945353267/1322513618217996338/1343221128096780420

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.

ありがとうございます
hroc135/leetcode#33 (comment)
こちらで理解しました。丁度この関数の計算量(請求書の数)がフィボナッチ数列の第N項になるので、黄金比を使って1.6^Nのオーダーになるということですね。
ホッチキスの数は、いわゆる「トーナメントにおける総試合数」と同じで、請求書の数 - 1になるということですね

std::vector<int> paint_ways(n);
paint_ways[0] = k;
paint_ways[1] = k * k;
for (int fence_index = 2; fence_index < n; fence_index++) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

個人的にはループ内の処理が3行くらいなら、単にiでループした方が理解しやすいと思います。逆に、ループの中身が長いあるいは複数あるような状況では、処理を追う際に迷子にならないように修飾語をつけたindex等の命名にします。

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.

ありがとうございます。indexも1つで、コードも短いのでiで良い気がしてきました。

int paint_ways_of_same_color = 0;
int paint_ways_of_different_color = k;
for (int fence_index = 1; fence_index < n; fence_index++) {
int temp = paint_ways_of_different_color;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

好みの範囲だと思いますが、187-191は読み解きにくかったです。i番目のフェンスを1つ前と同じ色で塗るか、違う色で塗るか、i番目のフェンスの塗り方の総計、1つ前のフェンスの塗り方の総計、2つ前のフェンスの塗り方の総計を使って書いた方が意図が伝わる気がします。

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.

ありがとうございます。共通因数で括ってしまいましたが、おっしゃる通り足し算にした方が意味がとりやすいですね

class Solution {
  public:
    int countWays(int n, int k) {
        if (n == 0 || k == 0) {
            return 0;
        }
        int paint_ways_of_same_color = 0;
        int paint_ways_of_different_color = k;
        for (int fence_index = 1; fence_index < n; fence_index++) {
            int temp = paint_ways_of_different_color;
            paint_ways_of_different_color = (paint_ways_of_same_color) * (k - 1)
                                            + (paint_ways_of_different_color) * (k - 1);
            paint_ways_of_same_color = temp;
        }
        return paint_ways_of_same_color + paint_ways_of_different_color;
    }
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants