题目描述

题解
// 动态规划
// 跟【Leetcode】198. 打家劫舍 基本上很像,但是根据题意,第一个跟最后一个
// 元素是连起来的。所以如果取最后一个值的时候,第一个值也不能要了,
// 如果要第一个值,那最后一个值也不能要了。
//
// 本题可以拆解为两个【Leetcode】198. 打家劫舍 问题,第一个从左到右打家劫舍,
// 一直遍历到length - 2位置,第二个从右到左打家劫舍,一直遍历到1位置。
// 我们定义subRob,实际上就是把【Leetcode】198. 打家劫舍 包装一下。
//
// 执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
// 内存消耗:35.7 MB, 在所有 Java 提交中击败了87.92%的用户
class Solution {
public int rob(int[] nums) {
int len = nums.length
if (len == 0)
return 0
else if (len == 1)
return nums[0]
int[] dp = new int[len]
int res1 = subRob(nums, dp, 0, 1, len - 2)
int res2 = subRob(nums, dp, len - 1, len - 2, 1)
return Math.max(res1, res2)
}
public int subRob(int[] nums, int[] dp, int start1, int start2, int end) {
dp[start1] = nums[start1]
dp[start2] = Math.max(dp[start1], nums[start2])
if (start1 < end) {
for (int i = start2 + 1
dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1])
}
}
else if (start1 > end) {
for (int i = start2 - 1
dp[i] = Math.max(dp[i + 2] + nums[i], dp[i + 1])
}
}
return dp[end]
}
}
// 简写一下
// 可以不用真的反方向dp,只要一个从0开始dp到倒数第二个,一个从1开始dp倒数
// 到倒数第一个。重新封装subRob,只需要保留从左到右的遍历,
// 注意排查特殊情况,比如[0,0]这种情况,start2根本取不到,会抛出异常,
// 所以在start1初始化之后,我们要验证一下start1和end是不是相等,如果是
// 直接返回dp[end]。
//
// 执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
// 内存消耗:35.6 MB, 在所有 Java 提交中击败了96.11%的用户
class Solution {
public int rob(int[] nums) {
int len = nums.length
if (len == 0)
return 0
else if (len == 1)
return nums[0]
int[] dp = new int[len]
int res1 = subRob(nums, dp, 0, 1, len - 2)
int res2 = subRob(nums, dp, 1, 2, len - 1)
return Math.max(res1, res2)
}
public int subRob(int[] nums, int[] dp, int start1, int start2, int end) {
dp[start1] = nums[start1]
if (start1 == end) return dp[end]
dp[start2] = Math.max(dp[start1], nums[start2])
for (int i = start2 + 1
dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1])
}
return dp[end]
}
}