6.1 广度优先搜索(BFS)
-
二进制矩阵中的最短路径: https://leetcode-cn.com/problems/shortest-path-in-binary-matrix/
// 求最短路径通常使用广度优先搜索,可以用队列实现。 // 从下标 [0,0] 开始遍历,每次寻找该点的八个方向是否可走,若可走就入队,继续执行该操作,最后走到 [n-1,n-1] 时, // 此时执行最外层循环的次数便是最短路径长度。(类似二叉树的层序遍历) class Solution { public: int shortestPathBinaryMatrix(vector<vector<int>>& grid) { if(grid[0][0]==1)return -1; int n=grid.size(),ans=1; const int dire[8][2]={{1,0},{-1,0},{0,1},{0,-1},{1,1},{1,-1},{-1,-1},{-1,1}}; queue<pair<int,int> > q; q.emplace(0,0); //从0,0开始 grid[0][0]=1; //标记为1代表走过 while(!q.empty()){ //bfs int m=q.size(); while(m--){ auto [x,y]=q.front(); q.pop(); if(x==n-1&&y==n-1)return ans; for(int i=0;i<8;i++){ //遍历八个方向的 int nx=x+dire[i][0]; int ny=y+dire[i][1]; if(nx<0||ny<0||nx>=n||ny>=n)continue; //判断是否越界 if(grid[nx][ny]==0){ //判断是否能走 q.emplace(nx,ny); grid[nx][ny]=1; //标记 } } } ans++; //记录循环次数 } return -1; } };
-
单词接龙: https://leetcode-cn.com/problems/word-ladder/
class Solution { public: unordered_map<string, int> wordId; vector<vector<int>> edge; int nodeNum = 0; void addWord(string& word) { if (!wordId.count(word)) { wordId[word] = nodeNum++; edge.emplace_back(); } } void addEdge(string& word) { addWord(word); int id1 = wordId[word]; for (char& it : word) { char tmp = it; it = '*'; addWord(word); int id2 = wordId[word]; edge[id1].push_back(id2); edge[id2].push_back(id1); it = tmp; } } int ladderLength(string beginWord, string endWord, vector<string>& wordList) { for (string& word : wordList) { addEdge(word); } addEdge(beginWord); if (!wordId.count(endWord)) { return 0; } vector<int> dis(nodeNum, INT_MAX); int beginId = wordId[beginWord], endId = wordId[endWord]; dis[beginId] = 0; queue<int> que; que.push(beginId); while (!que.empty()) { int x = que.front(); que.pop(); if (x == endId) { return dis[endId] / 2 + 1; } for (int& it : edge[x]) { if (dis[it] == INT_MAX) { dis[it] = dis[x] + 1; que.push(it); } } } return 0; } };
6.2 深度优先搜索(DFS)
-
岛屿的最大面积: https://leetcode-cn.com/problems/max-area-of-island/
class Solution { int dfs(vector<vector<int>>& grid, int cur_i, int cur_j) { if (cur_i < 0 || cur_j < 0 || cur_i == grid.size() || cur_j == grid[0].size() || grid[cur_i] [cur_j] != 1) { return 0; } grid[cur_i][cur_j] = 0; int di[4] = {0, 0, 1, -1}; int dj[4] = {1, -1, 0, 0}; int ans = 1; for (int index = 0; index != 4; ++index) { int next_i = cur_i + di[index], next_j = cur_j + dj[index]; ans += dfs(grid, next_i, next_j); } return ans; } public: int maxAreaOfIsland(vector<vector<int>>& grid) { int ans = 0; for (int i = 0; i != grid.size(); ++i) { for (int j = 0; j != grid[0].size(); ++j) { ans = max(ans, dfs(grid, i, j)); } } return ans; } };
-
岛屿数量: https://leetcode-cn.com/problems/number-of-islands/
class Solution { private: void dfs(vector<vector<char>>& grid, int r, int c) { int nr = grid.size(); int nc = grid[0].size(); grid[r][c] = '0'; if (r - 1 >= 0 && grid[r-1][c] == '1') dfs(grid, r - 1, c); if (r + 1 < nr && grid[r+1][c] == '1') dfs(grid, r + 1, c); if (c - 1 >= 0 && grid[r][c-1] == '1') dfs(grid, r, c - 1); if (c + 1 < nc && grid[r][c+1] == '1') dfs(grid, r, c + 1); } public: int numIslands(vector<vector<char>>& grid) { int nr = grid.size(); if (!nr) return 0; int nc = grid[0].size(); int num_islands = 0; for (int r = 0; r < nr; ++r) { for (int c = 0; c < nc; ++c) { if (grid[r][c] == '1') { ++num_islands; dfs(grid, r, c); } } } return num_islands; } };
-
省份数量: https://leetcode-cn.com/problems/number-of-provinces/
class Solution { public: void dfs(vector<vector<int>>& isConnected, vector<int>& visited, int provinces, int i) { for (int j = 0; j < provinces; j++) { if (isConnected[i][j] == 1 && !visited[j]) { visited[j] = 1; dfs(isConnected, visited, provinces, j); } } } int findCircleNum(vector<vector<int>>& isConnected) { int provinces = isConnected.size(); vector<int> visited(provinces); int circles = 0; for (int i = 0; i < provinces; i++) { if (!visited[i]) { dfs(isConnected, visited, provinces, i); circles++; } } return circles; } };
6.3 回溯(Backtracking)
学习: https://zhuanlan.zhihu.com/p/54275352
一种通过探索所有可能的候选解来找出所有的解的算法。如果候选解被确认不是一个解(或者至少不是最后一个解),回溯算法会通过在上一步进行一些变化抛弃该解,即回溯并且再次尝试。
-
全排列: https://leetcode-cn.com/problems/permutations/
class Solution { public: void backtrack(vector<vector<int>>& res, vector<int>& output, int first, int len){ // 所有数都填完了 if (first == len) { res.emplace_back(output); return; } for (int i = first; i < len; ++i) { // 动态维护数组 swap(output[i], output[first]); // 继续递归填下一个数 backtrack(res, output, first + 1, len); // 撤销操作 swap(output[i], output[first]); } } vector<vector<int>> permute(vector<int>& nums) { vector<vector<int> > res; backtrack(res, nums, 0, (int)nums.size()); return res; } };
-
N 皇后: https://leetcode-cn.com/problems/n-queens/
class Solution { public: vector<vector<string>> solveNQueens(int n) { auto solutions = vector<vector<string>>(); auto queens = vector<int>(n, -1); auto columns = unordered_set<int>(); auto diagonals1 = unordered_set<int>(); auto diagonals2 = unordered_set<int>(); backtrack(solutions, queens, n, 0, columns, diagonals1, diagonals2); return solutions; } void backtrack(vector<vector<string>> &solutions, vector<int> &queens, int n, int row, unordered_set<int> &columns, unordered_set<int> &diagonals1, unordered_set<int> &diagonals2) { if (row == n) { vector<string> board = generateBoard(queens, n); solutions.push_back(board); } else { for (int i = 0; i < n; i++) { if (columns.find(i) != columns.end()) { continue; } int diagonal1 = row - i; if (diagonals1.find(diagonal1) != diagonals1.end()) { continue; } int diagonal2 = row + i; if (diagonals2.find(diagonal2) != diagonals2.end()) { continue; } queens[row] = i; columns.insert(i); diagonals1.insert(diagonal1); diagonals2.insert(diagonal2); backtrack(solutions, queens, n, row + 1, columns, diagonals1, diagonals2); queens[row] = -1; columns.erase(i); diagonals1.erase(diagonal1); diagonals2.erase(diagonal2); } } } vector<string> generateBoard(vector<int> &queens, int n) { auto board = vector<string>(); for (int i = 0; i < n; i++) { string row = string(n, '.'); row[queens[i]] = 'Q'; board.push_back(row); } return board; } };