-
Notifications
You must be signed in to change notification settings - Fork 0
213. House Robber II #36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| ## 何も見ずに解いてみる | ||
|
|
||
| 最初の家に入ったか入っていないかで場合分けしないといけなさそう。 | ||
|
|
||
| ```cpp | ||
| class Solution { | ||
| public: | ||
| int rob(vector<int>& nums) { | ||
| int prev_max_with_first_broken = 0; | ||
| int current_max_with_first_broken = 0; | ||
| int prev_max_with_first_unbroken = 0; | ||
| int current_max_with_first_unbroken = 0; | ||
| if (nums.size() == 1) { | ||
| return nums[0]; | ||
| } | ||
| for (int i; i < nums.size(); ++i) { | ||
| int num = nums[i]; | ||
| if (i > 0) { | ||
| int next_max_with_first_unbroken = std::max(current_max_with_first_unbroken, prev_max_with_first_unbroken + num); | ||
| prev_max_with_first_unbroken = current_max_with_first_unbroken; | ||
| current_max_with_first_unbroken = next_max_with_first_unbroken; | ||
| } | ||
| if (i < nums.size() - 1) { | ||
| int next_max_with_first_broken = std::max(current_max_with_first_broken, prev_max_with_first_broken + num); | ||
| prev_max_with_first_broken = current_max_with_first_broken; | ||
| current_max_with_first_broken = next_max_with_first_broken; | ||
| } | ||
| } | ||
| return std::max(current_max_with_first_broken, current_max_with_first_unbroken); | ||
| } | ||
| }; | ||
| ``` | ||
|
|
||
| こっちの方がわかりやすいかも。有効な家の入り方は、最初の家に入らない場合と最後の家に入らない場合の二つに分けられる。(任意の隣り合う二つの家でも良いですが) | ||
| https://cpprefjp.github.io/reference/span/span.html | ||
| 書いているときは気づきませんでしたが空の配列が渡された時に`nums.begin() + 1`とか`nums.end() - 1`でバグりそうなので`nums.size() == 0`の時の場合分けが欲しいかもしれませんね。 | ||
|
|
||
| ```cpp | ||
| class Solution { | ||
| public: | ||
| int rob(vector<int>& nums) { | ||
| if (nums.size() == 1) { | ||
| return nums[0]; | ||
| } | ||
| std::span<int> span_without_first(nums.begin() + 1, nums.end()); | ||
| std::span<int> span_without_last(nums.begin(), nums.end() - 1); | ||
| return std::max(rob_line(span_without_last), rob_line(span_without_first)); | ||
| } | ||
| private: | ||
| int rob_line(std::span<int>& nums) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. std::span は軽量な軽量なデータ参照のため、値渡ししてしまってよいと思います。 #include <iostream>
#include <span>
int main()
{
std::span<int> s;
std::cout << sizeof(s) << std::endl;
}
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sizeofでサイズをチェックする方法も参考になります。ありがとうございます。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 補足すると、 Linux で使用される System V AMD64 ABI では 16 バイトまでのデータはレジスター渡しになるようです。 https://azelpg.gitlab.io/azsky2/note/prog/asm64/22_systemv.html
パフォーマンスが重要な場合については、コンパイラーから出力されるアセンブラを確認したり、マイクロベンチマークを取るのが良いと思います。そうでない場合は、ひとまず値渡しで良いと思います。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. なるほど、ありがとうございます!参考になります。 |
||
| int prev_max = 0; | ||
| int current_max = 0; | ||
| for (const int num : nums) { | ||
| int next_max = std::max(current_max, prev_max + num); | ||
| prev_max = current_max; | ||
| current_max = next_max; | ||
| } | ||
| return current_max; | ||
| } | ||
| }; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. std::span は初めて知りました。直接イテレータを渡しても書けそうな気がしたのですが、std::span を介することで vector のように扱えて直感的ということでしょうか?
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. おっしゃる通りイテレーターを二つ渡しても書けると思います。利点もその通りだと思います。 for (const int num : nums) {
...
}が for (it = begin; it < end; ++it) {
int num = *it
...
}のような形になりますね。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. わかりました。ありがとうございます! |
||
| ``` | ||
|
|
||
| ## 他の人のコードを見てみる | ||
|
|
||
| https://github.com/tokuhirat/LeetCode/pull/36/files | ||
| https://github.com/irohafternoon/LeetCode/pull/39/files | ||
| https://github.com/Ryotaro25/leetcode_first60/pull/38/files | ||
|
|
||
| ## 最終コード | ||
|
|
||
| ヘルパー関数をラムダ式で書いてみました。 | ||
| Solutionクラスのprivateに含めるのとどちらが良いでしょうか? | ||
|
|
||
| ```cpp | ||
| class Solution { | ||
| public: | ||
| int rob(std::vector<int>& nums) { | ||
| if (nums.size() == 1) { | ||
| return nums[0]; | ||
| } | ||
| auto rob_linearly = [&nums](int begin, int end) -> int { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ラムダ式は、長くなると、ソースコードを読むにあたり、目線をラムダ関数の前後で大きく動かさなければならなくなる場合があります。このため、読み手を疲れさせる場合があります。個人的には private なクラス関数としたほうが良いと思います。 ただ、イベントハンドラーを大量に書かなければならない場合や、並列計算フレームワークで計算ロジックをネストさせたい場合、キャプチャーを使いたい場合など、場合に応じて使い分けるのが良いと思います。 |
||
| int prev_max = 0; | ||
| int current_max = 0; | ||
| for (int i = begin; i < end; ++i) { | ||
| int next_max = std::max(current_max, prev_max + nums[i]); | ||
| prev_max = current_max; | ||
| current_max = next_max; | ||
| } | ||
| return current_max; | ||
| }; | ||
| return std::max(rob_linearly(0, nums.size() - 1), rob_linearly(1, nums.size())); | ||
| } | ||
| }; | ||
| ``` | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM です。個人的にはこれが一番好きですね。