【广度优先搜索】【堆】【C++算法】407. 接雨水 II

2024-03-06 22:52

本文主要是介绍【广度优先搜索】【堆】【C++算法】407. 接雨水 II,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

作者推荐

【二分查找】【C++算法】378. 有序矩阵中第 K 小的元素

本文涉及知识点

广度优先搜索 堆

LeetCoce407. 接雨水 II

给你一个 m x n 的矩阵,其中的值均为非负整数,代表二维高度图每个单元的高度,请计算图中形状最多能接多少体积的雨水。
示例 1:
在这里插入图片描述

输入: heightMap = [[1,4,3,1,3,2],[3,2,1,3,2,4],[2,3,3,2,3,1]]
输出: 4
解释: 下雨后,雨水将会被上图蓝色的方块中。总的接雨水量为1+2+1=4。
示例 2:
在这里插入图片描述

输入: heightMap = [[3,3,3,3,3],[3,2,2,2,3],[3,2,1,2,3],[3,2,2,2,3],[3,3,3,3,3]]
输出: 10
提示:
m == heightMap.length
n == heightMap[i].length
1 <= m, n <= 200
0 <= heightMap[i][j] <= 2 * 104

广度优先搜索

vHeight记录各单格包括水的高度,初始为-1,表示未处理。四周边界显然无法留住水,所以四周边界的vHeight等于heightMap。
不断处理vHeight最小单格(r,c)的邻接单格(nr,nc) vHeight[nr][nc] = max(vHeight[r][c],heightMap[nr][nc]。
边界全部在已处理格子中。
{ 不会做什么 已处理格子的邻居都已经处理 不是边界 处理邻居 已处理格子有邻居未处理 边界 \begin{cases} 不会做什么 & 已处理格子的邻居都已经处理 & 不是边界 \\ 处理邻居 & 已处理格子有邻居未处理 & 边界\\ \end{cases} {不会做什么处理邻居已处理格子的邻居都已经处理已处理格子有邻居未处理不是边界边界
假定h1是边界最低vHeight,则任意未处理单格的水达到h1时,都不会流出。
h1所在单格的邻居水不会超过h1,否则会流到h1所在单格。

代码

核心代码

class CEnumGridEdge
{
public:void Init(){for (int r = 0; r < m_r; r++){for (int c = 0; c < m_c; c++){Move(r, c, r + 1, c);Move(r, c, r - 1, c);Move(r, c, r, c + 1);Move(r, c, r, c - 1);}}}const int m_r, m_c;
protected:CEnumGridEdge(int r, int c) :m_r(r), m_c(c){}void Move(int preR, int preC, int r, int c){if ((r < 0) || (r >= m_r)){return;}if ((c < 0) || (c >= m_c)){return;}OnEnumEdge(preR, preC, r, c);};virtual void OnEnumEdge(int preR, int preC, int r, int c) = 0;
};class TNeiBoForGrid : public CEnumGridEdge
{
public:TNeiBoForGrid(const vector<vector<int>>& grid) :m_grid(grid),CEnumGridEdge(grid.size(), grid.front().size()){m_vNext.assign(m_r, vector < vector<pair<int, int>>>(m_c));Init();}virtual void OnEnumEdge(int preR, int preC, int r, int c){	m_vNext[preR][preC].emplace_back(r, c);}const vector<vector<int>>& m_grid;vector < vector < vector<pair<int, int>>>> m_vNext;
};
class Solution {
public:int trapRainWater(vector<vector<int>>& heightMap) {TNeiBoForGrid neiBo(heightMap);vector<vector<int>> vHeight(neiBo.m_r, vector<int>(neiBo.m_c, -1));priority_queue<tuple<int, int, int>, vector<tuple<int, int, int>>, greater<>> minHeap;auto Add = [&](int r, int c, int iHeight){if (vHeight[r][c] >= 0){return;}vHeight[r][c] = iHeight;minHeap.emplace(iHeight, r, c);};for (int r = 0; r < neiBo.m_r; r++){for (int c = 0; c < neiBo.m_c; c++){if ((0 == r) || (neiBo.m_r == r + 1) || (0 == c) || (neiBo.m_c == c + 1)){Add(r, c, heightMap[r][c]);}}}while (minHeap.size()){auto [height, r, c] = minHeap.top();minHeap.pop();for (const auto& [nr, nc] : neiBo.m_vNext[r][c]){Add(nr, nc, max(height, heightMap[nr][nc]));}}int iRet = 0;for (int r = 0; r < neiBo.m_r; r++){iRet += std::accumulate(vHeight[r].begin(), vHeight[r].end(), 0) - std::accumulate(heightMap[r].begin(), heightMap[r].end(), 0);}return iRet;}};

测试用例

template<class T,class T2>
void Assert(const T& t1, const T2& t2)
{assert(t1 == t2);
}template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{if (v1.size() != v2.size()){assert(false);return;}for (int i = 0; i < v1.size(); i++){Assert(v1[i], v2[i]);}}int main()
{vector<vector<int>> heightMap;{Solution sln;heightMap = { {1,4,3,1,3,2},{3,2,1,3,2,4},{2,3,3,2,3,1} };auto res = sln.trapRainWater(heightMap);Assert(4, res);}{Solution sln;heightMap = { {3,3,3,3,3},{3,2,2,2,3},{3,2,1,2,3},{3,2,2,2,3},{3,3,3,3,3} };auto res = sln.trapRainWater(heightMap);Assert(10, res);}}

2023年3月

class Solution {
public:
int trapRainWater(vector<vector>& heightMap) {
m_r = heightMap.size();
m_c = heightMap[0].size();
//memset(m_arrNeiNum, 4, sizeof(m_arrNeiNum));
for (int c = 0; c < m_c; c++)
{
//m_arrNeiNum[0][c] = 1;
//m_arrNeiNum[m_r - 1][c] = 1;
AddRowColToRange(0, c, heightMap);
AddRowColToRange(m_r-1, c, heightMap);
}
for (int r = 1; r + 1 < m_r; r++)
{
AddRowColToRange(r,0, heightMap);
AddRowColToRange(r,m_c-1, heightMap);
//m_arrNeiNum[r][0] = 1;
//m_arrNeiNum[r][m_c - 1] = 1;
}
while (m_mHeightRowCol.size())
{
const int iHeight = m_mHeightRowCol.begin()->first;
const int r = m_mHeightRowCol.begin()->second / 1000;
const int c = m_mHeightRowCol.begin()->second % 1000;
Add(r + 1, c, iHeight,heightMap);
Add(r - 1, c, iHeight, heightMap);
Add(r, c + 1, iHeight, heightMap);
Add(r, c - 1, iHeight, heightMap);
m_mHeightRowCol.erase(m_mHeightRowCol.begin());
}
return m_iRet;
}
void Add(int r, int c, int iPreHeight, const vector<vector>& heightMap)
{
if ((r < 0) || (r >= m_r))
{
return;
}
if ((c < 0) || (c >= m_c))
{
return;
}
if (m_setHasDo.count(RowColMask(r,c)))
{
return;
}
const int iCurHeight = heightMap[r][c];
const int iWaterHeight = max(iCurHeight, iPreHeight);
if (iWaterHeight > iCurHeight)
{
m_iRet += iWaterHeight - iCurHeight;
}
AddRowColToRange(r, c, iWaterHeight);
}
void AddRowColToRange(int r, int c, const int iWaterHeight)
{
const int iRowCol = RowColMask(r, c);
m_mHeightRowCol.emplace(iWaterHeight, iRowCol);
m_setHasDo.insert(iRowCol);
}
void AddRowColToRange(int r, int c,const vector<vector>& heightMap)
{
AddRowColToRange(r, c, heightMap[r][c]);
}
inline int RowColMask(int r, int c)
{
return 1000 * r + c;
}
int m_r;
int m_c;
std::multimap<int, int> m_mHeightRowCol;//记录当前边界
std::unordered_set m_setHasDo;//记录已经处理的格子
std::unordered_set m_setNeiHasDo;//记录相邻格子已经处理完毕
//char m_arrNeiNum[200][200];//记录邻居数
int m_iRet = 0;

};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步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
如无特殊说明,本算法用**C++**实现。

这篇关于【广度优先搜索】【堆】【C++算法】407. 接雨水 II的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/781625

相关文章

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

C++ 中的 if-constexpr语法和作用

《C++中的if-constexpr语法和作用》if-constexpr语法是C++17引入的新语法特性,也被称为常量if表达式或静态if(staticif),:本文主要介绍C++中的if-c... 目录1 if-constexpr 语法1.1 基本语法1.2 扩展说明1.2.1 条件表达式1.2.2 fa

Java时间轮调度算法的代码实现

《Java时间轮调度算法的代码实现》时间轮是一种高效的定时调度算法,主要用于管理延时任务或周期性任务,它通过一个环形数组(时间轮)和指针来实现,将大量定时任务分摊到固定的时间槽中,极大地降低了时间复杂... 目录1、简述2、时间轮的原理3. 时间轮的实现步骤3.1 定义时间槽3.2 定义时间轮3.3 使用时

C++中::SHCreateDirectoryEx函数使用方法

《C++中::SHCreateDirectoryEx函数使用方法》::SHCreateDirectoryEx用于创建多级目录,类似于mkdir-p命令,本文主要介绍了C++中::SHCreateDir... 目录1. 函数原型与依赖项2. 基本使用示例示例 1:创建单层目录示例 2:创建多级目录3. 关键注

C++从序列容器中删除元素的四种方法

《C++从序列容器中删除元素的四种方法》删除元素的方法在序列容器和关联容器之间是非常不同的,在序列容器中,vector和string是最常用的,但这里也会介绍deque和list以供全面了解,尽管在一... 目录一、简介二、移除给定位置的元素三、移除与某个值相等的元素3.1、序列容器vector、deque

C++常见容器获取头元素的方法大全

《C++常见容器获取头元素的方法大全》在C++编程中,容器是存储和管理数据集合的重要工具,不同的容器提供了不同的接口来访问和操作其中的元素,获取容器的头元素(即第一个元素)是常见的操作之一,本文将详细... 目录一、std::vector二、std::list三、std::deque四、std::forwa

C++字符串提取和分割的多种方法

《C++字符串提取和分割的多种方法》在C++编程中,字符串处理是一个常见的任务,尤其是在需要从字符串中提取特定数据时,本文将详细探讨如何使用C++标准库中的工具来提取和分割字符串,并分析不同方法的适用... 目录1. 字符串提取的基本方法1.1 使用 std::istringstream 和 >> 操作符示

C++原地删除有序数组重复项的N种方法

《C++原地删除有序数组重复项的N种方法》给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度,不要使用额外的数组空间,你必须在原地修改输入数组并在使用O(... 目录一、问题二、问题分析三、算法实现四、问题变体:最多保留两次五、分析和代码实现5.1、问题分析5.

C++ 各种map特点对比分析

《C++各种map特点对比分析》文章比较了C++中不同类型的map(如std::map,std::unordered_map,std::multimap,std::unordered_multima... 目录特点比较C++ 示例代码 ​​​​​​代码解释特点比较1. std::map底层实现:基于红黑

C++中函数模板与类模板的简单使用及区别介绍

《C++中函数模板与类模板的简单使用及区别介绍》这篇文章介绍了C++中的模板机制,包括函数模板和类模板的概念、语法和实际应用,函数模板通过类型参数实现泛型操作,而类模板允许创建可处理多种数据类型的类,... 目录一、函数模板定义语法真实示例二、类模板三、关键区别四、注意事项 ‌在C++中,模板是实现泛型编程