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

相关文章

Python在二进制文件中进行数据搜索的实战指南

《Python在二进制文件中进行数据搜索的实战指南》在二进制文件中搜索特定数据是编程中常见的任务,尤其在日志分析、程序调试和二进制数据处理中尤为重要,下面我们就来看看如何使用Python实现这一功能吧... 目录简介1. 二进制文件搜索概述2. python二进制模式文件读取(rb)2.1 二进制模式与文本

利用c++判断水仙花数并输出示例代码

《利用c++判断水仙花数并输出示例代码》水仙花数是指一个三位数,其各位数字的立方和恰好等于该数本身,:本文主要介绍利用c++判断水仙花数并输出的相关资料,文中通过代码介绍的非常详细,需要的朋友可以... 以下是使用C++实现的相同逻辑代码:#include <IOStream>#include <vec

基于C++的UDP网络通信系统设计与实现详解

《基于C++的UDP网络通信系统设计与实现详解》在网络编程领域,UDP作为一种无连接的传输层协议,以其高效、低延迟的特性在实时性要求高的应用场景中占据重要地位,下面我们就来看看如何从零开始构建一个完整... 目录前言一、UDP服务器UdpServer.hpp1.1 基本框架设计1.2 初始化函数Init详解

C++ 右值引用(rvalue references)与移动语义(move semantics)深度解析

《C++右值引用(rvaluereferences)与移动语义(movesemantics)深度解析》文章主要介绍了C++右值引用和移动语义的设计动机、基本概念、实现方式以及在实际编程中的应用,... 目录一、右值引用(rvalue references)与移动语义(move semantics)设计动机1

C++ move 的作用详解及陷阱最佳实践

《C++move的作用详解及陷阱最佳实践》文章详细介绍了C++中的`std::move`函数的作用,包括为什么需要它、它的本质、典型使用场景、以及一些常见陷阱和最佳实践,感兴趣的朋友跟随小编一起看... 目录C++ move 的作用详解一、一句话总结二、为什么需要 move?C++98/03 的痛点⚡C++

详解C++ 存储二进制数据容器的几种方法

《详解C++存储二进制数据容器的几种方法》本文主要介绍了详解C++存储二进制数据容器,包括std::vector、std::array、std::string、std::bitset和std::ve... 目录1.std::vector<uint8_t>(最常用)特点:适用场景:示例:2.std::arra

C++构造函数中explicit详解

《C++构造函数中explicit详解》explicit关键字用于修饰单参数构造函数或可以看作单参数的构造函数,阻止编译器进行隐式类型转换或拷贝初始化,本文就来介绍explicit的使用,感兴趣的可以... 目录1. 什么是explicit2. 隐式转换的问题3.explicit的使用示例基本用法多参数构造

C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解

《C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解》:本文主要介绍C++,C#,Rust,Go,Java,Python,JavaScript性能对比全面... 目录编程语言性能对比、核心优势与最佳使用场景性能对比表格C++C#RustGoJavapythonjav

C++打印 vector的几种方法小结

《C++打印vector的几种方法小结》本文介绍了C++中遍历vector的几种方法,包括使用迭代器、auto关键字、typedef、计数器以及C++11引入的范围基础循环,具有一定的参考价值,感兴... 目录1. 使用迭代器2. 使用 auto (C++11) / typedef / type alias

C++ scoped_ptr 和 unique_ptr对比分析

《C++scoped_ptr和unique_ptr对比分析》本文介绍了C++中的`scoped_ptr`和`unique_ptr`,详细比较了它们的特性、使用场景以及现代C++推荐的使用`uni... 目录1. scoped_ptr基本特性主要特点2. unique_ptr基本用法3. 主要区别对比4. u