-
Notifications
You must be signed in to change notification settings - Fork 0
198. House Robber #38
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,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]; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
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. 単独の if 文と if-else if が混ざっているのがやや違和感がありました。いずれも比較される対象が nums.length のため、統一した書き方で書いたほうが、読んでいて混乱が少なくなると思いました。 else if で十分だと思います。 |
||
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; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
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 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]; | ||
} | ||
} |
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.
私は、これ2変数に分けます。[0], [1] の意味は読み手にとってパズルですよね。