leetcode 198. House Robber 、 213. House Robber II 、337. House Robber III 、256. Paint House(lintcode 515) 、265. Paint House II(lintcode 516) 、276. Paint Fence(lintcode 514)
House Robber:不能相邻,求能获得的最大值
House Robber II:不能相邻且第一个和最后一个不能同时取,求能获得的最大值
House Robber III:二叉树下的不能相邻,求能获得的最大值
Paint House:用3种颜色,相邻的房屋不能用同一种颜色,求花费最小
Paint House II:用k种颜色,相邻的房屋不能用同一种颜色,求花费最小
Paint Fence:用k种颜色,相邻的可以用同一种颜色,但不能超过连续的2个,求有多少种可能性
198. House Robber
dp[i]表示当前位置获得最大值,偷当前这个位置,就不能偷前一个位置。所以如果偷当前位置,则dp[i] = dp[i-2] + nums[i-1];如果不偷当前位置,dp[i]就可以前一个相等,即dp[i] = dp[i-1]。
因为要计算i-2,所以初始0位置为0。
- class Solution {
- public:
- int rob(vector<int>& nums) {
- if(nums.empty())
- return ;
- vector<int> dp(nums.size() + );
- dp[] = ;
- dp[] = nums[];
- for(int i = ;i <= nums.size();i++){
- dp[i] = max(dp[i-] + nums[i-],dp[i-]);
- }
- return dp[nums.size()];
- }
- };
https://www.cnblogs.com/lightwindy/p/8648410.html
213. House Robber II
https://www.cnblogs.com/grandyang/p/4518674.html
第一个和最后一个不能同时偷,那就分成两种情况,即偷第一个和偷最后一个分别计算,然后求最大值。
计算的方式类似于House Robber ,不同在于这个题相对于原数组要限制开始和结尾的位置。
如果length为2,会存在开始和结尾相等的情况,这个时候直接返回开始位置的元素就好。所以有如下代码:
if(begin >= end)
return nums[begin];
其实也可以单独写个n == 2的情况进行判断。
length为1理论上也可以用刚才这个进行处理,但是因为begin是从1开始的,会造成越界,所以对length为1进行了单独判断。
rob_core的写法与House Robber 类似,需要注意dp的索引是根据索引来的,相对应的nums的索引也必须进行变化。
- class Solution {
- public:
- int rob(vector<int>& nums) {
- if(nums.empty())
- return ;
- if(nums.size() == )
- return nums[];
- return max(rob_core(nums,,nums.size()-),rob_core(nums,,nums.size()-));
- }
- int rob_core(vector<int>& nums,int begin,int end){
- if(begin >= end)
- return nums[begin];
- int length = end - begin + ;
- vector<int> dp(length + );
- dp[] = ;
- dp[] = nums[begin];
- for(int i = ;i <= length;i++){
- dp[i] = max(dp[i-] + nums[begin + i - ],dp[i-]);
- }
- return dp[length];
- }
- };
337. House Robber III
https://www.cnblogs.com/grandyang/p/5275096.html
修改返回值变成长度为2的vector,0位置代表不使用当前的元素,1位置代表使用当前的元素。
如果使用就是之前left、right不使用加上当前位置的数值。如果不使用,那就是需要获得left、right的最大值,这个最大值可能是left节点使用、也可能是不使用,right同理。(其实这样做的原因是隐含条件所有数值是大于0的,所以必须加上左右的值,只是选择到底加左右的什么值)
注意:left、right的最大值不一定是使用,所以找各自的最大值相加就好。并且left、right使不使用的选择,对当前节点都没有影响,因为当前节点反正都是不使用,所以只需要找各自的最大值。
- class Solution {
- public:
- int rob(TreeNode* root) {
- vector<int> result = robCore(root);
- return max(result[],result[]);
- }
- vector<int> robCore(TreeNode* root){
- if(root == NULL)
- return vector<int> (,);
- vector<int> left = robCore(root->left);
- vector<int> right = robCore(root->right);
- vector<int> result();
- result[] = max(left[],left[]) + max(right[],right[]);
- result[] = left[] + right[] + root->val;
- return result;
- }
- };
256. Paint House
这个题与House Robber不同在于,不仅对相邻的关系进行了约束,还需要求最小值。
dp[i][j]表示使用j这种颜色当前位置的最小值,由于相邻颜色不能相同,所以更新只能来自于前一个位置另外两种颜色的最小值。
最后再在最后一个位置求三种颜色的最小值就好。
- class Solution {
- public:
- /**
- * @param costs: n x 3 cost matrix
- * @return: An integer, the minimum cost to paint all houses
- */
- int minCost(vector<vector<int>> &costs) {
- // write your code here
- if(costs.empty())
- return ;
- if(costs[].empty())
- return ;
- vector<vector<int>> dp(costs.size() + ,vector<int>(,));
- for(int i = ;i <= costs.size();i++){
- dp[i][] = min(dp[i-][],dp[i-][]) + costs[i-][];
- dp[i][] = min(dp[i-][],dp[i-][]) + costs[i-][];
- dp[i][] = min(dp[i-][],dp[i-][]) + costs[i-][];
- }
- int res = min(dp[costs.size()][],min(dp[costs.size()][],dp[costs.size()][]));
- return res;
- }
- };
265. Paint House II
https://www.cnblogs.com/grandyang/p/5322870.html
这个题也可以使用Paint House的方法,但会超时。
当前位置的最小值来自于前一个位置的最小值+当前位置的cost,但是由于不能相同颜色不能相邻,所以如果计算到相同颜色时,就使用第二小的花费进行更新。
min1、min2、last1、last2都是针对的行,min1、min2针对是当前行的最小和第二小,last1、last2针对的是上一行的最小和第二小。
last2 == -1、last1 == -1是在第一行进行更新时做的处理,因为第一行其实没有前一行。
因为每一行都需要计算所有列的最小值,并且min1 、min2必须每行都重新初始化,min1 == -1和min2 == -1是针对第一、第二列的更新。
- class Solution {
- public:
- /**
- * @param costs: n x k cost matrix
- * @return: an integer, the minimum cost to paint all houses
- */
- int minCostII(vector<vector<int>> &costs) {
- // write your code here
- if(costs.empty())
- return ;
- if(costs[].empty())
- return ;
- vector<vector<int>> dp = costs;
- int min1 = -,min2 = -;
- for(int i = ;i < costs.size();i++){
- int last1 = min1,last2 = min2;
- min1 = - ,min2 = -;
- for(int j = ;j < costs[].size();j++){
- if(j == last1)
- dp[i][j] += last2 == - ? : dp[i-][last2];
- else
- dp[i][j] += last1 == - ? : dp[i-][last1];
- if(min1 == - || dp[i][j] < dp[i][min1]){
- min2 = min1;
- min1 = j;
- }
- else if(min2 == - || dp[i][j] < dp[i][min2])
- min2 = j;
- }
- }
- return dp[costs.size() - ][min1];
- }
- };
自己写的另一种写法:
没有将dp一开始初始化为costs。
如果不加括号,就会报错
- class Solution {
- public:
- /**
- * @param costs: n x k cost matrix
- * @return: an integer, the minimum cost to paint all houses
- */
- int minCostII(vector<vector<int>> &costs) {
- // write your code here
- int m = costs.size();
- if(m == )
- return ;
- int n = costs[].size();
- if(n == )
- return ;
- vector<vector<int>> dp(m,vector<int>(n));
- int cur1 = -,cur2 = -;
- for(int i = ;i < m;i++){
- int last1 = cur1,last2 = cur2;
- cur1 = -,cur2 = -;
- for(int j = ;j < n;j++){
- if(j != last1)
- dp[i][j] = costs[i][j] + (last1 == - ? : dp[i-][last1]);
- else if(j == last1)
- dp[i][j] = costs[i][j] + (last2 == - ? : dp[i-][last2]);
- if(cur1 == - || dp[i][j] < dp[i][cur1]){
- cur2 = cur1;
- cur1 = j;
- }
- else if(cur2 == - || dp[i][j] < dp[i][cur2])
- cur2 = j;
- }
- }
- return dp[m-][cur1];
- }
- };
276. Paint Fence
这个题算是斐波那契数列和House Robber的结合。
dp[i]表示当前位置所有的方式。当前位置可以选择与前两个位置不同颜色,也可以选择和前一个位置不同颜色,与前两个位置不同颜色就是dp[i-2] * (k-1),与前一个位置不同颜色就是dp[i-1] * (k-1)。与前一个位置不同颜色保证一定不会出现相邻的情况,与前两个位置不同颜色也保证了相邻的颜色不会超过2。
注意:k为1时,n=1、n=2的个数都是1,要注意这个corner case
- class Solution {
- public:
- /**
- * @param n: non-negative integer, n posts
- * @param k: non-negative integer, k colors
- * @return: an integer, the total number of ways
- */
- int numWays(int n, int k) {
- // write your code here
- if(k <= && n > )
- return ;
- if(n <= )
- return ;
- vector<int> dp(n);
- dp[] = k;
- dp[] = k*k;
- for(int i = ;i < n;i++)
- dp[i] = dp[i-] * (k-) + dp[i-] * (k-);
- return dp[n-];
- }
- };
上面这个代码n == 1的情况没考虑
- class Solution {
- public:
- /**
- * @param n: non-negative integer, n posts
- * @param k: non-negative integer, k colors
- * @return: an integer, the total number of ways
- */
- int numWays(int n, int k) {
- // write your code here
- if(k == && n > )
- return ;
- if(n == )
- return ;
- if(n == )
- return k;
- vector<int> dp(n);
- dp[] = k;
- dp[] = k*k;
- for(int i = ;i < n;i++)
- dp[i] = dp[i-]*(k-) + dp[i-]*(k-);
- return dp[n-];
- }
- };
leetcode 198. House Robber 、 213. House Robber II 、337. House Robber III 、256. Paint House(lintcode 515) 、265. Paint House II(lintcode 516) 、276. Paint Fence(lintcode 514)的更多相关文章
- 198. 213. 337. House Robber -- 不取相邻值的最大值
198. House Robber You are a professional robber planning to rob houses along a street. Each house ha ...
- [LeetCode] 337. House Robber III 打家劫舍 III
The thief has found himself a new place for his thievery again. There is only one entrance to this a ...
- Leetcode 337. House Robber III
337. House Robber III Total Accepted: 18475 Total Submissions: 47725 Difficulty: Medium The thief ha ...
- 337. House Robber III(包含I和II)
198. House Robber You are a professional robber planning to rob houses along a street. Each house ha ...
- [LeetCode] 198. 打家劫舍II ☆☆☆(动态规划)
描述 你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金.这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的.同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的 ...
- LeetCode 198. 打家劫舍(House Robber)LeetCode 213. 打家劫舍 II(House Robber II)
打家劫舍 题目描述 你是一个专业的小偷,计划偷窃沿街的房屋.每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报 ...
- [LeetCode] 198. House Robber 打家劫舍
You are a professional robber planning to rob houses along a street. Each house has a certain amount ...
- LeetCode 198. 打家劫舍(House Robber) 5
198. 打家劫舍 198. House Robber 题目描述 你是一个专业的小偷,计划偷窃沿街的房屋.每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两 ...
- Leetcode 198 House Robber
You are a professional robber planning to rob houses along a street. Each house has a certain amount ...
随机推荐
- HashMap原理探究
一.写随笔的原因:HashMap我们在平时都会用,一般面试题也都会问,借此篇文章分析下HashMap(基于JDK1.8)的源码. 二.具体的内容: 1.简介: HashMap在基于数组+链表来实现的, ...
- Object Pascal异常的种类
- zookeeper+activemq高可用集群搭建
一.准备工作: 准备三台机器:192.168.35.111192.168.35.112192.168.35.113 二.搭建zookeeper 三台机器上均要搭建zookeeper服务// 下载zoo ...
- docker常用命令与容器创建
################docker安装##################### Docker从1.13版本之后采用时间线的方式作为版本号,分为社区版CE和企业版EE. 社区版是免费提供给个 ...
- parfile解决exp时tables过多问题
parfile 一般用于表数据过大.使用导出.导入命令参数过多等场景: 在对oracle数据库使用exp命令导出数据时,如果tables=后面跟的表比较多,就是导致命令行放不下,从而不能导出.百度一把 ...
- kotlin函数式编程入门及图片处理
函数式编程入门: 对于面向对象编程[OOP]和函数式编程[FP] 由于在JAVA8的学习中系统的学习过了,所以这里对其概念就不过多解释了,下面直接用代码来看下在kotlin中函数式编程是如何编写的: ...
- vim快速到行尾
快速到行尾A,或者End键(挨着Home键) 快速到第一行gg 快速到行首Home键,数字键的上面
- 实践:Linux用户、组和密码相关文件被破坏如何恢复系统
我们先看一下用户用户组和密码相关文件: 1 2 3 4 5 6 7 8 9 [root❄centos7 ~]☭ ll /etc/passwd* /etc/shadow* /etc/group* /et ...
- CH5102/SPOJ?? Mobile Service/P4046 [JSOI2010]快递服务[线性dp+卡常]
http://contest-hunter.org:83/contest/0x50%E3%80%8C%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%E3%80%8D%E4%B ...
- cookie的使用以及cookie的跨域名获取
cookie存放容量4k左右,可设置过期时间. 1.cookie的封装使用 //设置cookies function setCookie(name, value) { var Days = 30; v ...