一天一大 leet(地下城游戏)难度:困难-Day20200712
时间:2022-07-25
本文章向大家介绍一天一大 leet(地下城游戏)难度:困难-Day20200712,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
题目:
一些恶魔抓住了公主(P)并将她关在了地下城的右下角。地下城是由 M x N 个房间组成的二维网格。我们英勇的骑士(K)最初被安置在左上角的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。
骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。
有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。
为了尽快到达公主,骑士决定每次只向右或向下移动一步。
编写一个函数来计算确保骑士能够拯救到公主所需的最低初始健康点数。
例如,考虑到如下布局的地下城,如果骑士遵循最佳路径 右 -> 右 -> 下 -> 下,则骑士的初始健康点数至少为 7。
-2(k) |
-3 |
3 |
---|---|---|
-5 |
-10 |
1 |
10 |
30 |
-5(p) |
说明
- 骑士的健康点数没有上限。
- 任何房间都可能对骑士的健康点数造成威胁,也可能增加骑士的健康点数,包括骑士进入的左上角房间以及公主被监禁的右下角房间。
抛砖引玉
看完题目想到了做过的机器人那题:不同路径
不同路径是障碍,而本题是记录每个路过节点的值
思路
- 最低初始需要到终点前是没有多余的值即1
- 现在问题变成了知道结束值1,推到起始值了
- 逻辑反转,从结束值没到一个单元格减去本单元格的值直到推导到起点
- 到达一个点只可能从左侧或者上面进入则公式为:cur[i - 1][j]-dungeon[i][j] cur[i][j-1]-dungeon[i][j]
- 可能有不同的路径到达终点前值都为1,只取最小值
实现
- 因为迭代过程中每一个[i][j]的变化都会生成一个新的路线那么默认矩阵中每个节点的值都为 1,代表一种可能
/**
* @param {number[][]} dungeon
* @return {number}
*/
var calculateMinimumHP = function (dungeon) {
let m = dungeon.length,
n = dungeon[0] ? dungeon[0].length : 0,
cur = Array(m+1);
// 初始化与dungeon对应数组,记录到达某个单元格是剩余数量
for(let i = 0;i<m+1;i++){
cur[i]= Array(n+1).fill(Number.MAX_VALUE)
}
// 终点前默认剩余1
cur[m][n - 1] = cur[m - 1][n] = 1;
for (let i = m-1; i >= 0; i--) {
for (let j = n-1; j >= 0; j--) {
// 本单元格入口剩余的最小值
let itemMin = Math.min(cur[i + 1][j], cur[i][j + 1]);
cur[i][j] = Math.max(itemMin - dungeon[i][j], 1);
}
}
return cur[0][0]
}
存储对象cur降维
/**
* @param {number[][]} dungeon
* @return {number}
*/
var calculateMinimumHP = function (dungeon) {
let m = dungeon.length,
n = dungeon[0] ? dungeon[0].length : 0,
cur = new Array(n + 1).fill(Number.MAX_VALUE);
cur[n - 1] = 1;
for (let i = m - 1; i >= 0; --i) {
for (let j = n - 1; j >= 0; --j) {
let itemMin = Math.min(cur[j], cur[j + 1]);
cur[j] = Math.max(1, itemMin - dungeon[i][j]);
}
}
return cur[0];
};
其他解法
- 使用递归完成双层循环的路线选择
- 上面通过Math.min之间选择了单元格入口方向
- 下面通过更直观的方式去检查每个入口的剩余值
- 使用递归每次都需要查询入口值,理论上就可以省略存储结果的对象cur 但是,每次都查询就会有效率问题,索引参考上面思路依旧使用cur记录已经查询到的结果
/**
* @param {number[][]} dungeon
* @return {number}
*/
var calculateMinimumHP = function (dungeon) {
let m = dungeon.length,
n = dungeon[0] ? dungeon[0].length : 0,
cur = new Array(m);
// 初始化,每一项都为0,代表还没记录
for (let i = 0; i < m; i++) {
cur[i] = Array(n).fill(0);
}
function getMin(dungeon, i, j){
// 递归的出口
if (i == m - 1 && j == n - 1) {
return dungeon[i][j] > 0 ? 1 : 1 - dungeon[i][j];
}
// 如果备忘录中有,就直接返回它
if (cur[i][j] > 0) return cur[i][j];
let down = Number.MAX_VALUE,
right = Number.MAX_VALUE;
// 走下方的点,需要带着的最小安全血量
if (i < m - 1) down = getMin(dungeon, i + 1, j);
// 走右方的点,需要带着的最小安全血
if (j < n - 1) right = getMin(dungeon, i, j + 1);
if (down < right) {
if (down - dungeon[i][j] <= 0) {
cur[i][j] = 1;
} else {
cur[i][j] = down - dungeon[i][j];
}
} else {
if (right - dungeon[i][j] <= 0) {
cur[i][j] = 1;
} else {
cur[i][j] = right - dungeon[i][j];
}
}
return cur[i][j];
};
return getMin(dungeon, 0, 0, cur);
};
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Flutter为什么使用Dart?
- Flutter中如何使用WillPopScope
- 谈谈我对 Flutter 发展前景 和 “嵌套地狱” 的浅显看法
- 超过百万的StackOverflow Flutter 问题-第二期
- Flutter Flow实现半圆弹出菜单
- 【Flutter实战】自定义滚动条
- vue.config.js的优化配置(element-ui, echarts, lodash按需加载 )
- Flutter “孔雀开屏”动画效果
- Flutter 使用Navigator进行局部跳转页面
- Flutter 动画鼻祖之CustomPaint
- 【Flutter实战】Flutter 中那么多组件,难道要都学一遍?
- 【Flutter组件终结篇】332个组件 658页PDF
- Kubernetes在pod中配置hosts解析域名
- 【Flutter 实战】简约而不简单的计算器
- Flutter 中渐变的高级用法