1.题目描述
你是一个经验丰富的小偷,准备偷沿湖的一排房间,每个房间都存有一定的现金,为了防止被发现,你不能偷相邻的两家,即,如果偷了第一家,就不能再偷第二家,如果偷了第二家,那么就不能偷第一家和第三家。沿湖的房间组成一个闭合的圆形,即第一个房间和最后一个房间视为相邻。
给定一个长度为n的整数数组nums,数组中的元素表示每个房间存有的现金数额,请你计算在不被发现的前提下最多的偷窃金额。
数据范围:数组长度满足 1≤n≤2×105 1≤n≤2×105 ,数组中每个值满足 1≤nums[i]≤5000 1≤nums[i]≤5000
示例1
输入:
[1,2,3,4]返回值:
6说明:
最优方案是偷第 2 4 个房间示例2
输入:
[1,3,6]返回值:
6说明:
由于 1 和 3 是相邻的,因此最优方案是偷第 3 个房间
2.解题思路
因为最后一个房间与第一个房间为相邻房间,整个数组成为了一个环形数组,而我们能否偷一个房间的规则是由它的邻居是否被偷决定的,所以我们需要把这个环形数组拆开,转化成两个非环形数组的子问题。
我们需要考虑:
第1个房间如果被偷了,那么最后一个房间就不用考虑了,所以,我们在[0,n-2]这个区间计算一次所能获得的最大金额;
第一个房间如果没有被偷,最后一个房间我们就可以偷,所以我们在[1,n-1]这个区间再计算一次所能获得的最大金额,这两者之间的较大值即为最终所能获得的最大金额。
3.代码实现
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param nums int整型一维数组
* @return int整型
*/
public int rob (int[] nums) {
// write code here
int n = nums.length;
//为了拆分环形数组,分两种情况
//如果从第0间开始,最后一间一定不能偷,则就是[0,n-2]的范围内的打家劫舍(一)
//如果从第1间开始,最后一间可以偷,则就是[1,n-1]范围内的打家劫舍(一)
return Math.max(getMax(Arrays.copyOfRange(nums,0,n-1)),getMax(Arrays.copyOfRange(nums,1,n)));
}
public int getMax(int[] nums) {
int n = nums.length;
int[][] dp = new int[n][2];
dp[0][0] = nums[0];
for(int i = 1; i < n; i++) {
dp[i][0] = dp[i-1][1] + nums[i];
dp[i][1] = Math.max(dp[i-1][0],dp[i-1][1]);
}
return Math.max(dp[n-1][0],dp[n-1][1]);
}
}