【解析与反思】leetcode 1219. 黄金矿工 DFS 解法(C++)

2023-11-08

目录


前言

本文采用 DFS 算法求解问题,针对提交过程中遇到了超时的问题做出了分析和调试,供大家参考。


一、原题

你要开发一座金矿,地质勘测学家已经探明了这座金矿中的资源分布,并用大小为 m * n 的网格 grid 进行了标注。每个单元格中的整数就表示这一单元格中的黄金数量;如果该单元格是空的,那么就是 0。

为了使收益最大化,矿工需要按以下规则来开采黄金:

每当矿工进入一个单元,就会收集该单元格中的所有黄金。
矿工每次可以从当前位置向上下左右四个方向走。
每个单元格只能被开采(进入)一次。
不得开采(进入)黄金数目为 0 的单元格。
矿工可以从网格中 任意一个 有黄金的单元格出发或者是停止。

示例 1:

输入:grid = [[0,6,0],[5,8,7],[0,9,0]]
输出:24
解释:
[[0,6,0],
 [5,8,7],
 [0,9,0]]
一种收集最多黄金的路线是:9 -> 8 -> 7。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/path-with-maximum-gold
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

二、基本思想

  1. 找到所有的可开始的单元作为起点 start;

  2. 每个 start 点开始【遍历挖矿】,最后比较哪种收集黄金最多;

  3. 【遍历挖矿】其实是做 DFS 深度优先搜索,条件是:上下左右四个方向 && 不为0 && 未访问过的邻接点;

  4. 遍历时同时求路线最大值;

  5. 遍历完返回该点遍历后的最大路线值。

三、代码实现

1. 程序主体

首先,为了方便接下来的 DFS 方便访问 grid,在功能函数外创建了 public 下的 grid2 拷贝;

两层循环寻找每一个不为 0 的 start 点,将这些点进行 DFS 遍历;

DFS 遍历后的返回值更新目前的最大值 max;

因为 visit 定义在了外部,对当前 start 点访问完后需要重置回 0,即未访问状态,这样不影响下一个 start 点正常遍历;(还原,再探索其他情况)

class Solution {
public:
    int dir[4] = {0, 1, 0, -1};
    int visit[20][20] = {0};
    vector<vector<int>> grid2;

    int getMaximumGold(vector<vector<int>>& grid) {
        grid2 = grid;
        int n = grid.size();//row
        //if(!grid.empty()) 
        int m = grid.front().size();//array
        //to mark whether it's visited
        int max = 0;
        for(int i = 0; i < n; i ++){
            for(int j = 0; j < m; j++){
                if(grid[i][j]){
                    visit[i][j] = 1;
                    max = max < DFS(i,j)? DFS(i,j): max;
                    visit[i][j] = 0;
                }
            }
        }
        return max;
    }
};

2. DFS 接着在 public 下定义

本题的 DFS 比基本 DFS 多以下几个问题:

  • 上下左右四个方向邻接点如何表示
  • 如何在遍历的过程中加和返回【最佳路径值】

解析:

  • 上下左右:
    分析共(i,j+1)(i,j-1)(i+1,j)(i-1,j)四个点,发现规律 i ± 1 的时候,j 是不变的;同样 j ± 1 的时候,i 是不变的。
    因此创建 0,±1 交错的数组 dir[4] = {0, 1, 0, -1},利用 k 遍历数组,让 i + dir[k],j + dir[k+1],为了让 dir[k+1] 能成环,所以对于 j 用取余的方法访问 dir[];所以让 j + dir[(k+1)%4]
  • 加和 ans:
    首先 ans 必定包含非 0 start 点的值,故初始化为 grid[i][j];
    访问符合条件的邻接点时,我们期望 ans 加上邻接点中【子线路】的值 再 加上该邻接点的值,因此构成递归解决问题;
    若该邻接点 【子线路】的值 再 加上该邻接点的值 没有现在 ans 大,则不选择该路线,也不会更新 ans;
    而递归的终点即最后一个点,该点无符合要求的邻接点,故 ans = grid[终点][终点],返回初始化的值即可;
    int DFS(int i, int j){
        int ans = grid2[i][j];
        //4 cells around
         for (int k = 0; k < 4; k++){
            int x = i + dir[k], y = j + dir[(k + 1) % 4];
            if(x < 0 || x >= grid2.size() || y < 0 || y >= grid2.front().size() || !grid2[x][y] || visit[x][y]) continue;
            visit[x][y] = 1;
            ans = ans < DFS(x, y) + grid2[i][j] ? DFS(x, y)+ grid2[i][j]:ans;
            visit[x][y] = 0;
        }
        return ans;
    }

四、代码优化

然而天有不测风雨...代码超时了。

在多次排查后发现罪魁祸首是 DFS 中的:

ans = ans < DFS(x, y) + grid2[i][j] ? DFS(x, y)+ grid2[i][j]:ans;

这里判断语句快速返回值中,每书写一次 DFS,都会做一次递归,因此时间炸了,功能函数中只有 1 次所以速度不影响。

改进-> 记录下 DFS 的值即可

所以我用的:

ans = max(ans, DFS(x, y) + grid2[i][j]);

就过了。

五、Dijktra 算法思考

问题可以同样转化成有权图的单源最长路算法。

回头填坑。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【解析与反思】leetcode 1219. 黄金矿工 DFS 解法(C++) 的相关文章

随机推荐

  • JPS命令的安装和使用

    一 简介 jps Java Virtual Machine Process Status Tool 是JDK 1 5提供的一个显示当前所有java进程pid的命令 简单实用 非常适合在linux unix平台上简单察看当前java进程的一些
  • android NDK编译openblas和向量检索库faiss

    设置android SDK和NDK路径 例如 export SDK ROOT root codes my sdk sdk export NDK ROOT root codes my sdk sdk ndk 24 0 8215888 sdk和
  • 自制带串口的J-Link OB 072

    自制带串口的J Link OB 072 普通的三线J link不带串口 使用起来比较麻烦 于是找资料自制了一个J Link OB 072 主芯片是stm32f072c8t6 带串口 使用方便 先上图 自带信仰加持 一遍调通 急急如律令 依然
  • vue 高德地图添加放大缩小地图、转盘工具

    新建文件 amap vue
  • Guided Diffusion/Diffusion Models Beat GANs on Image Synthesis (Paper reading)

    Guided Diffusion Diffusion Models Beat GANs on Image Synthesis Paper reading Prafulla Dhariwal OpenAI NeurlPS2021 Cited
  • JavaScript——大数组的合并问题及不同数组合并方法的探究

    JavaScript 大数组的合并问题及不同数组合并方法的探究 最近在处理模型数据的时候出现了一个问题 当合并不同模型的vertex等数据的时候 从网上查了查都说Array prototype push 这个好 结果我使用了这个方法却报错了
  • VUE的项目中怎样修改浏览器窗口的 LOGO

    vue项目如何修改上图浏览器的标题栏的图标 在public目录中的index html添加如下代码 注意logo svg是图片 图片位置在public目录下
  • 【直接收藏】前端 VUE 高阶面试题(一)

    1 说说vue动态权限绑定渲染列表 权限列表渲染 首先请求服务器 获取当前用户的权限数据 比如请求 this http get rights list 获取到权限数据之后 在列表中使用v if v if else的组合来展示不同的内容
  • 性能测试常见问题分析

    性能测试常见问题分析 1 请你个人描述一下性能测试的意义和作用 说出因性能不良造成的质量事故 2 如何进行性能测试 请说出整体的性能测试流程 a 分析测试范围 测试对象 如频繁使用的功能 频繁调用的接口 大量数据库读写操作多的功能 大量读写
  • 信息组织川大972

    网络信息组织 1 网络信息环境 1 1 网络发展的三个阶段 2 语义网信息组织 2 1 万维网与语义网 2 2 语义网技术架构 2 3 本体 2 4 关联数据 2 5 网站信息架构 3 Web2 0信息组织方法 3 1 标签法 3 2 Wi
  • 多元Huffman编码问题

    题目链接 题意 最多可以让k堆合并 每一次合并的花费为河合并堆的数量 问最多和最少的花费 题解 最少的花费一定是每次合并的堆数尽可能多 这样我们就会减少前面已经合并的堆的重复计算 所以 每次合并k堆时最少 每次合并2堆时最大 另外 最少的时
  • [WTL] STLport安装指南

    STLport安装指南STLport 4 6 是完全兼容ANSI C 标准的类库 This distribution contains STLport sources only no binaries To use STLport iost
  • Word文件删除后怎么恢复?好用的恢复方法分享

    Word文件删除后怎么恢复 在工作和学习的过程中 我们难免会遇到丢失数据的情况 比如有时候不小心删除了Word文件 或者Word文件在操作过程中意外卡顿导致丢失 有什么好方法恢复呢 下面就一起来了解下 遇到Word文件数据丢失不要慌张 首先
  • Java项目的开发流程

    一个java开发项目过程 1 项目启动 1 项目组成立 公司成员 客户成员 2 制定项目预期目标 3 制定项目计划周期 4 建立好项目组成员沟通机制 2 需求调研 1 创建调研计划 协调调研时间 2 收集客户资料 获取客户需求 所有的资料都
  • Redis缓存雪崩、穿透、击穿原因分析和解决方案,附Redis管道使用技巧

    先给大家附上其他几篇文章 感兴趣的自行开车导航 Redis过期策略和持久化机制全面揭秘 教你如何合理配置 深入浅出Redis 一 从版本特性到数据类型到线程模型 带你了解Redis的核心特性和应用场景 一次redis OOM问题分析解决 r
  • 阿里云ECS漏洞修复简单办法

    阿里云的安全检测功能会每天检测主机上的漏洞 然后短信推送 让你试用漏洞修复功能 或购买修复功能 其实不需要购买 在主机上执行 apt upgrade 或者 yum upgrade 就自动修复了 其实就是更新软件包 更新内核 然后重启就可以了
  • LeetCode-738

    738 单调递增的数字 给定一个非负整数 N 找出小于或等于 N 的最大的整数 同时这个整数需要满足其各个位数上的数字是单调递增 当且仅当每个相邻位数上的数字 x 和 y 满足 x lt y 时 我们称这个整数是单调递增的 Example
  • 油盐微服务——负载均衡Ribbon

    文章目录 客户端负载均衡 RestTemplate详解 Spring Cloud Ribbon 是一个基于http和tcp的客户端 负载均衡工具 它 不需要像服务注册中心那样 独立部署 它几乎存在于每一个Spring Cloud构建的微服务
  • ubuntu16.04 从源码安装opencv4.0 支持anaconda3.5

    step1 安装依赖库 sudo apt get install build essential cmake pkg config sudo apt get install libjpeg8 dev libtiff5 dev libjasp
  • 【解析与反思】leetcode 1219. 黄金矿工 DFS 解法(C++)

    目录 前言 一 原题 二 基本思想 三 代码实现 四 代码优化 五 Dijktra 算法思考 前言 本文采用 DFS 算法求解问题 针对提交过程中遇到了超时的问题做出了分析和调试 供大家参考 一 原题 你要开发一座金矿 地质勘测学家已经探明