From a862a55347889882f045435cf481d943830ffbe1 Mon Sep 17 00:00:00 2001 From: potrue <126231160+potrue@users.noreply.github.com> Date: Tue, 5 Aug 2025 18:09:57 +0900 Subject: [PATCH] 213. House Robber II MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 問題文: https://leetcode.com/problems/house-robber-ii/description/ --- 213/213.md | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 213/213.md diff --git a/213/213.md b/213/213.md new file mode 100644 index 0000000..2d9674e --- /dev/null +++ b/213/213.md @@ -0,0 +1,94 @@ +## 何も見ずに解いてみる + +最初の家に入ったか入っていないかで場合分けしないといけなさそう。 + +```cpp +class Solution { +public: + int rob(vector& 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& nums) { + if (nums.size() == 1) { + return nums[0]; + } + std::span span_without_first(nums.begin() + 1, nums.end()); + std::span 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& nums) { + 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; + } +}; +``` + +## 他の人のコードを見てみる + +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& nums) { + if (nums.size() == 1) { + return nums[0]; + } + auto rob_linearly = [&nums](int begin, int end) -> int { + 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())); + } +}; +```