题目描述:
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。
示例:
输入:nums = [2,3,2]
输出:3
解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。
解题思路:
首先考虑最简单的情况。如果只有一间房屋,则偷窃该房屋,可以偷窃到最高总金额。如果只有两间房屋,则由于两间房屋相邻,不能同时偷窃,只能偷窃其中的一间房屋,因此选择其中金额较高的房屋进行偷窃,可以偷窃到最高总金额。
注意到当房屋数量不超过两间时,最多只能偷窃一间房屋,因此不需要考虑首尾相连的问题。如果房屋数量大于两间,就必须考虑首尾相连的问题,第一间房屋和最后一间房屋不能同时偷窃。
如何才能保证第一间房屋和最后一间房屋不同时偷窃呢?如果偷窃了第一间房屋,则不能偷窃最后一间房屋,因此偷窃房屋的范围是第一间房屋到最后第二间房屋;如果偷窃了最后一间房屋,则不能偷窃第一间房屋,因此偷窃房屋的范围是第二间房屋到最后一间房屋。
假设数组 nums n u m s \textit{nums}nums numsnums 的长度为 n n n。如果不偷窃最后一间房屋,则偷窃房屋的下标范围是 [ 0 , n − 2 ] [0, n-2] [0,n−2] ;如果不偷窃第一间房屋,则偷窃房屋的下标范围是 [ 1 , n − 1 ] [1, n-1] [1,n−1]。在确定偷窃房屋的下标范围之后,即可用第 198 198 198题的方法解决。对于两段下标范围分别计算可以偷窃到的最高总金额,其中的最大值即为在 n n n间房屋中可以偷窃到的最高总金额。
假设偷窃房屋的下标范围是
[
start
,
end
]
[\textit{start},\textit{end } ]
[start,end ],用
dp
\textit{dp}
dp 表示在下标范围
[
start
]
[\textit{start} ]
[start]内可以偷窃到的最高总金额,那么就有如下的状态转移方程:
d
p
[
i
]
=
m
a
x
(
d
p
[
i
−
2
]
+
n
u
m
s
[
i
]
,
d
p
[
i
−
1
]
)
dp[i]=max(dp[i−2]+nums[i],dp[i−1])
dp[i]=max(dp[i−2]+nums[i],dp[i−1])
边界条件为:
{
d
p
[
s
t
a
r
t
]
=
n
u
m
s
[
s
t
a
r
t
]
只
有
一
间
房
屋
,
则
偷
窃
该
房
屋
d
p
[
s
t
a
r
t
+
1
]
=
m
a
x
(
n
u
m
s
[
s
t
a
r
t
]
,
n
u
m
s
[
s
t
a
r
t
+
1
]
)
只
有
两
间
房
屋
,
偷
窃
其
中
金
额
较
高
的
房
屋
\begin{cases}dp[start]=nums[start]&只有一间房屋,则偷窃该房屋\\dp[start+1]=max(nums[start],nums[start+1])&只有两间房屋,偷窃其中金额较高的房屋\end{cases}
{dp[start]=nums[start]dp[start+1]=max(nums[start],nums[start+1])只有一间房屋,则偷窃该房屋只有两间房屋,偷窃其中金额较高的房屋
计算得到
dp
[
end
]
\textit{dp}[\textit{end } ]
dp[end ] 即为下标范围
[
start
,
end
]
[\textit{start},\textit{end }]
[start,end ]内可以偷窃到的最高总金额。
分别取
(
start
,
end
)
=
(
0
,
n
−
2
)
(\textit{start},\textit{end})=(0,n-2)
(start,end)=(0,n−2)和
(
start
,
end
)
=
(
1
,
n
−
1
)
(
s
t
a
r
t
,
e
n
d
)
和
(
1
,
n
−
1
)
(\textit{start},\textit{end})=(1,n-1)(start,end) 和(1,n−1)
(start,end)=(1,n−1)(start,end)和(1,n−1)(进行计算,取两个
dp
[
end
]
\textit{dp}[\textit{end}]
dp[end]中的最大值,即可得到最终结果。
根据上述思路,可以得到时间复杂度 O ( n ) O(n) O(n)) 和空间复杂度 O ( n ) O(n) O(n) 的实现。考虑到每间房屋的最高总金额只和该房屋的前两间房屋的最高总金额相关,因此可以使用滚动数组,在每个时刻只需要存储前两间房屋的最高总金额,将空间复杂度降到 O ( 1 ) O(1) O(1)。
java代码:
class Solution {
public int rob(int[] nums) {
int length = nums.length;
if (length == 1) {
return nums[0];
} else if (length == 2) {
return Math.max(nums[0], nums[1]);
}
return Math.max(robRange(nums, 0, length - 2), robRange(nums, 1, length - 1));
}
public int robRange(int[] nums, int start, int end) {
int first = nums[start], second = Math.max(nums[start], nums[start + 1]);
for (int i = start + 2; i <= end; i++) {
int temp = second;
second = Math.max(first + nums[i], second);
first = temp;
}
return second;
}
}