一、什么是动态规划?
动态规划算法通常基于一个递推公式及一个或多个初始状态。当前子问题的解将由上一次子问题的解推出。使用动态规划来解题只需要多项式的时间复杂度。
二、例子讲解
首先,我们要找到某个状态的最优解,然后在它的帮助下,找到下一个状态的最优解。
用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