爬代价楼梯
题目描述:
给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。
你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。
请你计算并返回达到楼梯顶部的最低花费。
难于昨天的楼梯
解法一:(递归版)
源码:
cpp
class Solution {
int n1(int n, vector<int>& cost, vector<int>& vis) {
if (n > 2) {
if (vis[n] != 0) {
return vis[n];
} else {
vis[n] = min(n1(n - 1, cost, vis) + cost[n - 1],
n1(n - 2, cost, vis) + cost[n - 2]);
return vis[n];
}
} else {
if (n == 1) {
return 0;
} else {
return min(cost[0], cost[1]);
}
}
}
public:
int minCostClimbingStairs(vector<int>& cost) {
int n = cost.size();
vector<int> vis(n + 1);
return n1(n, cost, vis);
}
};
说明:
超时了
解法二:
源码:
cpp
class Solution {
int n1(int n, vector<int>& cost, vector<int>& vis) {
vis[1] = 0;
vis[2] = min(cost[0], cost[1]);
for (int i = 3; i <= n; i++) {
vis[i] = min(vis[i - 1] + cost[i - 1], vis[i - 2] + cost[i - 2]);
}
return vis[n];
}
public:
int minCostClimbingStairs(vector<int>& cost) {
int n = cost.size();
vector<int> vis(n + 1);
return n1(n, cost, vis);
}
};
说明:
递归太耗时了,循环替代。
解法三:
源码:
cpp
class Solution {
int n1(int n, vector<int>& cost) {
if (n == 1) return 0;
if (n == 2) return min(cost[0], cost[1]);
int a = 0; // 对应vis[1]
int b = min(cost[0], cost[1]); // 对应vis[2]
int res = 0;
for (int i = 3; i <= n; i++) {
res = min(b + cost[i - 1], a + cost[i - 2]);
a = b;
b = res;
}
return res;
}
public:
int minCostClimbingStairs(vector<int>& cost) {
int n = cost.size();
return n1(n, cost);
}
};
说明:
去掉数组,进一步压缩空间
总结
递归超时有3个主要原因:
1.函数调用栈的硬开销(主要原因)
递归的每一次调用,系统都需要:
- 为函数创建栈帧(保存返回地址、参数、局部变量);
- 把参数(n、cost、vis)从当前函数复制到新函数;
- 函数执行完成后,销毁栈帧并返回结果;
2.缓存访问的开销
递归函数中存在一些判断,多次调用多次判断
3.系统对递归的限制
操作系统对函数栈的深度有上限,超出会直接触发栈溢出错误,而迭代没有这个限制