LeetCode 每日一题 Day 10 || 并查集/二分搜索

1631. 最小体力消耗路径

你准备参加一场远足活动。给你一个二维 rows x columns 的地图 heights ,其中 heights[row][col] 表示格子 (row, col) 的高度。一开始你在最左上角的格子 (0, 0) ,且你希望去最右下角的格子 (rows-1, columns-1) (注意下标从 0 开始编号)。你每次可以往 上,下,左,右 四个方向之一移动,你想要找到耗费 体力 最小的一条路径。

一条路径耗费的 体力值 是路径上相邻格子之间 高度差绝对值 的 最大值 决定的。

请你返回从左上角走到右下角的最小 体力消耗值 。

示例 1:

在这里插入图片描述

输入:heights = [[1,2,2],[3,8,2],[5,3,5]]
输出:2
解释:路径 [1,3,5,3,5] 连续格子的差值绝对值最大为 2 。
这条路径比路径 [1,2,2,2,5] 更优,因为另一条路径差值最大值为 3 。

示例 2:
在这里插入图片描述

输入:heights = [[1,2,3],[3,8,4],[5,3,5]]
输出:1
解释:路径 [1,2,3,4,5] 的相邻格子差值绝对值最大为 1 ,比路径 [1,3,5,3,5] 更优。

示例 3:
在这里插入图片描述

输入:heights = [[1,2,1,1,1],[1,2,1,2,1],[1,2,1,2,1],[1,2,1,2,1],[1,1,1,2,1]]
输出:0
解释:上图所示路径不需要消耗任何体力。

提示:

rows == heights.length
columns == heights[i].length
1 <= rows, columns <= 100
1 <= heights[i][j] <= 106

这个题目第一眼看到就想DFS+二分,后面看了题解之后尝试了并查集来实现,但是代码似乎有点臃肿,时间和空间开销都比较大,首先讲一下我的第一种解法,二分搜索:

class Solution
{
public:
    bool dfs(const vector<vector<int>> &heights, int mid, int row, int col, vector<vector<bool>> &visited)
    {
        int row = heights.size();
        int col = heights[0].size();
        // 达到终点
        if (row == row - 1 && col == col - 1)
        {
            return true;
        }
        // 标记当前位置已访问

        visited[row][col] = true;
        // 定义四个方向的坐标变化

        vector<pair<int, int>> direction = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
        for (const auto &dir : direction)
        {
            int newRow = row + dir.first;
            int newCol = col + dir.second;

            // 检查新位置是否合法
            if (newRow >= 0 && newRow < row && newCol >= 0 && newCol < col &&
                !visited[newRow][newCol] && abs(heights[newRow][newCol] - heights[row][col]) <= mid)
            {
                if (dfs(heights, mid, newRow, newCol, visited))
                {
                    return true;
                }
            }
        }

        return false;
    }
    int minimumEffortPath(vector<vector<int>> &heights)
    {
        int left = 0, right = 1e6;

        while (left < right)
        {
            int mid = left + (right - left) / 2;

            vector<vector<bool>> visited(heights.size(), vector<bool>(heights[0].size(), false));

            if (dfs(heights, mid, 0, 0, visited))
            {
                // 如果可以达到终点,尝试减小体力值
                right = mid;
            }
            else
            {
                // 如果无法达到终点,增大体力值
                left = mid + 1;
            }
        }

        return left;
    }
};

下面是看了官方题解之后的并查集代码:

class UnionFind
{
public:
    vector<int> parent;
    vector<int> rank;

    UnionFind(int size)
    {
        parent.resize(size);
        rank.resize(size, 1);

        // 初始化并查集,每个节点的父节点为自己
        for (int i = 0; i < size; ++i)
        {
            parent[i] = i;
        }
    }

    // 查找节点所属集合的根节点
    int find(int x)
    {
        if (parent[x] != x)
        {
            parent[x] = find(parent[x]);
        }
        return parent[x];
    }

    // 合并两个集合
    void unite(int x, int y)
    {
        int rootX = find(x);
        int rootY = find(y);

        if (rootX != rootY)
        {
            if (rank[rootX] > rank[rootY])
            {
                parent[rootY] = rootX;
            }
            else if (rank[rootX] < rank[rootY])
            {
                parent[rootX] = rootY;
            }
            else
            {
                parent[rootY] = rootX;
                rank[rootX]++;
            }
        }
    }
};
class Solution
{
public:
    int minimumEffortPath(vector<vector<int>> &heights)
    {
        int rows = heights.size();
        int columns = heights[0].size();

        // 存储边的格式为 {体力消耗值, 单元格1, 单元格2}
        vector<vector<int>> edges;

        // 根据相邻单元格的高度差构建边
        for (int row = 0; row < rows; ++row)
        {
            for (int col = 0; col < columns; ++col)
            {
                if (row > 0)
                {
                    edges.push_back({abs(heights[row][col] - heights[row - 1][col]), row * columns + col, (row - 1) * columns + col});
                }
                if (col > 0)
                {
                    edges.push_back({abs(heights[row][col] - heights[row][col - 1]), row * columns + col, row * columns + col - 1});
                }
            }
        }

        // 根据体力消耗值升序排序边
        sort(edges.begin(), edges.end(), [](const vector<int> &a, const vector<int> &b)
             { return a[0] < b[0]; });

        UnionFind uf(rows * columns);

        // 遍历排序后的边,使用并查集找到最小体力消耗值
        for (const vector<int> &edge : edges)
        {
            uf.unite(edge[1], edge[2]);
            if (uf.find(0) == uf.find(rows * columns - 1))
            {
                return edge[0];
            }
        }

        return 0;
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/236780.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

案例056:基于微信小程序的购物系统

文末获取源码 开发语言&#xff1a;PHP 框架&#xff1a;Think PHP 数据库&#xff1a;mysql 5.7 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序运行软件&#xff1a;微信开发者工具 目录 前言 系统展示 后台模块的实现 用户信息管理 商品信…

USB Type-C一拖二线缆制作方法

1 实现方法 Figure 1-1 Type-C Socket(母口) Figure 1-2 Type-C Plug(公头) Table 1-1 Type-C Socket Pin连接描述 Type-C Plug连接&#xff0c; 需要做一个一拖二的线&#xff0c;一根的一端是USB&#xff0c; 另外一根的一端是USB转UART&#xff0c; 参考Table 1-2。 Table 1…

windows MYSQL解决中文乱码问题

1.首先确保你已经把mysql配置了环境变量 2.打开window终端 3.输入mysql -u root -p 4.输入密码&#xff0c;就是安装的时候设置的root超级管理员权限密码 5.输入&#xff1a; SHOW VARIABLES LIKE ‘character%’; 出现上图&#xff0c;说明就会出现中文乱码问题。 6.该怎么办…

31、卷积 - 参数 dilation 以及空洞卷积

在卷积算法中,还有一个不常见的参数叫做dilation(中文:膨胀)。 很多同学可能没听说过这个参数,下面看看这个参数有什么作用,用来控制什么的。 我们还是放这个经典的卷积运算图,图中是看不出 dilation 这个参数的存在的。 如果再换一张图呢,发现两图的区别了吗? 没错…

JavaDay17

创建不可变集合 import java.util.Iterator; import java.util.List;public class Test {public static void main(String[] args) {/*创建不可变的List集合* "张三" "李四" "王五" "赵六*///一旦创建之后 是无法进行修改的 在下面的代码…

[Linux] nginx防盗链与优化

一、Nginx的页面优化 1.1 Nginx的网页压缩 在Nginx的ngx_http_gzip_module压缩模块提供对文件内容压缩的功能。进行相关的配置修改&#xff0c;就能实现Nginx页面的压缩&#xff0c;达到节约带宽&#xff0c;提升用户访问速度 vim /usr/local/nginx/conf/nginx.conf http { .…

Shell三剑客:正则表达式简介

前言 一、名称解释 正则表达式&#xff08;regular expression&#xff0c;RE&#xff09;是一种字符模式&#xff0c;用于在查找过程中匹配指定的字符。在大多数程序里&#xff0c;正则表达式都被置于两个正斜杠之间&#xff1b;例如/l[oO]ve/就是由正斜杠界定的正则表达式&am…

python基于ModBusTCP服务端的业务实现特定的client

python实现ModBusTCP协议的client是一件简单的事情&#xff0c;只要通过pymodbus、pyModbusTCP等模块都可以实现&#xff0c;本文采用pymodbus。但要基于ModBusTCP服务端的业务实现特定的client&#xff0c;那得看看服务端是否复杂。前面系列文章&#xff0c;我们学习了对服务端…

无需公网IP联机Minecraft,我的世界服务器本地搭建教程

目录 前言 1.Mcsmanager安装 2.创建Minecraft服务器 3.本地测试联机 4. 内网穿透 4.1 安装cpolar内网穿透 4.2 创建隧道映射内网端口 5.远程联机测试 6. 配置固定远程联机端口地址 6.1 保留一个固定TCP地址 6.2 配置固定TCP地址 7. 使用固定公网地址远程联机 8.总…

开关量防抖滤波器(梯形图和SCL源代码)

模拟量防抖超限报警功能块请查看下面文章链接: https://rxxw-control.blog.csdn.net/article/details/133969425https://rxxw-control.blog.csdn.net/article/details/133969425 1、开关量防抖滤波器 2、防抖滤波 3、梯形图代码

【conda】利用Conda创建虚拟环境,Pytorch各版本安装教程(Ubuntu)

TOC conda 系列&#xff1a; 1. conda指令教程 2. 利用Conda创建虚拟环境&#xff0c;安装Pytorch各版本教程(Ubuntu) 1. 利用Conda创建虚拟环境 nolonolo:~/sun/SplaTAM$ conda create -n splatam python3.10查看结果&#xff1a; (splatam) nolonolo:~/sun/SplaTAM$ cond…

手把手教你玩转ESP8266(原理+驱动)

在嵌入式开发中&#xff0c;无线通信的方式有很多&#xff0c;其中 WIFI 是绕不开的话题。说到 WIFI 通信&#xff0c;就不得不提 ESP8266了。 ESP8266 是一款高性能的 WIFI 串口模块&#xff0c;实现透明传输。只要有一定的串口知识&#xff0c;不需要知道 WIFI 原理就可以上…

【Qt开发流程】之UI风格、预览及QPalette使用

概述 一个优秀的应用程序不仅要有实用的功能&#xff0c;还要有一个漂亮美腻的外观&#xff0c;这样才能使应用程序更加友善、操作性良好&#xff0c;更加符合人体工程学。作为一个跨平台的UI开发框架&#xff0c;Qt提供了强大而且灵活的界面外观设计机制&#xff0c;能够帮助…

如何快速访问未知世界【献给我的一位尚未谋面的“故友”】

1.下载Chrome浏览器 想要访问未知世界&#xff0c;强烈推荐Chrome&#xff0c;好用无广告&#xff0c;点击链接即可下载&#xff1a; 点我访问下载页面 2.安装插件 下一步&#xff0c;我们需要安装一个插件&#xff0c;这个插件能为Chrome浏览器插上腾飞的翅膀 [doge] (可以…

FTR223限时回归?经典三花再加金翅膀,CL500特别款亮相

FTR223可以说是非常经典的一款本田小攀爬车型了&#xff0c;之前我还有幸玩过一段时间&#xff0c;最近本田在泰国车展上展出了CL500的特别版&#xff0c;其中FTR223纪念版的版画让人眼前一亮&#xff0c;经典的白、红、蓝三色搭配让人眼前一亮。 CL500这台车在国内今年刚上市&…

18.Java程序设计-基于Springboot的电影院售票系统的设计与实现

摘要 电影产业在当今社会中占据着重要地位&#xff0c;电影院作为观影的主要场所&#xff0c;其售票系统的高效性和用户体验至关重要。本文基于Spring Boot框架设计并实现了一款电影院售票系统&#xff0c;旨在提高售票效率、优化用户体验&#xff0c;并解决传统售票方式存在的…

Panalog 日志审计系统 sprog_deletevent.php SQL 注入漏洞复现

0x01 产品简介 Panalog大数据日志审计系统定位于将大数据产品应用于高校、 公安、 政企、 医疗、 金融、 能源等行业之中&#xff0c;针对网络流量的信息进行日志留存&#xff0c;可对用户上网行为进行审计&#xff0c;逐渐形成大数据采集、 大数据分析、 大数据整合的工作模式…

Rocket MQ 架构介绍

文章目录 为什么选择Rocket MQ基本概念优点缺点架构图编程模型发送者发送消息固定步骤消费者消费消息固定步骤 为什么选择Rocket MQ Rocket MQ是阿帕奇顶级的开源项目&#xff0c;由阿里开发并开源。它的研发背景是Active MQ与Kafka不能很好的解决当时的业务场景。官网上是这么…

游戏中小地图的制作__unity基础开发教程

小地图的制作 Icon标识制作制作摄像机映射创建地图UI效果“不一样的效果” 在游戏中经常可以看到地图视角的存在&#xff0c;那么地图视角是如何让实现的呢&#xff1f; 这一期教大家制作一个简易的小地图。 &#x1f496;点关注&#xff0c;不迷路。 老样子&#xff0c;我们还…

c语言为什么要引入变量

大家好&#xff0c;今天给大家介绍c语言为什么要引入变量&#xff0c;文章末尾附有分享大家一个资料包&#xff0c;差不多150多G。里面学习内容、面经、项目都比较新也比较全&#xff01;可进群免费领取。 C语言引入变量的原因主要是为了存储数据并且方便后续的操作和计算。 变…