【广度优先搜索】【堆】【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

相关文章

C++中实现调试日志输出

《C++中实现调试日志输出》在C++编程中,调试日志对于定位问题和优化代码至关重要,本文将介绍几种常用的调试日志输出方法,并教你如何在日志中添加时间戳,希望对大家有所帮助... 目录1. 使用 #ifdef _DEBUG 宏2. 加入时间戳:精确到毫秒3.Windows 和 MFC 中的调试日志方法MFC

Python中的随机森林算法与实战

《Python中的随机森林算法与实战》本文详细介绍了随机森林算法,包括其原理、实现步骤、分类和回归案例,并讨论了其优点和缺点,通过面向对象编程实现了一个简单的随机森林模型,并应用于鸢尾花分类和波士顿房... 目录1、随机森林算法概述2、随机森林的原理3、实现步骤4、分类案例:使用随机森林预测鸢尾花品种4.1

深入理解C++ 空类大小

《深入理解C++空类大小》本文主要介绍了C++空类大小,规定空类大小为1字节,主要是为了保证对象的唯一性和可区分性,满足数组元素地址连续的要求,下面就来了解一下... 目录1. 保证对象的唯一性和可区分性2. 满足数组元素地址连续的要求3. 与C++的对象模型和内存管理机制相适配查看类对象内存在C++中,规

在 VSCode 中配置 C++ 开发环境的详细教程

《在VSCode中配置C++开发环境的详细教程》本文详细介绍了如何在VisualStudioCode(VSCode)中配置C++开发环境,包括安装必要的工具、配置编译器、设置调试环境等步骤,通... 目录如何在 VSCode 中配置 C++ 开发环境:详细教程1. 什么是 VSCode?2. 安装 VSCo

C++11的函数包装器std::function使用示例

《C++11的函数包装器std::function使用示例》C++11引入的std::function是最常用的函数包装器,它可以存储任何可调用对象并提供统一的调用接口,以下是关于函数包装器的详细讲解... 目录一、std::function 的基本用法1. 基本语法二、如何使用 std::function

C# ComboBox下拉框实现搜索方式

《C#ComboBox下拉框实现搜索方式》文章介绍了如何在加载窗口时实现一个功能,并在ComboBox下拉框中添加键盘事件以实现搜索功能,由于数据不方便公开,作者表示理解并希望得到大家的指教... 目录C# ComboBox下拉框实现搜索步骤一步骤二步骤三总结C# ComboBox下拉框实现搜索步骤一这

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

认识、理解、分类——acm之搜索

普通搜索方法有两种:1、广度优先搜索;2、深度优先搜索; 更多搜索方法: 3、双向广度优先搜索; 4、启发式搜索(包括A*算法等); 搜索通常会用到的知识点:状态压缩(位压缩,利用hash思想压缩)。

hdu1240、hdu1253(三维搜索题)

1、从后往前输入,(x,y,z); 2、从下往上输入,(y , z, x); 3、从左往右输入,(z,x,y); hdu1240代码如下: #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#inc