From f75031db1ce70a80900f93c76db0bce267a8e762 Mon Sep 17 00:00:00 2001 From: Ryo Oshima Date: Tue, 10 Jun 2025 02:10:52 +0900 Subject: [PATCH] 198. House Robber --- 198. House Robber/solution1_1.java | 40 +++++++++++++++++++++++++++ 198. House Robber/solution1_2.java | 32 ++++++++++++++++++++++ 198. House Robber/solution1_3.java | 35 ++++++++++++++++++++++++ 198. House Robber/solution2_1.java | 35 ++++++++++++++++++++++++ 198. House Robber/solution2_2.java | 43 ++++++++++++++++++++++++++++++ 5 files changed, 185 insertions(+) create mode 100644 198. House Robber/solution1_1.java create mode 100644 198. House Robber/solution1_2.java create mode 100644 198. House Robber/solution1_3.java create mode 100644 198. House Robber/solution2_1.java create mode 100644 198. House Robber/solution2_2.java diff --git a/198. House Robber/solution1_1.java b/198. House Robber/solution1_1.java new file mode 100644 index 0000000..6feb820 --- /dev/null +++ b/198. House Robber/solution1_1.java @@ -0,0 +1,40 @@ +/* + * ・概要 + * 自力解法 + * 最初に各要素についてとるとらないを考えて2^nになるなと思った。 + * i番目の家でrobするかどうかを考えると、2個前までの最大値+現在の家の合計 or 1個前の最大値(現在の家はとらない)の大きい方をとればいいのだと考えDPで実装。 + * dp[i]: i番目まででの最高Rob + * dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]) + * 実装はできてあってるんだけど、1個前の最大値については、1個前が使われてない場合もあるのになんでnums[i]を一律つかわないでいいんだろう、あまり腹落ちしない + * ↓ + * solution1_3まで実装して気づいたが、solution1_3を思いつく→改良する→solution1_1の解法を思いつくが思考として自然だと感じた。 + * * + * 5分くらいでAC + * + * ・計算量 + * O(n): nはnumsの要素数 + * O(n) + * + * ・その他 + * よくよく考えると、1次元配列で1、2つ前の値しか使わないので変数でいける→空間はO(1)にできそう。 + * もっとわかりやすく考えると、とる、とらないの二次元配列にして、最大をとったほうが直感的かも。 + * + */ +public class solution1_1 { + public int rob(int[] nums) { + if (nums.length == 0) { + return 0; + } else if (nums.length == 1) { + return nums[0]; + } else if (nums.length == 2) { + return Math.max(nums[0], nums[1]); + } + int[] currentMaxSum = new int[nums.length]; + currentMaxSum[0] = nums[0]; + currentMaxSum[1] = Math.max(nums[0], nums[1]); + for (int i = 2; i < nums.length; i++) { + currentMaxSum[i] = Math.max(currentMaxSum[i - 1], currentMaxSum[i - 2] + nums[i]); + } + return currentMaxSum[nums.length - 1]; + } +} diff --git a/198. House Robber/solution1_2.java b/198. House Robber/solution1_2.java new file mode 100644 index 0000000..830f34d --- /dev/null +++ b/198. House Robber/solution1_2.java @@ -0,0 +1,32 @@ +/* + * ・概要 + * 自力解法 + * solution1_1の配列使わないバージョン + * + * + * ・計算量 + * O(n): nはnumsの要素数 + * O(1) + * + */ + +public class solution1_2 { + public int rob(int[] nums) { + if (nums.length == 0) { + return 0; + } else if (nums.length == 1) { + return nums[0]; + } else if (nums.length == 2) { + return Math.max(nums[0], nums[1]); + } + int prevPrevMaxSum = nums[0]; + int prevMaxSum = Math.max(nums[0], nums[1]); + int currentMaxSum = prevMaxSum; + for (int i = 2; i < nums.length; i++) { + currentMaxSum = Math.max(prevMaxSum, prevPrevMaxSum + nums[i]); + prevPrevMaxSum = prevMaxSum; + prevMaxSum = currentMaxSum; + } + return currentMaxSum; + } +} diff --git a/198. House Robber/solution1_3.java b/198. House Robber/solution1_3.java new file mode 100644 index 0000000..229c89c --- /dev/null +++ b/198. House Robber/solution1_3.java @@ -0,0 +1,35 @@ +/* + * ・概要 + * 自力解法 + * solution1_1でコメントにも書いた、より直感的な動的計画法バージョン + * dp[i][j]: j=0のときは、i番目をつかうときの最大合計数、j=1のときは、i番目を使わないときの最大合計数 + * dp[i][0] = dp[i-1][1] + nums[i] : i-1は使えないので + * dp[i][1] = Max(dp[i - 1][0], dp[i - 1][1]) : iは使わないので、i-1番目までの最大をとる + * 個人的にはこっちのが素直 + * 例:[1,2,4,3]の場合、i = 0:[[1,0]] i = 1:[[1,0],[2,1]], i = 2:[[1,0], [2,1], [4,2]], i = 3:[[1,0], [2,1], [4,2], [3,4]] + * ここまできて、あっdp[i][1]ってdp[i-1][0]と同じやん!じゃあ1次元配列に省略できるね + * dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]) : solution1_1の解法だ!!!!!!! + * + * ・計算量 + * O(n): nはnumsの要素数 + * O(n) + * + */ + +public class solution1_3 { + public int rob(int[] nums) { + if (nums.length == 0) { + return 0; + } + int[][] currentMaxSum = new int[nums.length][2]; + currentMaxSum[0][0] = nums[0]; + currentMaxSum[0][1] = 0; + int maxSum = Math.max(currentMaxSum[0][0], currentMaxSum[0][1]); + for (int i = 1; i < nums.length; i++) { + currentMaxSum[i][0] = currentMaxSum[i - 1][1] + nums[i]; + currentMaxSum[i][1] = Math.max(currentMaxSum[i - 1][0], currentMaxSum[i - 1][1]); + maxSum = Math.max(maxSum, Math.max(currentMaxSum[i][0], currentMaxSum[i][1])); + } + return maxSum; + } +} diff --git a/198. House Robber/solution2_1.java b/198. House Robber/solution2_1.java new file mode 100644 index 0000000..afb369b --- /dev/null +++ b/198. House Robber/solution2_1.java @@ -0,0 +1,35 @@ +/* + * 他の人の解法 + * https://github.com/Fuminiton/LeetCode/pull/35/files + * だいたい同じ流れ + * 読めば読むほどsolution1_1でdp + * https://github.com/Fuminiton/LeetCode/pull/35/files#r2059511752 + * 確かに自分のもprevPrevは変えたいと思っていた + * + * おもに変数名の変更 + * https://github.com/olsen-blue/Arai60/pull/35/files + * メモ化再帰でもできそうなのでやってみる + */ + +public class solution2_1 { + public int rob(int[] nums) { + if (nums.length == 0) { + return 0; + } + if (nums.length == 1) { + return nums[0]; + } else if (nums.length == 2) { + return Math.max(nums[0], nums[1]); + } + int maxSumBeforeTwo = nums[0]; + int maxSumBeforeOne = Math.max(nums[0], nums[1]); + int currentMaxSum = Math.max(maxSumBeforeOne, maxSumBeforeTwo); + for (int i = 2; i < nums.length; i++) { + currentMaxSum = Math.max(maxSumBeforeOne, maxSumBeforeTwo + nums[i]); + maxSumBeforeTwo = maxSumBeforeOne; + maxSumBeforeOne = currentMaxSum; + } + + return currentMaxSum; + } +} diff --git a/198. House Robber/solution2_2.java b/198. House Robber/solution2_2.java new file mode 100644 index 0000000..36bdeb8 --- /dev/null +++ b/198. House Robber/solution2_2.java @@ -0,0 +1,43 @@ +/* + * https://github.com/olsen-blue/Arai60/pull/35/files + * メモ化再帰でもできそうなのでやってみる + * 考え方としては、1つ前と2つ前の最大値+現在の値のおおきいほうをとっていくも + * 上記では再帰の基底状態のindex == 1をやることで、memo[0]を最初に定義しなくてもよくしている。 + * + * ・計算量 + * O(n): nはnumsの要素数 + * O(n) + * + * + */ + +public class solution2_2 { + public int rob(int[] nums) { + int[] memo = new int[nums.length]; + Arrays.fill(memo, -1); + memo[0] = nums[0]; + robHelper(nums, memo, nums.length - 1); + int maxSum = 0; + for (int i = 0; i < nums.length; i++) { + maxSum = Math.max(maxSum, memo[i]); + } + return maxSum; + } + + private int robHelper(int[] nums, int[] memo, int currentIndex) { + if (currentIndex < 0) { + return 0; + } + if (currentIndex == 0) { + return memo[0]; + } + if (memo[currentIndex] != -1) { + return memo[currentIndex]; + } + memo[currentIndex] = + Math.max( + robHelper(nums, memo, currentIndex - 2) + nums[currentIndex], + robHelper(nums, memo, currentIndex - 1)); + return memo[currentIndex]; + } +}