力扣746使用最小花费爬楼梯
首先这道题目的理解需要花费一点时间,比如说给定n=cost.size()个台阶,那么数组下标的序号是0~n-1,如果第0层是最底层的话那么第n层是最顶层,题目问的是到达最顶层也就是第n层需要的花费。因为到达每一层需要的花费都是由上一层决定的,所以本题属于dp题目。对于递归函数的dp数组定义可以想到两种情况(1)dp[i]表示到达第i层需要的最小花费是多少(2)dp[i]表示到达第i层的顶层需要的最小花费是多少。对于不同的dp含义对应不同的递归公式,也对应不同的初始化,总体来说(1)比较好理解。考虑这种问题的时候注重想清楚如何逐步向后递归,而不是思考在离顶层还有几步的时候停下,因为这个已经包含在逐步向后递归的过程了。
int minCostClimbingStairs(vector<int>& cost) {
int n=cost.size();
vector<int>dp(n+1);//到达楼梯第i层需要的花费
dp[0]=0;//从0 huo 1出发都可以,所以出发即到达,所以花费为0
dp[1]=0;
for(int i=2;i<=n;++i)
{
dp[i]=min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);//可以前面一级台阶到也可以前面两级
}
return dp[n];
}
力扣62不同路径
积累:定义m行n列个vector二维数组:
vector<vector<int>>dp(m,vector<int>(n));//m行n列的二维数组
力扣63不同路径II
记得考虑第一个位置是障碍物的情况,此时所有位置到达的路径是0
if(obstacleGrid[0][0]==1)//只有一个位置但是有障碍物
return 0;
力扣416分割等和子集
1.看到这道题目将子集分割,首先想到的解法是双指针。但是这道题目不能使用双指针元素和,因为双指针移动的前提是数组有序,但是问题并不是基于要保证数组一定有序,比如说1 1 2 2 ,如果数组有序,那么返回值是false,但实际上1+2=1+2,无法使用双指针结束
2.当觉得使用双指针无法解决的时候,向背包解法靠近。每一个元素只能用一次所以是01背包,但是究竟递推公式是什么,也就是我们要找到一种什么关系? 首先可以确定的是dp[i]的含义是容量为i的时候一共有和为dp[i]的元素和,那肯定不是所有的最大容量i都会将背包装满,也就是dp[i]=i,所以我们要找的是dp[i]==i时的数组,如果无法相等也就是说当i=sum/2时,无法将这个背包装满,无法得到元素和的一半。
这道题的难点不在于想到是DP问题,也不在于如何定义dp数组,在于如何将dp数组转化为我们需要解决的问题,也就是对于 i 和 dp[i]之间关系的探索。
bool canPartition(vector<int>& nums) {
//首先这道题目不能使用双指针元素和,因为双指针移动的前提是数组有序,但是问题并不是基于要保证数组一定有序,比如说1 1 2 2 ,如果数组有序本题就不成立
int total=accumulate(nums.begin(),nums.end(),0);
if(total%2==1)return false;//无法找到两个相等的子集
int sum=total/2;
vector<int>dp(10001,0);//定义在第0-i个数据里面找和为dp[i]
//如果背包问题是最大还是最小和
for(int i=0;i<nums.size();++i)
{
for(int j=sum;j>=nums[i];--j)
{
dp[j]=max(dp[j],dp[j-nums[i]]+nums[i]);//容量为i时最多能容纳重量为i
}
}
if(dp[sum]==sum)return true;//容量为sum的背包正好能装下和为sum的数字
return false;
}