【二分查找】LeetCode1970:你能穿过矩阵的最后一天
本文涉及的基础知识点
二分查找算法合集
作者推荐
动态规划LeetCode2552:优化了6版的1324模式
题目
给你一个下标从 1 开始的二进制矩阵,其中 0 表示陆地,1 表示水域。同时给你 row 和 col 分别表示矩阵中行和列的数目。
一开始在第 0 天,整个 矩阵都是 陆地 。但每一天都会有一块新陆地被 水 淹没变成水域。给你一个下标从 1 开始的二维数组 cells ,其中 cells[i] = [ri, ci] 表示在第 i 天,第 ri 行 ci 列(下标都是从 1 开始)的陆地会变成 水域 (也就是 0 变成 1 )。
你想知道从矩阵最 上面 一行走到最 下面 一行,且只经过陆地格子的 最后一天 是哪一天。你可以从最上面一行的 任意 格子出发,到达最下面一行的 任意 格子。你只能沿着 四个 基本方向移动(也就是上下左右)。
请返回只经过陆地格子能从最 上面 一行走到最 下面 一行的 最后一天 。
示例 1:
输入:row = 2, col = 2, cells = [[1,1],[2,1],[1,2],[2,2]]
输出:2
解释:上图描述了矩阵从第 0 天开始是如何变化的。
可以从最上面一行到最下面一行的最后一天是第 2 天。
示例 2:
输入:row = 2, col = 2, cells = [[1,1],[1,2],[2,1],[2,2]]
输出:1
解释:上图描述了矩阵从第 0 天开始是如何变化的。
可以从最上面一行到最下面一行的最后一天是第 1 天。
示例 3:
输入:row = 3, col = 3, cells = [[1,2],[2,1],[3,3],[2,2],[1,1],[1,3],[2,3],[3,2],[3,1]]
输出:3
解释:上图描述了矩阵从第 0 天开始是如何变化的。
可以从最上面一行到最下面一行的最后一天是第 3 天。
参数范围:
2 <= row, col <= 2 * 104
4 <= row * col <= 2 * 104
cells.length == row * col
1 <= ri <= row
1 <= ci <= col
cells 中的所有格子坐标都是 唯一 的。
二分查找分析
时间复杂度
O(nlogn) ,二分查找O(logn),并集查找O(n)。
分析
随着天数的增大,逐步从能过变成不能过。左闭右开空间。
并集查找的时候只需要连接左边和上边。第一行下移,就是第二行上移。
代码
核心代码
class Solution {
public:
int latestDayToCross(int row, int col, vector<vector>& cells) {
m_r = row;
m_c = col;
int left = 0, right = m_r * m_c ;
while (right - left > 1)
{
const auto mid = left + (right - left) / 2;
vector<vector> mat(row, vector(col));
for (int i = 0; i < mid; i++)
{
mat[cells[i][0]-1][cells[i][1]-1] = 1;
}
if (Can(mat))
{
left = mid;
}
else
{
right = mid;
}
}
return left;
}
bool Can(const vector<vector>& mat)
{
const int n = m_r*m_c;
CUnionFind uf(n + 2);
for (int r = 0; r < m_r; r++)
{
for (int c = 0; c < m_c; c++)
{
if (1 == mat[r][c])
{
continue;
}
if ((0 != r) && (0 == mat[r - 1][c]))
{
uf.Union(r * m_c + c, (r - 1) * m_c + c);
}
if ((0 != c) && (0 == mat[r][c - 1]))
{
uf.Union(r * m_c + c, r * m_c + c - 1);
}
}
}
for (int c = 0; c < m_c; c++)
{
if (0 == mat[0][c])
{
uf.Union(n, c);
}
if (0 == mat[m_r - 1][c])
{
uf.Union(n+1, (m_r - 1) * m_c + c);
}
}
return uf.IsConnect(n, n + 1);
}
int m_r,m_c;
};
测试用例
template
void Assert(const vector& v1, const vector& v2)
{
if (v1.size() != v2.size())
{
assert(false);
return;
}
for (int i = 0; i < v1.size(); i++)
{
assert(v1[i] == v2[i]);
}
}
template
void Assert(const T& t1, const T& t2)
{
assert(t1 == t2);
}
int main()
{
int row, col, res;
vector<vector> cells;
{
row = 2, col = 2, cells = { {1,1},{2,1},{1,2},{2,2} };
Solution slu;
auto res = slu.latestDayToCross(row, col, cells);
Assert(2, res);
}
{
row = 2, col = 2, cells = { {1,1},{1,2},{2,1},{2,2} };
Solution slu;
auto res = slu.latestDayToCross(row, col, cells);
Assert(1, res);
}
{
row = 6, col = 2, cells = { {4, 2}, { 6,2 }, { 2,1 }, { 4,1 }, { 6,1 }, { 3,1 }, { 2,2 }, { 3,2 }, { 1,1 }, { 5,1 }, { 5,2 }, { 1,2 } };
Solution slu;
auto res = slu.latestDayToCross(row, col, cells);
Assert(3, res);
}
//CConsole::Out(res);
}
逆序思考
反向思考:水慢慢变成陆地,最晚什么时候连通陆地。
时间复杂度😮(n)
代码
class CUnionFind
{
public:CUnionFind(int iSize) :m_vNodeToRegion(iSize){for (int i = 0; i < iSize; i++){m_vNodeToRegion[i] = i;}m_iConnetRegionCount = iSize;}int GetConnectRegionIndex(int iNode){int& iConnectNO = m_vNodeToRegion[iNode];if (iNode == iConnectNO){return iNode;}return iConnectNO = GetConnectRegionIndex(iConnectNO);}void Union(int iNode1, int iNode2){const int iConnectNO1 = GetConnectRegionIndex(iNode1);const int iConnectNO2 = GetConnectRegionIndex(iNode2);if (iConnectNO1 == iConnectNO2){return;}m_iConnetRegionCount--;if (iConnectNO1 > iConnectNO2){UnionConnect(iConnectNO1, iConnectNO2);}else{UnionConnect(iConnectNO2, iConnectNO1);}}bool IsConnect(int iNode1, int iNode2){return GetConnectRegionIndex(iNode1) == GetConnectRegionIndex(iNode2);}int GetConnetRegionCount()const{return m_iConnetRegionCount;}vector<int> GetNodeCountOfRegion()//各联通区域的节点数量{const int iNodeSize = m_vNodeToRegion.size();vector<int> vRet(iNodeSize);for (int i = 0; i < iNodeSize; i++){vRet[GetConnectRegionIndex(i)]++;}return vRet;}std::unordered_map<int, vector<int>> GetNodeOfRegion(){std::unordered_map<int, vector<int>> ret;const int iNodeSize = m_vNodeToRegion.size();for (int i = 0; i < iNodeSize; i++){ret[GetConnectRegionIndex(i)].emplace_back(i);}return ret;}
private:void UnionConnect(int iFrom, int iTo){m_vNodeToRegion[iFrom] = iTo;}vector<int> m_vNodeToRegion;//各点所在联通区域的索引,本联通区域任意一点的索引,为了增加可理解性,用最小索引int m_iConnetRegionCount;
};class Solution {
public:int latestDayToCross(int row, int col, vector<vector<int>>& cells) {m_r = row;m_c = col;const int n = m_r * m_c;CUnionFind uf(n + 2);for (int c = 0; c < m_c; c++){uf.Union(n, c);uf.Union(n + 1, (m_r - 1) * m_c + c);}vector<vector<int>> mat(row, vector<int>(col,1));for (int i = cells.size() - 1; i >= 0; i--){const int r = cells[i][0] - 1;const int c = cells[i][1] - 1;mat[r][c] = 0;auto Add = [&](const int rNew, const int cNew){if ((rNew < 0) || (rNew >= m_r)){return;}if ((cNew < 0) || (cNew >= m_c)){return;}if (0 == mat[rNew][cNew]){uf.Union(r * m_c + c, rNew * m_c + cNew);}};Add(r + 1, c);Add(r - 1, c);Add(r, c - 1);Add(r, c + 1);if (uf.IsConnect(n, n + 1)){return i ;}} return 0;}int m_r,m_c;
};
2023年3月旧代码
class Solution {
public:
int latestDayToCross(int row, int col, vector<vector>& cells) {
m_r = row;
m_c = col;
int left = 0,r = cells.size()+1 ;
while (r > left + 1)
{
int iMid = left + (r - left) / 2;
vector<vector> mat(m_r, vector(m_c));
for (int i = 0; i < iMid; i++)
{
mat[cells[i][0]-1][cells[i][1]-1] = 1;
}
if (bfs(mat))
{
left = iMid;
}
else
{
r = iMid;
}
}
return left;
}
bool bfs(const vector<vector>& mat)
{
std::queue<std::pair<int, int>> queCanViste;
std::unordered_map<int, std::unordered_set> setDo;
for (int c = 0; c < m_c; c++)
{
Add(queCanViste, setDo, 0, c, mat);
}
while (queCanViste.size())
{
const int r = queCanViste.front().first;
const int c = queCanViste.front().second;
if (r == m_r - 1)
{
return true;
}
queCanViste.pop();
Add(queCanViste, setDo, r+1, c, mat);
Add(queCanViste, setDo, r-1, c, mat);
Add(queCanViste, setDo, r , c+1, mat);
Add(queCanViste, setDo, r, c-1, mat);
}
return false;
}
void Add(std::queue<std::pair<int, int>>& queCanViste, std::unordered_map<int, std::unordered_set>& setDo, int r, int c,const vector<vector>& mat)
{
if ((r < 0) || (r >= m_r))
{
return;
}
if ((c<0) || (c >=m_c))
{
return;
}
if (1 == mat[r][c])
{
return;
}
if (setDo[r].count©)
{
return;
}
queCanViste.emplace(r, c);
setDo[r].emplace©;
}
int m_r, m_c;
};
2023年9月旧代码
class Solution {
public:
int latestDayToCross(int row, int col, vector<vector>& cells) {
m_c = col;
int iMaskNum = row * col;
vector<vector> grid(row, vector(col));
for (auto& v : cells)
{
v[0]–;
v[1]–;
grid[v[0]][v[1]] = 1;
}
CUnionFind uf(iMaskNum+2);//增加两个特殊端点; iMaskNum 连接所有第0行 iMaskNum+1 连接多有最后一行
auto Add = [&row,this,&grid,&uf](int iMask, int r, int c)
{
if ((r < 0) || (r >= row))
{
return;
}
if ((c < 0) || (c >= m_c))
{
return;
}
if (1 == grid[r][c])
{
return;
}
uf.Union(iMask, Mask(r, c));
};
for (int r = 0; r < row; r++)
{
for (int c = 0; c < m_c; c++)
{
if (1 == grid[r][c])
{
continue;
}
const int mask = Mask(r, c);
Add(mask, r + 1, c);
Add(mask, r, c + 1);
}
}
for (int c = 0; c < m_c; c++)
{
uf.Union(iMaskNum, Mask(0, c));
uf.Union(iMaskNum+1, Mask(row-1, c));
}
for (int i = cells.size() - 1; i >= 0; i–)
{
if (uf.IsConnect(iMaskNum, iMaskNum+1))
{
return i+1;
}
const auto& v = cells[i];
grid[v[0]][v[1]] = 0;
const int mask = Mask(v[0], v[1]);
Add(mask, v[0] + 1, v[1]);
Add(mask, v[0], v[1] + 1);
Add(mask, v[0] - 1, v[1]);
Add(mask, v[0], v[1] - 1);
}
return 0;
}
inline int Mask(int r, int c)
{
return r * m_c + c;
}
int m_c;
};
扩展阅读
视频课程
有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快
速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176
相关下载
想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653
我想对大家说的话 |
---|
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。 |
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。 |
如果程序是一条龙,那算法就是他的是睛 |
测试环境
操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境:
VS2022 C++17
相关文章:

【二分查找】LeetCode1970:你能穿过矩阵的最后一天
本文涉及的基础知识点 二分查找算法合集 作者推荐 动态规划LeetCode2552:优化了6版的1324模式 题目 给你一个下标从 1 开始的二进制矩阵,其中 0 表示陆地,1 表示水域。同时给你 row 和 col 分别表示矩阵中行和列的数目。 一开始在第 0 …...

利用python连接MySQL数据库并执行相关sql操作
一、新建MySQL数据库 1.启动MySQL服务 打开phpstudy,开启MySQL服务。如果开启失败的话,可以打开任务管理器,把正在运行的mysqld服务的进程进行关闭,再次打开MySQL服务即可启动。 2.新建MySQL数据库 选择数据库,点击…...
jenkins配置
branch: "dev" 切换分支 $WORKSPACE: /var/lib/jenkins/workspace/jenkins任务名 dest_passwd服务器密码 变量 sudo sshpass -p $dest_passwd ssh root192.168.211.319 -tt rm -rf /data/patent/*:删除文件/data/patent/* sudo sshpa…...

LeNet对MNIST 数据集中的图像进行分类--keras实现
我们将训练一个卷积神经网络来对 MNIST 数据库中的图像进行分类,可以与前面所提到的CNN实现对比CNN对 MNIST 数据库中的图像进行分类-CSDN博客 加载 MNIST 数据库 MNIST 是机器学习领域最著名的数据集之一。 它有 70,000 张手写数字图像 - 下载非常简单 - 图像尺…...
Django的回顾的第4天
1.模型层 1.1简介 你可能已经注意到我们在例子视图中返回文本的方式有点特别。 也就是说,HTML被直接硬编码在 Python代码之中。 def current_datetime(request):now datetime.datetime.now()html "<html><body>It is now %s.</body><…...
点云从入门到精通技术详解100篇-基于三维点云的工件曲面轮廓检测与机器人打磨轨迹规划(中)
目录 2.2.2 散乱点云滤波去噪 2.2.3 海量点云数据压缩 2.3 点云采集与预处理实验...

Mapper文件夹在resource目录下但是网页报错找不到productMapper.xml文件的解决
报错如下: 我的Mapper文件夹在resourse目录下但是网页报错找不到productMapper.xml。 结构如下:代码如下:<mappers><mapper resource"com/dhu/mapper/productMapper.xml" /> </mappers> 这段代码是在mybatis-co…...
22.Oracle中的临时表空间
Oracle中的临时表空间 一、临时表空间概述1、什么是临时表空间2、临时表空间的作用 二、临时表空间相关语法三、具体使用案例1、具体使用场景示例2、具体使用场景代码示例 点击此处跳转下一节:23.Oracle11g的UNDO表空间点击此处跳转上一节:21.Oracle的程…...

附录A 指令集基本原理
1. 引言 本书主要关注指令集体系结构4个主题: 1. 提出对指令集进行分类的方法,并对各种方法的优缺点进行定性评估; 2. 提出并分析一些在很大程度上独立于特定指令集的指令集评估数据。 3. 讨论语言与编译器议题以及…...

Unittest单元测试之unittest用例执行顺序
unittest用例执行顺序 当在一个测试类或多个测试模块下,用例数量较多时,unittest在执行用例 (test_xxx)时,并不是按从上到下的顺序执行,有特定的顺序。 unittest框架默认根据ACSII码的顺序加载测试用例&a…...

海云安谢朝海:开发安全领域大模型新实践 人工智能助力高效安全左移
2023年11月29日,2023中国(深圳)金融科技大会成功举行,该会议是深圳连续举办的第七届金融科技主题年度会议,也是2023深圳国际金融科技节重要活动之一。做好金融工作,需要兼顾创新与安全,当智能体…...

Postman接口测试工具完整教程
前言 作为软件开发过程中一个非常重要的环节,软件测试越来越成为软件开发商和用户关注的焦点。完善的测试是软件质量的保证,因此软件测试就成了一项重要而艰巨的工作。要做好这项工作当然也绝非易事。 第一部分:基础篇 postman:4.5.1 1.安…...

Android 滑动按钮(开关) SwitchCompat 自定义风格
原生的SwitchCompat控件如下图,不说不堪入目,也算是不敢恭维了。开个玩笑... 所以我们就需要对SwitchCompat进行自定义风格,效果如下图 代码如下 <androidx.appcompat.widget.SwitchCompatandroid:id"id/switch_compat"android:…...
前端面试灵魂提问-计网(2)
1、websocket 为什么全双工? 1.1 WebSocket是什么 WebSocket 是一种通信协议,它在客户端和服务器之间建立持久的全双工连接。全双工意味着数据可以双向流动,即客户端可以向服务器发送消息,服务器也可以向客户端发送消息,而无需…...

Git修改远程仓库名称
1、先直接在远程点仓库名,然后左侧菜单栏找settings-general,然后直接修改工程名,保存即可。 2、还是在settings-general下,下拉找到Advanced点击Expand展开,然后下拉到最底部 在Change path里填入新的项目名称&#x…...

kafka 集群 ZooKeeper 模式搭建
Apache Kafka是一个开源分布式事件流平台,被数千家公司用于高性能数据管道、流分析、数据集成和关键任务应用程序 Kafka 官网:Apache Kafka 关于ZooKeeper的弃用 根据 Kafka官网信息,随着Apache Kafka 3.5版本的发布,Zookeeper现…...

【LeetCode】 160. 相交链表
相交链表 题目题解 题目 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。 图示两个链表在节点 c1 开始相交: 题目数据 保证 整个链式结构中不存在环。 注意&am…...

TZOJ 1429 小明A+B
答案: #include <stdio.h> int main() {int T0, A0, B0, sum0;scanf("%d", &T); //输入测试数据的组数while (T--) //循环T次{scanf("%d %d", &A, &B); //输入AB的值sum A B;if (sum > 100) //如果是三位数{…...
制作openeuler的livecd
下载该项目,执行下面的操作gitee openeuler livecd项目 基于openeuler环境 #安装工具,第一次可能报错,可以再执行一次 make installx86 livecd-creator -d -v --config./config/euler_x86_64.ks --fslabeleuler-LiveCD --cachecache --log…...

B.牛牛排队伍——模拟双链表
当前位置: 首页 > news >正文 B.牛牛排队伍——模拟双链表 news 2023/12/1 15:14:37 分析 题目其实很简单,就是双链表的增删查,但是刚开始,直接vis标记删除元素,查找一个位置的前一个用的while不断向前找,但是TLE;毕竟O(n*k)的复杂度,一开始没有考虑时间复杂度…...

7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...

【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
Kafka主题运维全指南:从基础配置到故障处理
#作者:张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1:主题删除失败。常见错误2:__consumer_offsets占用太多的磁盘。 主题日常管理 …...
【SpringBoot自动化部署】
SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一,能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时,需要添加Git仓库地址和凭证,设置构建触发器(如GitHub…...

Matlab实现任意伪彩色图像可视化显示
Matlab实现任意伪彩色图像可视化显示 1、灰度原始图像2、RGB彩色原始图像 在科研研究中,如何展示好看的实验结果图像非常重要!!! 1、灰度原始图像 灰度图像每个像素点只有一个数值,代表该点的亮度(或…...
Windows 下端口占用排查与释放全攻略
Windows 下端口占用排查与释放全攻略 在开发和运维过程中,经常会遇到端口被占用的问题(如 8080、3306 等常用端口)。本文将详细介绍如何通过命令行和图形化界面快速定位并释放被占用的端口,帮助你高效解决此类问题。 一、准…...

Redis上篇--知识点总结
Redis上篇–解析 本文大部分知识整理自网上,在正文结束后都会附上参考地址。如果想要深入或者详细学习可以通过文末链接跳转学习。 1. 基本介绍 Redis 是一个开源的、高性能的 内存键值数据库,Redis 的键值对中的 key 就是字符串对象,而 val…...