leetcode #198 打家劫舍 | 刷题之路第二站——动态规划类问题

题号 198

题目描述

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

示例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 。

 

解题思路一——暴力法、伪动态规划【借助了动态规划的思路,但是未能推出来递推公式】

使用数组 dp[ i ] 表示:如果小偷偷窃第 i 间房的现金,可以偷窃到的最高金额。

显然,dp[ 0 ] = nums[ 0 ],dp[ 1 ] = nums[ 1 ]。

令 j = i - 2,当 j >=0 时,进行如下循环:

(1)如果 dp[ j ] > myMax,则 myMax = dp[ j ];

(2)j = j - 2;

dp[ i ] = myMax + nums[ i ]

最后从数组 dp 中选取最大值就是该问题的答案。

代码如下:

class Solution {
public:
	int rob(vector& nums) {
		int len = nums.size();
		if (len == 0) return 0;
		if (len == 1) return nums[0];
		vector dp(len);
		dp[0] = nums[0];
		dp[1] = nums[1];
		int myMax = 0;
		for (int i = 2; i < len; i++) {
			for (int j = i - 2; j >= 0; j -= 2) {
				if (dp[j] > myMax)
					myMax = dp[j];
			}
			dp[i] = myMax + nums[i];
		}
		return *max_element(dp.begin(), dp.end());
	}
};

时间复杂度:O(n^2)

空间复杂度:O(n)

 

解题思路二——动态规划

使用数组 dp[ i ] 表示:截止到第 i 间房间共可偷窃的最高总金额

注意:第 i 间房间可能进入,也可能不进入

对于第 n 个房间而言:

如果我们选择进入该房间,由于不能同时进入相邻的房间,则 dp[ i ] = dp[ i - 2] + nums[ i ];

如果我们未进入该房间,则 dp[ i ] = dp[ i - 1 ];

所以,递推公式为:dp[ i ] = max( dp[ i - 2 ] + nums[ i ],dp[ i - 1 ]) 。

问题的底为:

当没有房间时,直接返回 0 ;

当只有一间房间时,则肯定是进入该房间,所以 dp[ 0 ] = nums[ 0 ];

当有两间房间时,进入现金金额多的那间房间,所以 dp[ 1 ] = max( nums[ 0 ], nums[ 1 ]) 。

代码如下:

class Solution {
public:
	int rob(vector& nums) {
		int len = nums.size();
		if (len == 0) return 0;
		if (len == 1) return nums[0];
		vector dp(len);
		dp[0] = nums[0];
		dp[1] = max(nums[0], nums[1]);
		for (int i = 2; i < len; i++) {
			dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]);
		}
		return dp[len - 1];
	}
};

时间复杂度:O( n )

空间复杂度:O( n )

你可能感兴趣的:(算法设计与分析,动态规划,leetcode,算法,c++)