动态规划问题总结

一、什么是动态规划?

动态规划算法通常基于一个递推公式及一个或多个初始状态。当前子问题的解将由上一次子问题的解推出。使用动态规划来解题只需要多项式的时间复杂度。

 

二、例子讲解

首先,我们要找到某个状态的最优解,然后在它的帮助下,找到下一个状态的最优解。

 

用leetcode上的198题House Robber作为一个入门例子吧。

链接:https://leetcode.com/problems/house-robber/

 

题目的大意是:你是一个专业的江洋大盗要盗窃一条街道上的房屋里的财宝。每个房屋都有一定数量的财宝。唯一的限制条件是:任意相邻的两个房屋都有一个互联的安全系统,如果你同时盗窃相邻的两个房屋那么安全系统会自动报警。在不惊动警察的前提下,算出你今晚能盗窃到的最大的财宝数。用数组nums存储每个房屋的财宝,nums[i]表示第i间房屋的财宝。

 

用动态规划的思想,将一个子问题用上一个子问题的解来表示。对于第i 间房屋,你有两种选择:盗窃和不盗窃。(1)如果要盗窃第i间房屋,那么必定不能盗窃第i-1间房屋,因为会报警,所以收益就等于在判断第i-2间房屋时候得到的最大收益+第i间房屋的财宝。(2)如果不盗窃第i间房屋,最大收益等于判断第i-1间房屋时的最大收益。

我们不妨用dp[i] 表示在判断第i间房屋时得到的最大收益,rob[i]表示盗窃第i间房屋。

那么转换方程是:dp[i] = max(dp[i-2]+nums[i], dp[i-1])

有了转换方程,接下来只需要对其进行初始化即可。易知:dp[0] = 0, dp[1] = nums[0]。有了状态和状态转移方程,这个问题基本上也就解决了。

 

因此c++代码如下:

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


类似的还有leetcode上的121题:Best Time to Buy and Sell Stock。

链接:https://leetcode.com/problems/best-time-to-buy-and-sell-stock/

 

另一类动态规划的题像leetcode上的377题:Combination Sum IV。

链接:https://leetcode.com/problems/combination-sum-iv/

 

题意:给你一个整数序列,序列中的数均为正数且没有重复的,找出所有可能的组合使得它们加起来等于target。

Example:

nums = [1, 2, 3]

target = 4

 

The possible combination ways are:

(1, 1, 1, 1)

(1, 1, 2)

(1, 2, 1)

(1, 3)

(2, 1, 1)

(2, 2)

(3, 1)

 

Note that different sequences are countedas different combinations.

 

Therefore the output is 7.

 

使用动态规划的思想,将一个子问题用前一个子问题的解来表示。不妨设dp[i] 表示当target=i 时一共有多少种组合情况。假设可以拆分的整数序列为nums,那么第一种情况就是将target 拆分成nums[0]和target-nums[0]两部分,那么第一种情况的组合数量为dp[target-nums[0]];第二种情况是将target拆分成nums[1]和target-nums[1],那么第二种情况的组合数量为dp[target-nums[1]]....,以此类

推,  dp[target]=

dp[target-nums[0]]+dp[target-nums[1]]+dp[target-nums[2]]+...+dp[target-nums[n-1],

n=nums.size()

有了状态转移方程后,要思考初始化情况, dp[0]=1。

于是c++代码如下:

class Solution {
public:
    int combinationSum4(vector<int>&nums, int target) {
        vector<int> dp(target+1, 0);
        int len=nums.size();
        dp[0]=1;
        for(int i=1; i<=target; i++){
            for(num: nums){
                if(i>=num)
                    dp[i]+=dp[i-num];
            }
        }//for
        return dp[target];
    }
};

会做这道题,那么爱奇艺17年校招的这道编程题问题也不大了,是上面这道题的变形。详情见链接:

http://blog.csdn.net/xiaoquantouer/article/details/52709941?locationNum=2

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值