Leecode---动态规划---打家劫舍 / 乘积最大子数组

在这里插入图片描述
动态规划法
思路
(1)状态定义:dp[i]代表前i家能偷盗的最大金额
(2)状态初始化:如果只有一家,只能偷这家dp[0]=nums[0];如果有两家,因为是连通的,所以,只能偷较富的dp[i]=max(nums[1],nums[0])
(3)状态转移:如果大于等于3家,转移方程为:dp[i]=max(dp[i-1],dp[i-2]+nums[i])

class Solution
{
public:
	int rob(vector<int>& nums)
	{
		int n = nums.size();
		vector<int> dp;
		dp.resize(n);
		if(n==1) return nums[0];
		else if(n==2) return max(nums[0],nums[1]);
		else
		{
			// 状态初始化
			dp[0] = nums[0];
			dp[1] = max(nums[0], nums[1]);
			for(int i = 2; i<n; i++)
			{
				// 状态转移
				dp[i] = max(dp[i-1], dp[i-2] + nums[i]);
			}
			return dp[n-1];
		}
	}
};

解法二、奇偶性
思路:
设置两个变量,sumOdd 和 sumEven 分别对数组的奇数和偶数元素求和。
遍历数组,索引为奇数时,将元素加到奇数和,并与偶数和比较更新成max。
偶数和同理。
返回时进行最后一次更新max。

class solution
{
public:
	int rob(vector<int>& nums)
	{
		int sumOdd = 0;		// 奇数和
		int sumEven = 0;	// 偶数和
		for(int i = 0; i<nums.size(); i++)
		{
			if(i%2 == 0)
			{
				sumEven += nums[i];
				sumEven = max(sumEven,sumOdd);
			}
			else
			{
				sumOdd += nums[i];
				sumOdd = max(sumEven,sumOdd);
			}
		}
		return max(sumOdd,sumEven);
	}
};

在这里插入图片描述

动态规划法
思路
保存当前的最大值和最小值
所有最大值中最大的那个就是结果
状态定义
dpmin[i] = 以i下标结尾的最小乘积
dpmax[i] = 以i下标结尾的最大乘积;
状态初始化

状态转移方程
1、nums[i] = 0
dpmin[i] = dpmax[i] = 0
2、nums[i] > 0
dpmax[i] = max(dpmax[i - 1] * nums[i], nums[i])
dpmin[i] = min(dpmin[i - 1] * nums[i], nums[i])
正数 * 较大值->较大值,正数 * 较小值->较小值
nums[i]要么续上之前的min或max,要么不续上,自己就是当前最大值或者最小值
3、nums[i] < 0
dpmax[i] = max(dpmin[i-1] * nums[i], nums[i])
dpmin[i] = min(dpmax[i-1] * nums[i], nums[i])
负数 * 较大值->较小值,负数 * 较小值->较大值
nums[i]要么续上之前的min或max,要么不续上,自己就是当前最大值或者最小值。

result = max(dpmax[i])

class Solution
{
public:
	int maxProduct(vector<int> &nums)
	{
		int n = nums.size();

		// 数组中至少存在一个数,所以nums[0]存在
		// dpmin[0] = dpmax[0] = nums[0]
		int dpmin = nums[0], dpmax = nums[0];

		// result=max(dpmax[i]), 这里先令result = dpmax[0]
		int res = dpmax;

		for(int i = 1; i < n; i++)
		{
			if(nums[i] == 0)
			{
				dpmin = dpmax = 0;
			}
			else if(nums[i] > 0)
			{
				dpmax = max(dpmax * nums[i], nums[i]);
				dpmin = min(dpmin * nums[i], nums[i]);
			}
			else
			{
				// tmp用来临时保存dpmax
				int tmp = dpmax;
				dpmax = max(dpmin * nums[i], nums[i]);
				dpmin = min(tmp * nums[i], nums[i]);
			}
			res = max(res, dpmax);
		}
		return res;
	}
};
  • 11
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
打家劫舍是一个经典的动态规划问题。根据引用\[2\]中的解法,我们可以使用动态规划来解决这个问题。假设偷窃房屋的下标范围是\[start, end\],用dp\[i\]表示在下标范围\[start, i\]内可以偷窃到的最高总金额。根据状态转移方程dp\[i\] = max(dp\[i − 2\] + nums\[i\], dp\[i − 1\]),我们可以通过递推得到最终的结果。 在解决这个问题时,我们可以使用滚动数组来降低空间复杂度,只需要存储前两间房屋的最高总金额,将空间复杂度降到O(1)。具体的代码实现可以参考引用\[2\]中的代码。 另外,对于打家劫舍 III这个问题,根据引用\[3\]中的解法,我们可以使用递归的方式来解决。对于每个节点,我们可以选择偷取该节点的钱和其四个孙节点的钱,或者选择偷取其两个儿节点的钱,然后比较两种方案的钱数,选择钱数较多的方案作为当前节点能偷取的最大钱数。 具体的代码实现可以参考引用\[3\]中的代码。 综上所述,我们可以使用动态规划来解决打家劫舍问题,具体的解法可以参考引用\[2\]中的代码。对于打家劫舍 III这个问题,可以使用递归的方式来解决,具体的解法可以参考引用\[3\]中的代码。 #### 引用[.reference_title] - *1* *2* *3* [动态规划解决打家劫舍问题](https://blog.csdn.net/p1967914901/article/details/125372599)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ghx3110

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值