[C++]动态规划入门(一) 以LeetCode 198. House Robber为例

在这里插入图片描述
在这里插入图片描述

在考虑动态规划的时候,可以把问题简化为选和不选的问题,并把问题抛给下一轮的选和不选。小偷入室偷窃就是一类经典的基本动态规划问题—如何在选取一个数而不再取相邻数字相加最大和

有一个目标数组array=[1,2,3,1]; 
·如果选择array[0]=1 那么array[1]则不再选取 抛出下一轮选和不选的问题 有一个目标数组array=[3,1];
·如果不选择array[0] 那么array[1]=2可以选取 抛出下一轮问题 有一个目标数组array=[2,3,1];

对于目标数组array[3,1];
·如果选择array[0]=3 那么array[1]则不再选取 抛出下一轮选和不选的问题 有一个目标数组array=[]; 
目标数组长度为0返回最终结果 sum=4;
·如果不选择array[0] 那么array[1]=1可以选取 抛出下一轮问题 有一个目标数组array=[1];

对于目标数组array[2,3,1];
·如果选择array[0]=2 那么array[1]则不再选取 抛出下一轮选和不选的问题 有一个目标数组array=[1]; 
·如果不选择array[0] 那么array[1]=3可以选取 抛出下一轮问题 有一个目标数组array=[];
目标数组长度为0返回最终结果 sum=3;
.....
.....

…动态规划实际上就是一轮接着一轮的套娃,并返回最终结果的最大值,选和不选的经过不需要我们详细地去了解,这一切只需要把它抛给计算机即可。(下图是选与不选出现的分支结果)

在这里插入图片描述

一、递归法
这是最容易理解的方式也是通用模板,但是时间复杂度和回溯法一样是O(n!)

class Solution
{
	private:
	int dp(vector<int>&nums,int step)//step 为当前数字的下标
	{
		/*模板出口*/
		if(step>=nums.size())//递归出口 理解为当下标大于数组长度时停止递归
		{
			return 0;
		}
		
		/*模板 选和不选的问题*/
		int choose = nums[step]+dp(nums,step+2);//选择当前数字,下一个数字就不再选择所以step+2
		int nochoose = dp(nums,step+1);//不选择当前数字,下一个数字可以选择所以step+1
		return max(choose,nochoose);//我们不用去关心过程是怎么样的 把选和不选的问题抛给计算机 
		//如果还是不明白的可以看一下上面的图

	}
	
	public:
	int rob(vector<int>&nums){
	return dp(nums,0);
	}

};

运行代码试一下,emmm…当nums的长度少于30的时候还是挺顺畅的,但当nums数组的内容不断扩展的时候问题就来了,对于普通的电脑来说一般都是“超时”。
试想一下,递归的过程中对于每一次的结果都是从根节点出发的,即从
sum=0 -> sum=4 -> sum=0 -> sum=2 -> sum=0 …->sum=3
但是从上图中我们可以看出有一些节点可以用上一次的节点从发选择结果,
例如sum=0->sum=4的过程中,我们可不可以把sum=1这个结果保存下来然后直接进行下一轮选择呢。

二、数组法
利用数组保存已经遍历节点的结果(剪枝)
—唯有懂得怎么保存先前的结果才算真的懂得了动态规划

class Solution{


    int rob(vector<int>& nums) {
       
       //--------边界检查---
       if(nums.size()==0)
       return 0;
       if(nums.size()==1)
       return nums[0];
       //----------------

        vector<int>v(nums.size()+2);//申请一个nums.size()+2大小的数组
        v[0]=0;v[1]=0;//假设nums[0]之前还有两个数字0,0
        for(int i=2;i<=nums.size()+1;++i)//回到和方法一同样的问题 选和不选
        {
            int choose = nums[i-2]+v[i-2];//选择 跳跃一个结果选择
            int nochoose = v[i-1];//不选 保存当前结果
            v[i]=max(choose,nochoose);
			//我们不用去关心过程是怎么样实现的 只需要把选和不选的问题抛给计算机即可
        }
        return v[nums.size()+1];


    }
};

只遍历了一次数组,时间复杂度为O(n)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值