⭐算法入门⭐《广度优先搜索》中等01 —— LeetCode 994. 腐烂的橘子
C語言免費動漫教程,和我一起打卡! 🌞《光天化日學C語言》🌞
LeetCode 太難?先看簡單題! 🧡《C語言入門100例》🧡
數據結構難?不存在的! 🌳《數據結構入門》🌳
LeetCode 太簡單?算法學起來! 🌌《夜深人靜寫算法》🌌
文章目錄
- 一、題目
- 1、題目描述
- 2、基礎框架
- 3、原題鏈接
- 二、解題報告
- 1、思路分析
- 2、時間復雜度
- 3、代碼詳解
- 三、本題小知識
- 四、加群須知
一、題目
1、題目描述
在給定的網格中,每個單元格可以有以下三個值之一:
??1)值 0 代表空單元格;
??2)值 1 代表新鮮橘子;
??3)值 2 代表腐爛的橘子。
每分鐘,任何與腐爛的橘子(在 4 個正方向上)相鄰的新鮮橘子都會腐爛。返回直到單元格中沒有新鮮橘子為止所必須經過的最小分鐘數。如果不可能,返回 -1。
??樣例輸入:[211110011]\left[ \begin{matrix} 2 & 1 & 1 \\ 1 & 1 & 0 \\ 0 & 1 & 1\end{matrix} \right]???210?111?101????
??樣例輸出: 4
2、基礎框架
- c++ 版本給出的基礎框架代碼如下:
- vector<vector<int>>& grid代表的是一個二維數組,用來代表二維矩陣的橘子位置,&作為引用,用來加速參數傳遞。
- 返回值是一個int,代表哪個時刻下所有橘子都腐爛了。
3、原題鏈接
LeetCode 994. 腐爛的橘子
二、解題報告
1、思路分析
??首先,將所有腐爛的橘子(值為 2 的格子)的位置進行哈希(標記訪問時間為 0),然后壓入隊列。利用廣搜,擴散范圍。對于相鄰的格子,如下幾種情況分別處理:
??1)格子沒有被訪問過,且遇到一個新鮮橘子(值為 1 的格子),哈希后壓入隊列,并且標記格子的訪問時間為相鄰那個擴散到它的格子的訪問時間 + 1。
??2)格子沒有被訪問過,且遇到空位置,不做任何處理;
??3)格子被訪問過,不做任何處理;
搜索完畢,遍歷所有格子,如果存在新鮮橘子,返回 -1;否則,取最訪問時間最大的進行返回。
- 廣搜的更多內容,可以參考這篇文章:夜深人靜寫算法(十)- 單向廣搜。
2、時間復雜度
- 對于一個 n×mn \times mn×m 的矩陣,每個元素只會訪問一次,時間復雜度為 O(nm)O(nm)O(nm)。
3、代碼詳解
int dir[4][2] = {{0, 1}, // right{1, 0}, // down{0, -1}, // left{-1, 0}, // up };const int maxn = 120;class Solution {int n, m;int visited[maxn];queue <int> que;int getVisitedId(int x, int y) { // (1)return x * m + y;}void getPosByVisitedId(int visitedId, int &x, int &y) { // (2)x = visitedId / m;y = visitedId % m;}void init(vector<vector<int>>& mat) {while(!que.empty()) { // (3)que.pop();}memset(visited, -1, sizeof(visited)); // (4)n = mat.size(); // (5)m = mat[0].size(); // (6)for(int i = 0; i < n; ++i) {for(int j = 0; j < m; ++j) {if(2 == mat[i][j]) { // (7)visited[ getVisitedId(i, j) ] = 0; que.push( getVisitedId(i, j) );}}}}bool outOfBound(int x, int y) {return x < 0 || x >= n || y < 0 || y >= m; }void bfs(vector<vector<int>>& mat) {while(!que.empty()) {int vid = que.front(); // (8)int x, y;getPosByVisitedId(vid, x, y); // (9)que.pop();for(int i = 0; i < 4; ++i) { // (10)int tx = x + dir[i][0];int ty = y + dir[i][1];if(outOfBound(tx, ty)) {continue;}int nextvid = getVisitedId(tx, ty); // (11)if(mat[tx][ty] == 1 && visited[nextvid] == -1) { visited[nextvid] = visited[vid] + 1; que.push(nextvid);}}}}int output(int *visited, vector<vector<int>>& mat) { int maxv = 0;for(int i = 0; i < n; ++i) {vector <int> ans;for(int j = 0; j < m; ++j) {int vid = getVisitedId(i, j);if(mat[i][j] == 1 && visited[ vid ] == -1) { return -1; // (12)}if( visited[ vid ] > maxv ) {maxv = visited[ vid ]; // (13)}}}return maxv;} public:int orangesRotting(vector<vector<int>>& grid) {init(grid); bfs(grid);return output(visited, grid);} };- (1)(1)(1) 將二維向量映射到一維,方便索引;
- (2)(2)(2) 將一維向量拆解成二維,方便計算;
- (3)(3)(3) 定義的隊列為類私有成員,所以每次計算,初始化的時候需要首先進行清空;
- (4)(4)(4) 利用memset初始化將所有矩陣元素的標記位全部置為-1,關于memset更多用法,可以參考:《C/C++ 面試 100 例》(六)memset 全網最全總結;
- (5)(5)(5) 矩陣的行,保存成類的成員變量,方便成員函數使用;
- (6)(6)(6) 矩陣的列,保存成類的成員變量,方便成員函數使用;
- (7)(7)(7) 找到矩陣中所有的 2(腐爛的橘子),將標記為置為 0,代表腐爛的時刻為 0,然后塞入隊列;
- (8)(8)(8) 每次從隊列頭部彈出一個元素;
- (9)(9)(9) 將它轉換成坐標的形式,方便進行上下左右的運算;
- (10)(10)(10) 枚舉四個方向擴散;
- (11)(11)(11) 得到一個相鄰位置,如果這個位置沒有被訪問過,且值為 1 (代表新鮮橘子),則將步數置為 當前位置步數 + 1;
- (12)(12)(12) 搜索完畢,遍歷所有格子,如果存在新鮮橘子,返回 -1;
- (13)(13)(13) 否則,取最訪問時間最大的進行返回。
三、本題小知識
1)一維的vector可以當數組用,二維的vector可以當矩陣用。
2)利用memset可以將標記置為-1代表尚未訪問。
3)廣搜的過程,就是不斷把狀態壓入隊列尾,不斷取出隊列頭部狀態的過程,由于狀態可能是多維的,所以我們一般考慮將多維狀態變成一維,這個稱為序列化;再在彈出隊列的時候,將一維狀態還原成多維,這個稱為反序列化。一般就是通過進制轉換來完成。
四、加群須知
??相信看我文章的大多數都是「 大學生 」,能上大學的都是「 精英 」,那么我們自然要「 精益求精 」,如果你還是「 大一 」,那么太好了,你擁有大把時間,當然你可以選擇「 刷劇 」,然而,「 學好算法 」,三年后的你自然「 不能同日而語 」。
??那么這里,我整理了「 幾十個基礎算法 」 的分類,點擊開啟:
??如果鏈接被屏蔽,或者有權限問題,可以私聊作者解決。
??大致題集一覽:
??為了讓這件事情變得有趣,以及「 照顧初學者 」,目前題目只開放最簡單的算法 「 枚舉系列 」 (包括:線性枚舉、雙指針、前綴和、二分枚舉、三分枚舉),當有 一半成員刷完 「 枚舉系列 」 的所有題以后,會開放下個章節,等這套題全部刷完,你還在群里,那么你就會成為「 夜深人靜寫算法 」專家團 的一員。
??不要小看這個專家團,三年之后,你將會是別人 望塵莫及 的存在。如果要加入,可以聯系我,考慮到大家都是學生, 沒有「 主要經濟來源 」,在你成為神的路上,「 不會索取任何 」。
??🔥聯系作者,或者掃作者主頁二維碼加群,加入刷題行列吧🔥
🔥讓天下沒有難學的算法🔥
C語言免費動漫教程,和我一起打卡! 🌞《光天化日學C語言》🌞
入門級C語言真題匯總 🧡《C語言入門100例》🧡
幾張動圖學會一種數據結構 🌳《畫解數據結構》🌳
組團學習,抱團生長 🌌《算法入門指引》🌌
競賽選手金典圖文教程 💜《夜深人靜寫算法》💜
總結
以上是生活随笔為你收集整理的⭐算法入门⭐《广度优先搜索》中等01 —— LeetCode 994. 腐烂的橘子的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 线性同余法的伪随机数
- 下一篇: 【老生谈算法】matlab人脸识别算法(