题目:
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
示例 1:
输入: [1,2,3,1]
输出: 4
解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
示例 2:
输入: [2,7,9,3,1]
输出: 12
解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
偷窃到的最高金额 = 2 + 9 + 1 = 12 。
解题思路:
这题的考点是动态规划。
动态规划一定要找递推公式!!!
1. 对这题来说,对每一家房子,在其前一家房子偷不偷的前提下,有两种可能的情况。
2. 前一家房子被偷了,它就不能再偷了。前一家房子没被偷,它可以被偷也可以选择不偷。
3. 可看出,每一个子问题都依赖于前一个子问题,同时每一个子问题都会产生至少一种情况(之多两种情况)状态转移方程:
dp[0] = num[0] (当i=0时)
dp[1] = max(num[0], num[1]) (当i=1时)
dp[i] = max(num[i] + dp[i - 2], dp[i - 1]) (当i !=0 and i != 1时)
dp[i]表示从0-i户可以打劫到的最大钱数。考虑在i处,我们只需要考虑两种情况,一种是偷了i-1,这时也就不能偷i。另一种是i-1没有偷,我们可以偷i,则有dp[i] = max(dp[i-1],dp[i-2]+nums[i]),第 i 个值为第(i-1)或者(i-2)加(i)的值,比较两者中的最大值。
class Solution(object):
def rob(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if not nums: #输入0个数
return 0
elif len(nums) == 1: #输入1给数时
return nums[0]
else: #输入2个数以上
dp = [0] * len(nums) #定义一个数组,长度和原来的一样
dp[0] = nums[0]
dp[1] = max(nums[0], nums[1])
for i in range(2, len(nums)):
dp[i] = max(nums[i] + dp[i-2], dp[i-1])
return dp[-1] #返回新数组的最后一个元素
以下是Java版本:
读题: 一个数组,不能取连续的两个值,求可得到和的最大值。
知识储备:
动态规划
动规解题的一般思路:
1. 将原问题分解为子问题
把原问题分解为若干个子问题,子问题和原问题形式相同或类似,只不过规模变小了。 子问题的解一旦求出要被保存。
2.确定状态
在用动态规划解题时,我们往往将和子问题相关的各个变量的一组取值,称之为一个“状 态”。一个“状态”对应于一个或多个子问题, 所谓某个“状态”下的“值”,就是这个“状 态”所对应的子问题的解。
3.确定一些初始状态(边界状态)的值
4. 确定状态转移方程
定义出什么是“状态”,以及在该“状态”下的“值”后,就要找出不同的状态之间如何迁移――即如何从一个或多个“值”已知的 “状态”,求出另一个“状态”的“值”(递推公式)。
解题思路:
1. 将原问题分解为子问题——今天偷不偷
2. 确定状态——每间房子可以有两个状态:偷或者不偷
3. 确定一些边界状态——当走到最后一间房子的时候结束
4. 确定状态转移方程——判断偷和不偷这件房子,那个收益大,将收益大的选作最佳方案
public class Solution {
public int rob(int[] nums) {
if (nums == null)
return 0;
int n = nums.length;
if (n == 0)
return 0;
if (n == 1)
return nums[0];
int dp[] = new int[n];
dp[0] = nums[0];
dp[1] = Math.max(nums[0], nums[1]);
for (int i = 2; i < n; i++)
dp[i] = Math.max(dp[i - 2]
+ nums[i], dp[i - 1]);
return dp[n - 1];
}
}
另一种解法:
1. public class Solution {
2. public int rob(int[] nums) {
3. if (nums.length == 0) {
4. return 0;
5. }
6. if (nums.length == 1) {
7. return nums[0];
8. }
9. int now = 0;
10. int last = 0;
11.
12. for (int i=0; i<nums.length; i++) {
13. int temp = last;
14. last = now;
15. now = Math.max(now,nums[i]+temp);
16. }
17. return now;
18. }
19. }