这道题的意思是说,你站在一个台阶上,需要支付相应的费用才可以继续向上走
定义一个dp数组,dp[i]表示站在第i层台阶已经支付的费用,由于我们直接就能站到0和1级台阶,不需要支付费用,因此 dp[0]=0,dp[1]=0
状态转移方程为:dp[i] = min(dp[i-2] + cost[i-2], dp[i-1] + cost[i-1])
要想到达 i 级台阶,则必须指向i-2或i-1级台阶的费用,加上先前的费用dp[i-2]/dp[i-1]
最后需要返回dp[n],因为n-1表示最后一级台阶,dp[n-1]表示站在n-1级台阶已经花费的费用
class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
// dp[i]:站在第i层台阶已经支付的费用
// 最后需要返回dp[n],因为dp[n-1]表示最后一级台阶
int n = cost.size();
int* dp = new int[n+1];
dp[0] = 0;
dp[1] = 0;
for(int i = 2; i <= n; i++){
dp[i] = min(dp[i-2] + cost[i-2], dp[i-1] + cost[i-1]);
}
return dp[n];
}
};
进阶:打印经过的路径
我们定义一个记录路径的数组path,path[i]表示站在 i 级台阶时,是从path[i] 级台阶上来的。我们最后一步是从path[n]出发的,所以path数组长度的应该是n+1,将0和1级台阶的path记为-1,表示起点
每次更新dp数组的时候,同时更新path数组,记录到当前台阶是从哪个台阶过来的
比如对于如下的cost数组来说,path数组应该为如下形式:
我们回溯时,先把路径记录在stack中,然后再输出就是路径了
class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
// dp[i]:站在第i层台阶已经支付的费用
// 最后需要返回dp[n],因为dp[n-1]表示最后一级台阶
int n = cost.size();
int* dp = new int[n+1];
int* path = new int[n+1];
path[0] = path[1] = -1;
dp[0] = 0;
dp[1] = 0;
for(int i = 2; i <= n; i++){
dp[i] = min(dp[i-2] + cost[i-2], dp[i-1] + cost[i-1]);
if(dp[i] == dp[i-2] + cost[i-2]){
// 从i-2级台阶爬上来
path[i] = i - 2;
}else{
// 从i-1级台阶爬上来
path[i] = i - 1;
}
}
stack<int> st;
int p = path[n]; // 最后一步从path[n]出发的,越过第n级台阶,到达终点
while(p != -1){
st.push(p);
p = path[p];
}
while(!st.empty()){
cout << st.top() << " ";
st.pop();
}
return dp[n];
}
};