BFS
- 原理
- 經典例題
- 解決FloodFill 算法
- [733. 圖像渲染](https://leetcode.cn/problems/flood-fill/description/)
- [200. 島嶼數量](https://leetcode.cn/problems/number-of-islands/description/)
- [695. 島嶼的最大面積](https://leetcode.cn/problems/max-area-of-island/description/)
- [130. 被圍繞的區域](https://leetcode.cn/problems/surrounded-regions/description/)
- 解決最短路徑問題
- [1926. 迷宮中離入口最近的出口](https://leetcode.cn/problems/nearest-exit-from-entrance-in-maze/description/)
- [433. 最小基因變化](https://leetcode.cn/problems/minimum-genetic-mutation/description/)
- [127. 單詞接龍](https://leetcode.cn/problems/word-ladder/description/)
- [675. 為高爾夫比賽砍樹](https://leetcode.cn/problems/cut-off-trees-for-golf-event/description/)
- 解決多源最短路徑問題
- [542. 01 矩陣](https://leetcode.cn/problems/01-matrix/description/)
- [1020. 飛地的數量](https://leetcode.cn/problems/number-of-enclaves/description/)
- [1765. 地圖中的最高點](https://leetcode.cn/problems/map-of-highest-peak/description/)
- [1162. 地圖分析](https://leetcode.cn/problems/as-far-from-land-as-possible/description/)
- 解決拓撲排序問題
- [207. 課程表](https://leetcode.cn/problems/course-schedule/description/)
- [210. 課程表 II](https://leetcode.cn/problems/course-schedule-ii/description/)
- [LCR 114. 火星詞典](https://leetcode.cn/problems/Jf1JuT/description/)
原理
圖有兩種遍歷算法:深度優先搜索(DFS)和廣度優先搜索(BFS),DFS就是先往深處走,直到無路可走就回溯從另一個方向繼續往深處走,BFS就是一圈一圈的往外擴張直至邊界為止。
正難則反原則:以a作為起點,b作為終點執行BFS算法可能難以得到結果,不妨嘗試一下以b作為起點a作為終點反向使用BFS。
經典例題
解決FloodFill 算法
FloodFill 算法即洪水灌溉算法,就是像洪水泛濫一樣找到一片連通的區域,
733. 圖像渲染
有一幅以 m x n 的二維整數數組表示的圖畫 image ,其中 image[i][j] 表示該圖畫的像素值大小。你也被給予三個整數 sr , sc 和 color 。你應該從像素 image[sr][sc] 開始對圖像進行上色 填充 。
為了完成 上色工作:
從初始像素開始,將其顏色改為 color。
對初始坐標的 上下左右四個方向上 相鄰且與初始像素的原始顏色同色的像素點執行相同操作。
通過檢查與初始像素的原始顏色相同的相鄰像素并修改其顏色來繼續 重復 此過程。
當 沒有 其它原始顏色的相鄰像素時 停止 操作。
最后返回經過上色渲染 修改 后的圖像 。
class Solution {
public:void GetAnswer(vector<vector<int>>& image, int sr, int sc, int color,int originColor){if(sr<0||sc<0||sr>=image.size()||sc>=image[0].size()||originColor!=image[sr][sc]){return;}image[sr][sc]=color;printf("%d %d\n",sr,sc);GetAnswer(image,sr-1,sc,color,originColor);GetAnswer(image,sr+1,sc,color,originColor);GetAnswer(image,sr,sc-1,color,originColor);GetAnswer(image,sr,sc+1,color,originColor);}vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int color) {if(color!=image[sr][sc]){GetAnswer(image,sr,sc,color,image[sr][sc]);}return image;}
};
200. 島嶼數量
給你一個由 ‘1’(陸地)和 ‘0’(水)組成的的二維網格,請你計算網格中島嶼的數量。
島嶼總是被水包圍,并且每座島嶼只能由水平方向和/或豎直方向上相鄰的陸地連接形成。
此外,你可以假設該網格的四條邊均被水包圍。
class Solution {
public:void Cover(vector<vector<char>>& grid,vector<vector<char>>& record,int i,int j){if(i<0||j<0||i>=grid.size()||j>=grid[0].size()||'0'==record[i][j]||'0'==grid[i][j]){return;}record[i][j]='0';Cover(grid,record,i+1,j);Cover(grid,record,i-1,j);Cover(grid,record,i,j+1);Cover(grid,record,i,j-1);}int numIslands(vector<vector<char>>& grid) {vector<vector<char>> record(grid.size(),vector<char>(grid[0].size(),'1'));int i=0;int ans=0;for(i=0;i<grid.size();++i){int j=0;for(j=0;j<grid[0].size();++j){if('1'==grid[i][j]&&'1'==record[i][j]){++ans;Cover(grid,record,i,j);}}}return ans;}
};
695. 島嶼的最大面積
給你一個大小為 m x n 的二進制矩陣 grid 。
島嶼 是由一些相鄰的 1 (代表土地) 構成的組合,這里的「相鄰」要求兩個 1 必須在 水平或者豎直的四個方向上 相鄰。你可以假設 grid 的四個邊緣都被 0(代表水)包圍著。
島嶼的面積是島上值為 1 的單元格的數目。
計算并返回 grid 中最大的島嶼面積。如果沒有島嶼,則返回面積為 0 。
class Solution {
public:int GetArea(vector<vector<int>>& grid,vector<vector<int>>& copyGrid,int row,int column){if(row<0||row>=grid.size()||column<0||column>=grid[0].size()||0==copyGrid[row][column]||0==grid[row][column]){return 0;}copyGrid[row][column]=0;int left=GetArea(grid,copyGrid,row,column-1);int right=GetArea(grid,copyGrid,row,column+1);int up=GetArea(grid,copyGrid,row-1,column);int down=GetArea(grid,copyGrid,row+1,column);return left+right+up+down+1;}int maxAreaOfIsland(vector<vector<int>>& grid) {vector<vector<int>> copyGrid(grid.size(),vector<int>(grid[0].size(),1));int maxArea=0;int i=0;for(;i<grid.size();++i){int j=0;for(;j<grid[0].size();++j){maxArea=max(maxArea,GetArea(grid,copyGrid,i,j));}}return maxArea;}
};
130. 被圍繞的區域
給你一個 m x n 的矩陣 board ,由若干字符 ‘X’ 和 ‘O’ 組成,捕獲 所有 被圍繞的區域:
連接:一個單元格與水平或垂直方向上相鄰的單元格連接。
區域:連接所有 ‘O’ 的單元格來形成一個區域。
圍繞:如果您可以用 ‘X’ 單元格 連接這個區域,并且區域中沒有任何單元格位于 board 邊緣,則該區域被 ‘X’ 單元格圍繞。
通過 原地 將輸入矩陣中的所有 ‘O’ 替換為 ‘X’ 來 捕獲被圍繞的區域。你不需要返回任何值。
class Solution {
public:bool IsSurround(vector<vector<char>>& board,vector<vector<int>>& copyBoard,int i,int j){if(0==copyBoard[i][j]){return true;}if('X'==board[i][j]||i==0||j==0||i+1==board.size()||j+1==board[0].size()){copyBoard[i][j]=0;if('X'==board[i][j]){return true;}return false;}copyBoard[i][j]=0;int left=IsSurround(board,copyBoard,i,j-1);int right=IsSurround(board,copyBoard,i,j+1);int up=IsSurround(board,copyBoard,i-1,j);int down=IsSurround(board,copyBoard,i+1,j);return left&&right&&up&&down;}void Replace(vector<vector<char>>& board,int i,int j){if('X'==board[i][j]){return;}board[i][j]='X';Replace(board,i-1,j);Replace(board,i+1,j);Replace(board,i,j-1);Replace(board,i,j+1);}void solve(vector<vector<char>>& board) {vector<vector<int>> copyBoard(board.size(),vector<int>(board[0].size(),1));int i=1;for(;i+1<board.size();++i){int j=1;for(;j+1<board[0].size();++j){if('O'==board[i][j]&&1==copyBoard[i][j]&&IsSurround(board,copyBoard,i,j)){Replace(board,i,j);}}}}
};
解決最短路徑問題
即找到一條從源點到目的地的最短路徑,解決辦法為從源點開始采用BFS一層一層往外擴張,直到擴張到目的地為止,此時就得到了最短路徑。
1926. 迷宮中離入口最近的出口
給你一個 m x n 的迷宮矩陣 maze (下標從 0 開始),矩陣中有空格子(用 ‘.’ 表示)和墻(用 ‘+’ 表示)。同時給你迷宮的入口 entrance ,用 entrance = [entrancerow, entrancecol] 表示你一開始所在格子的行和列。
每一步操作,你可以往 上,下,左 或者 右 移動一個格子。你不能進入墻所在的格子,你也不能離開迷宮。你的目標是找到離 entrance 最近 的出口。出口 的含義是 maze 邊界 上的 空格子。entrance 格子 不算 出口。
請你返回從 entrance 到最近出口的最短路徑的 步數 ,如果不存在這樣的路徑,請你返回 -1 。
class Solution {
public:bool Renew(vector<vector<char>>& maze,vector<vector<int>>& record,queue<vector<int>> &q,int i,int j,int& cur){if (0 > i || 0 > j || i == maze.size() || j == maze[0].size() || '+' == maze[i][j] || 0 == record[i][j]) {return false;}if(0 == i || 0 == j || i+1 == maze.size() || j+1 == maze[0].size()){return true;}record[i][j]=0;q.push({i,j});++cur;return false;}int nearestExit(vector<vector<char>>& maze, vector<int>& entrance) {vector<vector<int>> record(maze.size(),vector<int>(maze[0].size(),1));record[entrance[0]][entrance[1]]=0;queue<vector<int>> q;q.push(entrance);int d=1;int count=1;while(!q.empty()){int cur=0;while(count--){int i=q.front()[0];int j=q.front()[1];q.pop();int left=Renew(maze,record,q,i,j-1,cur);int right=Renew(maze,record,q,i,j+1,cur);int up=Renew(maze,record,q,i-1,j,cur);int down=Renew(maze,record,q,i+1,j,cur);if(left||right||up||down){return d;}}count=cur;++d;}return -1;}
};
433. 最小基因變化
基因序列可以表示為一條由 8 個字符組成的字符串,其中每個字符都是 ‘A’、‘C’、‘G’ 和 ‘T’ 之一。
假設我們需要調查從基因序列 start 變為 end 所發生的基因變化。一次基因變化就意味著這個基因序列中的一個字符發生了變化。
例如,“AACCGGTT” --> “AACCGGTA” 就是一次基因變化。
另有一個基因庫 bank 記錄了所有有效的基因變化,只有基因庫中的基因才是有效的基因序列。(變化后的基因必須位于基因庫 bank 中)
給你兩個基因序列 start 和 end ,以及一個基因庫 bank ,請你找出并返回能夠使 start 變化為 end 所需的最少變化次數。如果無法完成此基因變化,返回 -1 。
注意:起始基因序列 start 默認是有效的,但是它并不一定會出現在基因庫中。
class Solution {
public:void SToI(map<char,int>& mapOfCToI,string& s,vector<int>& res){int i=0;for(;i<8;++i){res.push_back(mapOfCToI[s[i]]);}}bool IsLegal(map<vector<int>,int>& mp,vector<int>& v){int i=0;for(;i<8;++i){auto it=mp.find(v);if(v[i]<0||v[i]==8||mp.end()==it||it->second==0){return false;}}return true;}int minMutation(string startGene, string endGene, vector<string>& bank) {map<char,int> mapOfCToI;mapOfCToI['A']=0;mapOfCToI['C']=1;mapOfCToI['G']=2;mapOfCToI['T']=3;map<vector<int>,int> mp;for(auto& e:bank){vector<int> res;SToI(mapOfCToI,e,res);mp[res]=1;}vector<int> start;vector<int> end;queue<vector<int>> q;int count=1;int d=1;SToI(mapOfCToI,startGene,start);SToI(mapOfCToI,endGene,end);q.push(start);mp[start]=0;if(mp.end()==mp.find(end)){return -1;}while(!q.empty()){int cur=0;while(count--){vector<int> tmp=q.front();q.pop();int i=0;for(;i<8;++i){int j=0;int k=tmp[i];for(;j<4;++j){tmp[i]=j;if(IsLegal(mp,tmp)){q.push(tmp);mp[tmp]=0;++cur;if(0==mp[end]){return d;}}}tmp[i]=k;}}++d;count=cur;}return -1;}
};
127. 單詞接龍
字典 wordList 中從單詞 beginWord 到 endWord 的 轉換序列 是一個按下述規格形成的序列 beginWord -> s1 -> s2 -> … -> sk:
每一對相鄰的單詞只差一個字母。
對于 1 <= i <= k 時,每個 si 都在 wordList 中。注意, beginWord 不需要在 wordList 中。
sk == endWord
給你兩個單詞 beginWord 和 endWord 和一個字典 wordList ,返回 從 beginWord 到 endWord 的 最短轉換序列 中的 單詞數目 。如果不存在這樣的轉換序列,返回 0 。
class Solution {
public:int ladderLength(string beginWord, string endWord, vector<string>& wordList) {if(beginWord.size()!=endWord.size()){return 0;}wordList.push_back(beginWord);map<string, int> mp;for (auto& e : wordList) {if(e.size()==beginWord.size()){mp[e]=1;}}if(mp.end()==mp.find(endWord)){return 0;}queue<string> q;q.push(beginWord);mp[beginWord]=0;int count = 1;int d = 2;while (!q.empty()) {int cur = 0;while (count--) {string tmp = q.front();q.pop();int i = 0;for (; i < beginWord.size(); ++i) {int j = 0;char c = tmp[i];for (; j < 26; ++j) {tmp[i] = 'a'+j;auto it=mp.find(tmp);if (mp.end()!=it&&it->second) {q.push(tmp);it->second = 0;++cur;if (0 == mp[endWord]) {return d;}}}tmp[i] = c;}}++d;count = cur;}return 0;}
};
675. 為高爾夫比賽砍樹
你被請來給一個要舉辦高爾夫比賽的樹林砍樹。樹林由一個 m x n 的矩陣表示, 在這個矩陣中:
0 表示障礙,無法觸碰
1 表示地面,可以行走
比 1 大的數 表示有樹的單元格,可以行走,數值表示樹的高度
每一步,你都可以向上、下、左、右四個方向之一移動一個單位,如果你站的地方有一棵樹,那么你可以決定是否要砍倒它。
你需要按照樹的高度從低向高砍掉所有的樹,每砍過一顆樹,該單元格的值變為 1(即變為地面)。
你將從 (0, 0) 點開始工作,返回你砍完所有樹需要走的最小步數。 如果你無法砍完所有的樹,返回 -1 。
可以保證的是,沒有兩棵樹的高度是相同的,并且你至少需要砍倒一棵樹。
class Solution {
public:bool record[51][51];int dx[4] = { 0, 0, 1, -1 };int dy[4] = { 1, -1, 0, 0 };int GetDist(vector<vector<int>>& forest,vector<int>& src,vector<int>& dest){if(src[0]==dest[0]&&src[1]==dest[1]){return 0;}memset(record,1,sizeof(record));int dist=1;queue<pair<int, int>> cordiates;cordiates.push({src[0],src[1]});record[src[0]][src[1]]=0;while(!cordiates.empty()){int count=cordiates.size();while(count--){auto tmp=cordiates.front();cordiates.pop();int k=4;while(k--){int i=tmp.first+dx[k];int j=tmp.second+dy[k];if(i>=0&&i<forest.size()&&j>=0&&j<forest[0].size()&&forest[i][j]&&record[i][j]){if(i==dest[0]&&j==dest[1]){return dist;}cordiates.push({i,j});record[i][j]=0;}}}++dist;}return -1;}int cutOffTree(vector<vector<int>>& forest) {if(0==forest[0][0]){return -1;}vector<vector<int>> cordiates;int i=0;int j=0;for(i=0;i<forest.size();++i){for(j=0;j<forest[0].size();++j){if(forest[i][j]>1){cordiates.push_back({i,j});}}}sort(cordiates.begin(),cordiates.end(),[&](vector<int>& v1,vector<int>& v2)->bool{return forest[v1[0]][v1[1]]<forest[v2[0]][v2[1]];});int dist=0;vector<int> src={0,0};vector<int>& dest=cordiates[0];for(i=0;i<cordiates.size();++i){dest=cordiates[i];int t=GetDist(forest,src,dest);//int t=bfs(forest,src[0],src[1],dest[0],dest[1]);if(t<0){return -1;}src=dest;dist+=t;}return dist;}
};
解決多源最短路徑問題
解決多個起點到到某個終點的最短路徑問題。
解決辦法一:遍歷所有點作為起點,進行多次單源最短路徑問題算法
解決辦法二:以所有可能的起點作為源點,同時執行BFS算法
542. 01 矩陣
給定一個由 0 和 1 組成的矩陣 mat ,請輸出一個大小相同的矩陣,其中每一個格子是 mat 中對應位置元素到最近的 0 的距離。
兩個相鄰元素間的距離為 1 。
以所有值為0的點作為起點,值為1的點作為終點執行BFS算法即可
class Solution {
public:bool IsLegal(vector<vector<int>>& ans,vector<int>& cordiate){if(cordiate[0]<0||cordiate[1]<0||cordiate[0]>=ans.size()||cordiate[1]>=ans[0].size()||ans[cordiate[0]][cordiate[1]]>=0){return false;}return true;}vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {vector<vector<int>> ans(mat.size(),vector<int>(mat[0].size(),-1));int dist=1;queue<vector<int>> q;int i=0;for(;i<mat.size();++i){int j=0;for(;j<mat[0].size();++j){if(0==mat[i][j]){q.push({i,j});ans[i][j]=0;}}}int count=q.size();while(!q.empty()){int cur=0;while(count--){auto tmp=q.front();q.pop();vector<vector<int>> cordiates;cordiates.push_back({tmp[0]+1,tmp[1]});cordiates.push_back({tmp[0]-1,tmp[1]});cordiates.push_back({tmp[0],tmp[1]+1});cordiates.push_back({tmp[0],tmp[1]-1});int k=0;for(;k<4;++k){if(IsLegal(ans,cordiates[k])){ans[cordiates[k][0]][cordiates[k][1]]=dist;q.push(cordiates[k]);++cur;}}}count=cur;++dist;}return ans;}
};
1020. 飛地的數量
給你一個大小為 m x n 的二進制矩陣 grid ,其中 0 表示一個海洋單元格、1 表示一個陸地單元格。
一次 移動 是指從一個陸地單元格走到另一個相鄰(上、下、左、右)的陸地單元格或跨過 grid 的邊界。
返回網格中 無法 在任意次數的移動中離開網格邊界的陸地單元格的數量。
以所有值為1的邊界點作為起點執行BFS,將離開網格邊界的陸地單元格置為0,最后值仍為1的點就是網格中 無法 在任意次數的移動中離開網格邊界的陸地單元格。
class Solution {
public:int Renew(vector<vector<int>>& grid,int i,int j){if(i<0||j<0||i>=grid.size()||j>=grid[0].size()||0==grid[i][j]){return 0;}grid[i][j]=0;int left=Renew(grid,i,j-1);int right=Renew(grid,i,j+1);int up=Renew(grid,i-1,j);int down=Renew(grid,i+1,j);return left+right+up+down+1;}int numEnclaves(vector<vector<int>>& grid) {int ans=0;int i=0;int j=0;vector<vector<int>> cordiates;for(i=0;i<grid.size();++i){for(j=0;j<grid[0].size();++j){if(1==grid[i][j]){if(i==0||j==0||i+1==grid.size()||j+1==grid[0].size()){cordiates.push_back({i,j});}++ans;}}}for(auto & e:cordiates){ans-=Renew(grid,e[0],e[1]);}return ans;}
};
1765. 地圖中的最高點
給你一個大小為 m x n 的整數矩陣 isWater ,它代表了一個由 陸地 和 水域 單元格組成的地圖。
如果 isWater[i][j] == 0 ,格子 (i, j) 是一個 陸地 格子。
如果 isWater[i][j] == 1 ,格子 (i, j) 是一個 水域 格子。
你需要按照如下規則給每個單元格安排高度:
每個格子的高度都必須是非負的。
如果一個格子是 水域 ,那么它的高度必須為 0 。
任意相鄰的格子高度差 至多 為 1 。當兩個格子在正東、南、西、北方向上相互緊挨著,就稱它們為相鄰的格子。(也就是說它們有一條公共邊)
找到一種安排高度的方案,使得矩陣中的最高高度值 最大 。
請你返回一個大小為 m x n 的整數矩陣 height ,其中 height[i][j] 是格子 (i, j) 的高度。如果有多種解法,請返回 任意一個 。
class Solution {
public:void Renew(vector<vector<int>>& isWater,vector<vector<int>>& ans,queue<vector<int>>& q,int & cur,int dist,int i, int j) {if (i < 0 || j < 0 || i >= isWater.size() || j >= isWater[0].size() || 1 == isWater[i][j]) {return;}isWater[i][j] = 1;ans[i][j]=dist;q.push({i,j});++cur;}vector<vector<int>> highestPeak(vector<vector<int>>& isWater) {int i=0;int j=0;int dist=1;vector<vector<int>> ans(isWater.size(),vector<int>(isWater[0].size(),0));queue<vector<int>> q;for(i=0;i<isWater.size();++i){for(j=0;j<isWater[0].size();++j){if(1==isWater[i][j]){q.push({i,j});}}}int count=q.size();while(!q.empty()){int cur=0;while(count--){auto e=q.front();q.pop();Renew(isWater,ans,q,cur,dist,e[0]+1,e[1]);Renew(isWater,ans,q,cur,dist,e[0]-1,e[1]);Renew(isWater,ans,q,cur,dist,e[0],e[1]+1);Renew(isWater,ans,q,cur,dist,e[0],e[1]-1);}++dist;count=cur;}return ans;}
};
1162. 地圖分析
你現在手里有一份大小為 n x n 的 網格 grid,上面的每個 單元格 都用 0 和 1 標記好了。其中 0 代表海洋,1 代表陸地。
請你找出一個海洋單元格,這個海洋單元格到離它最近的陸地單元格的距離是最大的,并返回該距離。如果網格上只有陸地或者海洋,請返回 -1。
、我們這里說的距離是「曼哈頓距離」( Manhattan Distance):(x0, y0) 和 (x1, y1) 這兩個單元格之間的距離是 |x0 - x1| + |y0 - y1| 。
class Solution {
public:void Renew(vector<vector<int>>& grid,queue<vector<int>> &q,int& cur,int i,int j){if(i<0||j<0||i==grid.size()||j==grid[0].size()||1==grid[i][j]){return ;}q.push({i,j});grid[i][j]=1;++cur;}int maxDistance(vector<vector<int>>& grid) {queue<vector<int>> q;int i=0;int j=0;for(i=0;i<grid.size();++i){for(j=0;j<grid[0].size();++j){if(1==grid[i][j]){q.push({i,j});}}}if(q.empty()||grid.size()*grid[0].size()==q.size()){return -1;}int count=q.size();int dist=-1;while(!q.empty()){int cur=0;while(count--){auto e=q.front();q.pop();Renew(grid,q,cur,e[0]+1,e[1]);Renew(grid,q,cur,e[0]-1,e[1]);Renew(grid,q,cur,e[0],e[1]+1);Renew(grid,q,cur,e[0],e[1]-1);}count=cur;++dist;}return dist;}
};
解決拓撲排序問題
解決拓撲排序問題的思路為選擇入度為0的頂點將該頂點加入到結果中,同時刪除與該頂點相關聯的邊,重復上面步驟直到沒有入度為0的頂點為止(如果此時還有頂點沒有選入結果,說明該圖不是有向無環圖)。圖的表示形式有鄰接矩陣和鄰接表,其中鄰接表的建圖方式有:
①采用鏈表:vector<list<T>>
②采用數組:vector<vector<T>>
③采用哈希:map<T,vector<T>>
實現步驟為以所有入度為0的頂點作為起點,執行BFS算法即可。
207. 課程表
你這個學期必須選修 numCourses 門課程,記為 0 到 numCourses - 1 。
在選修某些課程之前需要一些先修課程。 先修課程按數組 prerequisites 給出,其中 prerequisites[i] = [ai, bi] ,表示如果要學習課程 ai 則 必須 先學習課程 bi 。
例如,先修課程對 [0, 1] 表示:想要學習課程 0 ,你需要先完成課程 1 。
請你判斷是否可能完成所有課程的學習?如果可以,返回 true ;否則,返回 false 。
class Solution {
public:bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {vector<int> count(numCourses,0);//采用鄰接表vector<vector<T>>建圖vector<vector<int>> edges(numCourses,vector<int>());for(auto& e:prerequisites){edges[e[1]].push_back(e[0]);count[e[0]]++;}//BFSint m=0;queue<int> q;int i=0;for(i=0;i<count.size();++i){if(0==count[i]){q.push(i);++m;}}while(!q.empty()){int s=q.size();while(s--){int course=q.front();q.pop();for(auto e:edges[course]){count[e]--;if(0==count[e]){q.push(e);++m;}}}}if(m<numCourses){return false;}return true;}
};
210. 課程表 II
現在你總共有 numCourses 門課需要選,記為 0 到 numCourses - 1。給你一個數組 prerequisites ,其中 prerequisites[i] = [ai, bi] ,表示在選修課程 ai 前 必須 先選修 bi 。
例如,想要學習課程 0 ,你需要先完成課程 1 ,我們用一個匹配來表示:[0,1] 。
返回你為了學完所有課程所安排的學習順序。可能會有多個正確的順序,你只要返回 任意一種 就可以了。如果不可能完成所有課程,返回 一個空數組 。
class Solution {
public:vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {vector<int> count(numCourses, 0);vector<int> ans;//采用鄰接表vector<vector<T>>建圖vector<vector<int>> edges(numCourses, vector<int>());for (auto& e : prerequisites) {edges[e[1]].push_back(e[0]);count[e[0]]++;}//BFSqueue<int> q;int i = 0;for (i = 0; i < count.size(); ++i) {if (0 == count[i]) {q.push(i);ans.push_back(i);}}while (!q.empty()) {int s = q.size();while (s--) {int course = q.front();q.pop();for (auto e : edges[course]) {count[e]--;if (0 == count[e]) {q.push(e);ans.push_back(e);}}}}if (ans.size() < numCourses) {return {};}return ans;}
};
LCR 114. 火星詞典
現有一種使用英語字母的外星文語言,這門語言的字母順序與英語順序不同。
給定一個字符串列表 words ,作為這門語言的詞典,words 中的字符串已經 按這門新語言的字母順序進行了排序 。
請你根據該詞典還原出此語言中已知的字母順序,并 按字母遞增順序 排列。若不存在合法字母順序,返回 “” 。若存在多種可能的合法字母順序,返回其中 任意一種 順序即可。
字符串 s 字典順序小于 字符串 t 有兩種情況:
在第一個不同字母處,如果 s 中的字母在這門外星語言的字母順序中位于 t 中字母之前,那么 s 的字典順序小于 t 。
如果前面 min(s.length, t.length) 字母都相同,那么 s.length < t.length 時,s 的字典順序也小于 t 。
class Solution {
public:string alienOrder(vector<string>& words) {string ans;map<char,int> count;int i=0;int j=0;for(i=0;i<words.size();++i){for(j=0;j<words[i].size();++j){count[words[i][j]]=0;}}//采用哈希:map<T,vector<T>>建圖map<char,set<char>> edges;for(i=1;i<words.size();++i){for(j=0;j<words[i].size()&&j<words[i-1].size();++j){if(words[i-1][j]!=words[i][j]){if(edges[words[i-1][j]].end()==edges[words[i-1][j]].find(words[i][j])){edges[words[i-1][j]].insert(words[i][j]);count[words[i][j]]++;}break;}}if(j>=words[i].size()&&words[i-1].size()>words[i].size()){return "";}}//BFSqueue<char> q;for(auto& e:count){if(0==e.second){q.push(e.first);ans.push_back(e.first);}}while(!q.empty()){int s=q.size();while(s--){char c=q.front();q.pop();for(auto e:edges[c]){count[e]--;if(0==count[e]){q.push(e);ans.push_back(e);}}}}//判斷是否有環for(auto& e:count){if(e.second){return "";}}return ans;}
};