House Robber 打家劫舍 系列

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

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

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

根据给的例子直观感觉是对奇数和偶数位分别计数累加,最后返回累加奇数和和累加偶数和最大的那个。但是这样做是不对的,比如:2>1>1>2这个数组,最大值是(2,2)的组合,对应的下标是[0,3]并不是奇数组合或者偶数组合。那么我们就要换种思路,这道题没有想象的那么简单。

我们采用动态规划来解答,因为不能盗窃两家连续的店,所以我们定义一个包含两个数字的数组cur_max,cur_max[0]表示上上次偷盗的最优解,cur_max[1]表示上次偷盗的最优解的递归公式如下:

cur_max[1] = max(cur_max[0] + nums[i], cur_max[1]);

即在这次一定偷第i家店铺和这次不偷第i家店中取最大。

一定偷第i家店=偷i-2家店时的最优解+偷这家店的价值(一定包含当前解的局部最优)

不偷第i家店=偷上家店的价值(历史最优)

初始化为:

int cur_max[2] = { nums[0],max(nums[0],nums[1]) };

代码如下:

    int rob(vector& nums) {
	if (nums.size() <= 0) {
		return 0;
	}
    if(nums.size() ==1){
        return nums[0];
    }
	int cur_max[2] = { nums[0],max(nums[0],nums[1]) };
	for (int i = 2; i < nums.size(); i++) {
		int tmp = cur_max[1];
		cur_max[1] = max(cur_max[0] + nums[i], cur_max[1]);
		cur_max[0] = tmp;	
	}
	return cur_max[1];  
    }

House Robber II

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

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

示例 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,2]
输出: 3
解释: 你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。

示例 2:

输入: [1,2,3,1]
输出: 4
解释: 你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。

这道题店家围成一个圈了,规则同样是不能偷两家连续的店铺,这道题可以分解成两个子问题的合集。

偷1~n-1家店的价值和偷2~n家店的价值中选择较大的一个,于是我们把上题中的主函数分解成两个子函数,返回两个子函数的最大值即可。

代码:

int helper(vector& nums,int start,int end){
	if ((end - start) == 0) {
		return nums[start];
	}
	if ((end - start) == 1) {
		return max(nums[start],nums[end]);
	}
	int cur_max[2] = { nums[start],max(nums[start],nums[start+1]) };
	for (int i = start+2; i <= end; i++) {
		int tmp = cur_max[1];
		cur_max[1] = max(cur_max[0] + nums[i], cur_max[1]);
		cur_max[0] = tmp;
	}
	return cur_max[1];
}
int rob(vector& nums) {
	if (nums.size() <= 0) {
		return 0;
	}
	if (nums.size() == 1) {
		return nums[0];
	}
	return max(helper(nums,0,nums.size()-2), helper(nums, 1, nums.size() - 1));
}

这里传入的helper的是下标,所以分别对应[0,nums.size()-1]和[1,nums.size()-1]。

House Robber III

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

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

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

     3
    / \
   2   3
    \   \ 
     3   1

能盗取的最高金额 = 3 + 3 + 1 = 7.

示例 2:

     3
    / \
   4   5
  / \   \ 
 1   3   1

能盗取的最高金额 = 4 + 5 = 9.

小偷都学会上树了。。。出题人也是煞费苦心。。。这道题还是用动态规划,但是动态规划的方程要有所变化。我们定义子函数返回值为vector m,包含两个数字。定义如下:

m[0]表示不包含当前节点的最大值

m[1]表示包含当前节点的最大值

则递归公式为:

m[0]=max(左子树返回的m)+max(右子树返回的m);
m[1]=左子树返回的m的不包含左节点的值+右子树返回的不包含右节点的值+当前节点的值;

代码如下:

//vector m
//m[0]表示不包含当前节点的最大值
//m[1]表示包含当前节点的最大值
vector robCore(TreeNode* root) {
	vector m;
	if (!root) {
		m.push_back(0);
		m.push_back(0);
		return m;
	}
	vector left_m = robCore(root->left);
	vector right_m = robCore(root->right);
	m.push_back(max(left_m[0], left_m[1])+ max(right_m[0], right_m[1]));
	m.push_back(root->val + left_m[0]+right_m[0]);
	return m;
}
int rob(TreeNode* root) {
	if (!root) {
		return 0;
	}
	vector m= robCore(root);
	return max(m[0],m[1]);
}



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

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

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

你可能感兴趣的:(算法)