算法15--BFS

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;}
};

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:
http://www.pswp.cn/web/70573.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/70573.shtml
英文地址,請注明出處:http://en.pswp.cn/web/70573.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

網絡空間安全(2)應用程序安全

前言 應用程序安全&#xff08;Application Security&#xff0c;簡稱AppSec&#xff09;是一個綜合性的概念&#xff0c;它涵蓋了應用程序從開發到部署&#xff0c;再到后續維護的整個過程中的安全措施。 一、定義與重要性 定義&#xff1a;應用程序安全是指識別和修復應用程序…

Plantsimulation中機器人怎么通過阻塞角度設置旋轉135°

創建一個這樣的簡單模型。 檢查PickAndPlace的角度表。源位于180的角位置&#xff0c;而物料終結位于90的角位置。“返回默認位置”選項未被勾選。源每分鐘生成一個零件。啟動模擬時&#xff0c;Plant Simulation會選擇兩個位置之間的最短路徑。示例中的機器人無法繞135的角位…

Fisher信息矩陣(Fisher Information Matrix, FIM)與自然梯度下降:機器學習中的優化利器

Fisher信息矩陣與自然梯度下降&#xff1a;機器學習中的優化利器 在機器學習尤其是深度學習中&#xff0c;優化模型參數是一個核心任務。我們通常依賴梯度下降&#xff08;Gradient Descent&#xff09;來調整參數&#xff0c;但普通的梯度下降有時會顯得“笨拙”&#xff0c;…

Spring Boot集成Swagger API文檔:傻瓜式零基礎教程

Springfox Swagger 是一個用于構建基于 Spring Boot 的 RESTful API 文檔的開源工具。它通過使用注解來描述 API 端點&#xff0c;自動生成易于閱讀和理解的 API 文檔。Springfox 通過在運行時檢查應用程序&#xff0c;基于 Spring 配置、類結構和各種編譯時 Java 注釋來推斷 A…

接口測試基礎 --- 什么是接口測試及其測試流程?

接口測試是軟件測試中的一個重要部分&#xff0c;它主要用于驗證和評估不同軟件組件之間的通信和交互。接口測試的目標是確保不同的系統、模塊或組件能夠相互連接并正常工作。 接口測試流程可以分為以下幾個步驟&#xff1a; 1.需求分析&#xff1a;首先&#xff0c;需要仔細…

kafka-集群縮容

一. 簡述&#xff1a; 當業務增加時&#xff0c;服務瓶頸&#xff0c;我們需要進行擴容。當業務量下降時&#xff0c;為成本考慮。自然也會涉及到縮容。假設集群有 15 臺機器&#xff0c;預計縮到 10 臺機器&#xff0c;那么需要做 5 次縮容操作&#xff0c;每次將一個節點下線…

Spring Boot 概要(官網文檔解讀)

Spring Boot 概述 Spring Boot 是一個高效構建 Spring 生產級應用的腳手架工具&#xff0c;它簡化了基于 Spring 框架的開發過程。 Spring Boot 也是一個“構件組裝門戶”&#xff0c;何為構件組裝門戶呢&#xff1f;所謂的“構件組裝門戶”指的是一個對外提供的Web平臺&#x…

Linux 命令大全完整版(12)

Linux 命令大全 5. 文件管理命令 ln(link) 功能說明&#xff1a;連接文件或目錄。語  法&#xff1a;ln [-bdfinsv][-S <字尾備份字符串>][-V <備份方式>][--help][--version][源文件或目錄][目標文件或目錄] 或 ln [-bdfinsv][-S <字尾備份字符串>][-V…

遺傳算法初探

組成要素 編碼 分為二進制編碼、實數編碼和順序編碼 初始種群的產生 分為隨機方法、基于反向學習優化的種群產生。 基于反向學習優化的種群其思想是先隨機生成一個種群P(N)&#xff0c;然后按照反向學習方法生成新的種群OP(N),合并兩個種群&#xff0c;得到一個新的種群S(N…

【算法】堆

堆 heap&#xff0c;一棵完全二叉樹&#xff0c;使用數組實現的&#xff0c;但具備完全二叉樹的一些性質。一般總是滿足以下性質&#xff1a; 堆中某個節點的值總是不大于或不小于其父節點的值&#xff1b;堆總是一棵完全二叉樹。&#xff08;即除了最底層&#xff0c;其他層…

C/C++高性能Web開發框架全解析:2025技術選型指南

一、工業級框架深度解析&#xff08;附性能實測&#xff09; 1. Drogon v2.1&#xff1a;異步框架性能王者 核心架構&#xff1a; Reactor 非阻塞I/O線程池&#xff08;參考Nginx模型&#xff09; 協程實現&#xff1a;基于Boost.Coroutine2&#xff08;兼容C11&#xff09;…

使用PHP接入純真IP庫:實現IP地址地理位置查詢

引言 在日常開發中,我們經常需要根據用戶的IP地址獲取其地理位置信息,例如國家、省份、城市等。純真IP庫(QQWry)是一個常用的IP地址數據庫,提供了豐富的IP地址與地理位置的映射關系。本文將介紹如何使用PHP接入純真IP庫,并通過一個完整的案例演示如何實現IP地址的地理位…

Django ORM 的常用字段類型、外鍵關聯的跨表引用技巧,以及 `_` 和 `__` 的使用場景

一、Django ORM 常用字段類型 1. 基礎字段類型 字段類型說明示例CharField字符串字段&#xff0c;必須指定 max_lengthname models.CharField(max_length50)IntegerField整數字段age models.IntegerField()BooleanField布爾值字段is_active models.BooleanField()DateFiel…

java遞歸求自然數列的前n項和

概述 實現 /*** 數列 1 2 3 ... n ...* 遞歸求數列的前n項和* param n* return*/private static long calSum(long n){if (n1) return 1;else {return ncalSum(n-1); // 前n項的和 即第n項的值前n-1項的和}}測試用例 public static void main(String[] args) {long res1 cal…

【Golang 面試題】每日 3 題(六十五)

?個人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;專欄地址&#xff1a;http://t.csdnimg.cn/UWz06 &#x1f4da;專欄簡介&#xff1a;在這個專欄中&#xff0c;我將會分享 Golang 面試中常見的面試題給大家~ ??如果有收獲的話&#xff0c;歡迎點贊&#x1f44d;收藏…

16、Python面試題解析:python中的淺拷貝和深拷貝

在 Python 中&#xff0c;淺拷貝&#xff08;Shallow Copy&#xff09; 和 深拷貝&#xff08;Deep Copy&#xff09; 是處理對象復制的兩種重要機制&#xff0c;它們的區別主要體現在對嵌套對象的處理方式上。以下是詳細解析&#xff1a; 1. 淺拷貝&#xff08;Shallow Copy&a…

【Godot4.3】題目與答案解析合并器

免責申明 本文和工具截圖中涉及題庫和題目&#xff0c;均為本人自學使用&#xff0c;并未有商業和傳播企圖。如有侵害&#xff0c;聯系刪改。 概述 筆者本人醫學專業從業人員&#xff0c;編程只是業余愛好。在自己的專業應考學習過程當中&#xff1a; 有時候不太喜歡紙質題庫…

Lm studio本地部署DeepSeek

為什么用Lm studio Ollama官網下載過慢或失敗&#xff08;Lm默認下載源無法下載&#xff0c;但可以更換下載源&#xff09;Ollama默認安裝至C盤一部分Nivida顯卡無法吃滿顯存資源一部分AMD顯卡替換rocm文件后無法啟動 Lm studio安裝 官網下載&#xff1a;LM Studio - Discov…

基于Qlearning強化學習的2DoF機械臂運動控制系統matlab仿真

目錄 1.算法仿真效果 2.算法涉及理論知識概要 2.1 2DoF機械臂運動學模型 2.2 Q-learning強化學習算法原理 3.MATLAB核心程序 4.完整算法代碼文件獲得 1.算法仿真效果 matlab2022a仿真結果如下&#xff08;完整代碼運行后無水印&#xff09;&#xff1a; 仿真操作步驟可參…

Unity貼圖與模型相關知識

一、貼圖 1.貼圖的類型與形狀 貼圖類型 貼圖形狀 2.在Unity中可使用一張普通貼圖來生成對應的法線貼圖&#xff08;但并不規范&#xff09; 復制一張該貼圖將復制后的貼圖類型改為Normal Map 3.貼圖的sRGB與Alpha sRGB&#xff1a;勾選此選項代表此貼圖存儲于Gamma空間中…