问题描述
剑指offer88题:爬楼梯的最少成本
解法一:自上而下递归
const cost = [1, 100, 1, 1, 100, 1]
// 得到爬上该楼梯的最小花费
function minCost(cost) {
const length = cost.length
/** 为什么这里不用 + cost[i]?你仔细想想:helpler 函数得到的其实是第 i 层向上爬所需要的花费也就是说:
** 我们只需要判断 length 层向上爬和 length - 1 层向上爬的那个花费比较小就可以了
*/
return Math.min(helper(cost, length - 1), helper(cost, length - 2));
// tips:因为索引是从 0 开始,所以 length - 1 代表第 length 层
}
// 得到第 i 层向上爬所需要的花费
function helper(cost, i) {
if (i < 2) return cost[i];
return Math.min(helper(cost, i - 1), helper(cost, i - 2)) + cost[i]
}
console.log(minCost(cost));
解法二:缓存结果减少重复计算
const cost = [1, 100, 1, 1, 100, 1]
function minCost(cost) {
const length = cost.length;
// 将计算结果缓存到 dep 中不重复计算,dep[0]的值就是从第1层向上爬所需要的花费
const dep = [cost[0], cost[1]];
helper(cost, length - 1, dep);
return Math.min(dep[length - 2], dep[length - 1])
}
// 为 dep[level] 赋值
function helper(cost, level, dep) {
// dep[0], dep[1] 已经赋值无需重复赋值
if (level < 2) return;
// 只有在 dep[level] 没有赋值的情况才需要赋值
if (!dep[level]) {
// 要求 dep[level] 首先得为 dep[level - 1] 和 dep[level - 2] 赋值
helper(cost, level - 1, dep);
helper(cost, level - 2, dep);
dep[level] = Math.min(dep[level - 1], dep[level - 2]) + cost[level];
}
}
console.log(minCost(cost));
解法三:自下而上的写法
这种解法比较好理解,耐心看下第四种解法!!
const cost = [1, 100, 1, 1, 100, 1]
function minCost(cost) {
const length = cost.length;
const dep = [cost[0], cost[1]]
for (let i = 2; i < length; i++) {
dep[i] = Math.min(dep[i - 1], dep[i - 2]) + cost[i]
}
return Math.min(dep[length - 1], dep[length - 2]);
}
console.log(minCost(cost));
解法四:再次优化,其实每次计算完只需保留前两个的结果
const cost = [1, 100, 1, 1, 100, 1]
function minCost(cost) {
const length = cost.length;
const dep = [cost[0], cost[1]]
for (let i = 2; i < length; i++) {
// 改动, i%2 说明 i = 2 的时候回替换掉 dep[0] 的数,旧的 dep[0](求下一个解并不需要它),以此类推...
dep[i % 2] = Math.min(dep[0], dep[1]) + cost[i]
}
return Math.min(dep[0], dep[1]);
}
console.log(minCost(cost));
总结
这篇文章是本人对《剑指offer》动态规划14.1的一个总结,希望对大家有帮助,有条件的可以看看原著,这是第一次发表文章,如果感觉还不错的话就给个三连吧,也算是我后续创作的一种激励,也欢迎大家在评论区批评指正,祝各位早日拿到自己心仪的 offer!
后话
立个 flag,在下周末会对 14.2 也做一个总结